从服务器请求数据的最佳方式

pit*_*zzo 1 post multithreading android server

我需要从我的服务器获取一些数据才能使我的应用程序正常工作。为了做到这一点,我将使用 POST。据我所知,我必须在不能作为主线程的线程中请求该数据。我发现将我正在接收的数据放在 UI 线程中定义的变量中有点困难。所以,我的问题是,哪种方法最好?例如,在我的主要活动中,使用在 AsyncTask 中调用的 setter 来设置定义的变量的值是否正确?或者这个选项可能更好?

Thread nt = new Thread(){
        @Override
    public void run(){

            try{

               //get data with POST and then something like main.setValue(data);
            }catch(Exception e){

                e.printStackTrace();
            }
        }

    };
    nt.start();
Run Code Online (Sandbox Code Playgroud)

我已经读到我可能会使用接口来存档它,但这是一个我还不太了解的概念。我想直接使用返回数据的方法,但据我所知,这是不可能的。你的时间!

编辑:根据 NoChinDeluxe 答案的新代码:

public class LoginHandler {

public static class Login extends AsyncTask<String, String, Integer> {


    LoginCallback listener;

    @Override
    protected Integer doInBackground(String... params) {


        URL url;

        postDataParams.put("name", params[0]);
        HashMap<String, String> postDataParams = new HashMap<String, String>();
        postDataParams.put("password", params[1]);

        try {

            url = new URL("http://mashiron.xyz/_03z/gmpia/proc.php");

            HttpURLConnection conn = (HttpURLConnection) url.openConnection();
            conn.setReadTimeout(15000);
            conn.setConnectTimeout(15000);
            conn.setRequestMethod("POST");
            conn.setDoInput(true);
            conn.setDoOutput(true);


            OutputStream os = conn.getOutputStream();
            BufferedWriter writer = new BufferedWriter(
                    new OutputStreamWriter(os, "UTF-8"));

            writer.write(HttpHandler.getPostDataString(postDataParams));
            writer.flush();
            writer.close();
            os.close();
            System.out.println("Respuesta: "+conn.getResponseCode());
            return conn.getResponseCode();

        } catch (Exception e) {
            e.printStackTrace();

            return 404;
        }
    }

    protected void onPostExecute(int result){
        System.out.println("Respuesta 2: "+result);

        listener.onResultReceived(result);
    }

}



public interface LoginCallback {

    void onResultReceived(int result);
}
Run Code Online (Sandbox Code Playgroud)

}

编辑:为 NoChinDeluxe 添加了例外:

03-24 17:38:09.072 13312-13312/com.pitazzo.geomoments E/AndroidRuntime:致命异常:主进程:com.pitazzo.geomoments,PID:13312 java.lang.NullPointerException:尝试调用接口方法.pitazzo.geomoments.Handlers.LoginHandler$LoginCallback.onResultReceived(int)' 在 com.pitazzo.geomoments.Handlers.LoginHandler$Login.onPostExecute(LoginHandler.java:65) 的空对象引用上,在 com.pitazzo.geomoments.Handlers .LoginHandler$Login.onPostExecute(LoginHandler.java:17) 在 android.os.AsyncTask.finish(AsyncTask.java:636) 在 android.os.AsyncTask.access$500(AsyncTask.java:177) 在 android.os.AsyncTask$InternalHandler.handleMessage(AsyncTask.java:653)在 android.os.Handler.dispatchMessage(Handler.java:102) 在 android.os.Looper.loop(Looper.java:135) 在 android.app.ActivityThread.main(ActivityThread.java:5300) 在 java.lang.reflect.Method.invoke(Native Method) 在 java.lang.reflect.Method.invoke(Method.java:372) 在 com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit. java:904) 在 com.android.internal.os.ZygoteInit.main(ZygoteInit.java:699)ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:904) 在 com.android.internal.os.ZygoteInit.main(ZygoteInit.java:699)ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:904) 在 com.android.internal.os.ZygoteInit.main(ZygoteInit.java:699)

编辑:NoChainDeluxe 的更多代码

public class LoginActivity extends AppCompatActivity implements LoginHandler.LoginCallback{

EditText name;
EditText password;
Button login;
int code;


@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.login_activity);

    /*
    if(logueado){

    }


     */


    name = (EditText) findViewById(R.id.loginuser);
    password = (EditText) findViewById(R.id.loginpassword);
    login = (Button) findViewById(R.id.loginlogin);

    login.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {

            String params[] = {name.getText().toString(), password.getText().toString()};
            System.out.println("Params: "+params.toString());

            new LoginHandler.Login().execute(params);
            System.out.println("Respuesta 4: "+code);

            if(code == 200){
                Toast toast1 =
                        Toast.makeText(getApplicationContext(),
                                "Iniciado sesión", Toast.LENGTH_SHORT);

                toast1.show();
            }else{

                Toast toast1 =
                        Toast.makeText(getApplicationContext(),
                                "Nombre de usuario y/o contraseña incorrectos: "+code, Toast.LENGTH_SHORT);

                toast1.show();

            }

        }
    });

}

