从服务器请求数据的最佳方法 [英] Best way to request data from server

查看:79
本文介绍了从服务器请求数据的最佳方法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I need to fetch some data from my server in order to make my app work. In order to do that, I will be using POST. As far as I know, I have to request that data in a thread which can not be the main thread. I am finding a little bit diffcult to put the data I am reciving in a variable defined in the UI thread. So, my question is, which is the best way to do it? Is it correct to set the value of a variable defined, for example, in my main activity, with a setter called inside an AsyncTask? Or might be better this option?

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();

我已经读到我可以使用Interfaces来对其进行存档,但这是一个我还不太了解的概念.我想直接使用一种返回数据的方法,但据我所知,这是不可能的. 为您节省时间!

I have read that I may use Interfaces in order to archive that, but it is a concept that I do not understand very well yet. I would like to use directly a method which returns the data, but as far as I know, it is not possible. Thabks for your time!

根据NoChinDeluxe答案的新代码:

new code according to NoChinDeluxe answer:

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);
}

}

为NoChinDeluxe添加了例外:

added exception for NoChinDeluxe:

03-24 17:38:09.072 13312-13312/com.pitazzo.geomoments E/Android运行时:致命异常:主要 流程:com.pitazzo.geomoments,PID:13312 java.lang.NullPointerException:尝试在空对象引用上调用接口方法'void com.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(本机方法) 在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)

03-24 17:38:09.072 13312-13312/com.pitazzo.geomoments E/AndroidRuntime: FATAL EXCEPTION: main Process: com.pitazzo.geomoments, PID: 13312 java.lang.NullPointerException: Attempt to invoke interface method 'void com.pitazzo.geomoments.Handlers.LoginHandler$LoginCallback.onResultReceived(int)' on a null object reference at com.pitazzo.geomoments.Handlers.LoginHandler$Login.onPostExecute(LoginHandler.java:65) at com.pitazzo.geomoments.Handlers.LoginHandler$Login.onPostExecute(LoginHandler.java:17) at android.os.AsyncTask.finish(AsyncTask.java:636) at android.os.AsyncTask.access$500(AsyncTask.java:177) at android.os.AsyncTask$InternalHandler.handleMessage(AsyncTask.java:653) at android.os.Handler.dispatchMessage(Handler.java:102) at android.os.Looper.loop(Looper.java:135) at android.app.ActivityThread.main(ActivityThread.java:5300) at java.lang.reflect.Method.invoke(Native Method) at java.lang.reflect.Method.invoke(Method.java:372) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:904) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:699)

NoChainDeluxe的更多代码

more code for 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);

}

}

推荐答案

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

The best way to achieve this is to use an HttpURLConnection to make your web calls inside an AsyncTask and then pass the result back to your calling Activity through a callback. Here's some code to help you get started:

您应该了解的第一件事是如何正确地将AsyncTask与回调一起使用.这是定义回调接口的示例AsyncTask:

The first thing you should understand is how to properly use a callback with an AsyncTask. Here is an example AsyncTask that defines a callback interface:

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);
    }
}

此方法的工作方式是,定义一个公共接口,然后在活动"中实现该接口.它充当侦听器",正在等待通过它发送的任何数据.我们定义接口TestTaskCallback是因为我们要将数据从AsyncTask发送到调用方Activity.

The way this works is, you define a public interface that you then implement in your Activity. This acts as a "listener" that is waiting for any data that is sent through to it. We define the interface TestTaskCallback because we are going to be sending our data from our AsyncTask to our calling Activity.

然后在Activity中,我们需要实现此接口,并在创建任务时将对我们实现的引用传递给任务.这样,当任务触发时,它知道将结果发送到哪里,该结果又返回到我们的Activity中.一个示例实现可能如下所示:

Then in the Activity, we need to implement this interface, and pass in a reference to our implementation to the task when we create it. That way, when the task fires, it knows where to send the result, which is back to our Activity. An example implementation might look like this:

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);
    }
}

因此,我们的Activity实现了在AsyncTask内部定义的接口,并注意我们的AsyncTask引用了该实现的引用(通过构造函数传递),并通过onPostExecute()方法将数据发送给该实现.这将允许您将结果发送到主UI线程,以便您可以适当地更新Activity.

So our Activity implements the interface that we defined inside our AsyncTask, and notice that our AsyncTask takes the reference to this implementation (passed in through the constructor) and sends data to it in the onPostExecute() method. This will allow your result to be sent to the main UI thread so that you can update your Activity appropriately.

剩下的唯一一件事就是实际进行网络通话.我建议为此使用HttpURLConnection.您可以将此代码放入AsyncTaskdoInBackground()方法中.

The only thing left is to actually make the web calls. I would recommend using an HttpURLConnection for this. You would put this code inside the doInBackground() method of your AsyncTask.

我将向您展示我已建立的示例Web服务呼叫.这显示了如何进行Web服务调用以检索JSON响应.看起来像这样:

I'll show you an example web service call I have set up. This shows how to make a web service call to retrieve a JSON response. It looks something like this:

//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;

这几乎是您要做的所有事情.我意识到这是一次向您提供大量信息,但是如果您花费时间并逐一进行研究,您会发现它毕竟并不难,实际上它是一种非常强大的工具,会一直使用编程的Android应用程序!

This is pretty much all you need to know to do exactly what it is you are trying to do. I realize this is a ton of info to throw at you all at once, but if you take your time and work through it piece by piece, you'll find it's not too difficult after all and is actually a VERY powerful tool that you'll use all the time programming Android apps!

希望这会有所帮助.对于尚未完全理解的任何部分,随时提出问题!

Hope this helps. Feel free to ask questions for any parts you don't fully understand yet!

这篇关于从服务器请求数据的最佳方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