public void onResultReceived(int resultado) {
    code = resultado;
    System.out.println("Respuesta 3: "+code);

}
Run Code Online (Sandbox Code Playgroud)

}

NoC*_*uxe 5

实现此目的的最佳方法是使用 anHttpURLConnection在 an 内部进行 Web 调用AsyncTask,然后通过回调将结果传递回调用 Activity。以下是一些可帮助您入门的代码:

您应该了解的第一件事是如何正确使用带有AsyncTask. 下面是一个AsyncTask定义回调接口的例子:

import android.os.AsyncTask;

public class TestTask extends AsyncTask<String, Void, String> {

    TestTaskCallback listener;

    public TestTask(TestTaskCallback listener) {
        this.listener = listener;
    }

    protected String doInBackground(String... args) {

        String input = args[0];
        String output = "simulated return value";

        return output;
    }

    protected void onPostExecute(String result) {
        listener.onResultReceived(result);
    }

    public interface TestTaskCallback {
        void onResultReceived(String result);
    }
}
Run Code Online (Sandbox Code Playgroud)

其工作方式是,您定义一个公共接口,然后在您的 Activity 中实现该接口。它充当“侦听器”,等待发送给它的任何数据。我们定义接口TestTaskCallback是因为我们将从我们的数据发送AsyncTask到我们的调用 Activity。

那么在Activity中,我们需要实现这个接口,并在创建任务的时候传入一个对我们实现的引用。这样,当任务触发时,它知道将结果发送到哪里,结果返回到我们的 Activity。示例实现可能如下所示:

public class TestActivity extends AppCompatActivity implements TestTask.TestTaskCallback {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.your_layout);

        new TestTask(this).execute("Some input");

    }

    public void onResultReceived(String result) {
        Log.d("TEST TASK RESULT", result);
    }
}
Run Code Online (Sandbox Code Playgroud)

所以我们的 Activity 实现了我们在我们的 中定义的接口AsyncTask,并注意到我们AsyncTask获取了对这个实现的引用(通过构造函数传入)并在onPostExecute()方法中向它发送数据。这将允许您的结果发送到主 UI 线程,以便您可以适当地更新您的活动。

剩下的唯一事情就是实际拨打网络电话。我建议HttpURLConnection为此使用一个。您可以将此代码放在doInBackground()您的AsyncTask.

我将向您展示我设置的示例 Web 服务调用。这显示了如何进行 Web 服务调用以检索 JSON 响应。它看起来像这样:

//The JSON we will get back as a response from the server
JSONObject jsonResponse = null;

//Http connections and data streams
URL url;
HttpURLConnection httpURLConnection = null;
OutputStreamWriter outputStreamWriter = null;

try {

    //open connection to the server
        url = new URL("your_url_to_web_service");
        httpURLConnection = (HttpURLConnection) url.openConnection();

        //set request properties
        httpURLConnection.setDoOutput(true); //defaults request method to POST
        httpURLConnection.setDoInput(true);  //allow input to this HttpURLConnection
        httpURLConnection.setRequestProperty("Content-Type", "application/json"); //header params
        httpURLConnection.setRequestProperty("Accept", "application/json"); //header params
        httpURLConnection.setFixedLengthStreamingMode(jsonToSend.toString().getBytes().length); //header param "content-length"

        //open output stream and POST our JSON data to server
        outputStreamWriter = new OutputStreamWriter(httpURLConnection.getOutputStream());
        outputStreamWriter.write(jsonToSend.toString());
        outputStreamWriter.flush(); //flush the stream when we're finished writing to make sure all bytes get to their destination

        //prepare input buffer and get the http response from server
        StringBuilder stringBuilder = new StringBuilder();
        int responseCode = httpURLConnection.getResponseCode();

        //Check to make sure we got a valid status response from the server,
        //then get the server JSON response if we did.
        if(responseCode == HttpURLConnection.HTTP_OK) {

            //read in each line of the response to the input buffer
            BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(httpURLConnection.getInputStream(),"utf-8"));
            String line;
            while ((line = bufferedReader.readLine()) != null) {
                stringBuilder.append(line).append("\n");
            }

            bufferedReader.close(); //close out the input stream

            try {
                //Copy the JSON response to a local JSONObject
                jsonResponse = new JSONObject(stringBuilder.toString());
            } catch (JSONException je) {
                je.printStackTrace();
            }
        }

} catch (IOException ioe) {
    ioe.printStackTrace();
} finally {
    if(httpURLConnection != null) {
        httpURLConnection.disconnect(); //close out our http connection
    }

    if(outputStreamWriter != null) {
        try {
            outputStreamWriter.close(); //close our output stream
        } catch (IOException ioe) {
            ioe.printStackTrace();
        }
    }
}

//Return the JSON response from the server.
return jsonResponse;
Run Code Online (Sandbox Code Playgroud)

这几乎就是你想要做的事情所需要知道的全部内容。我意识到这是一次性向您提供的大量信息,但是如果您花时间一点一点地研究它,您会发现这毕竟不是太难,而且实际上是一个非常强大的工具将一直使用编程 Android 应用程序!

希望这可以帮助。有任何不完全理解的部分,请随时提问!