从服务器

时间:2016-03-22 22:30:42

标签: android multithreading post 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();

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

编辑: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);
}

}

编辑:为NoChinDeluxe添加了例外:

03-24 17:38:09.072 13312-13312 / com.pitazzo.geomoments E / AndroidRuntime:致命异常:主要                                                                         过程:com.pitazzo.geomoments,PID:13312                                                                         java.lang.NullPointerException:尝试调用接口方法&#39; void com.pitazzo.geomoments.Handlers.LoginHandler $ LoginCallback.onResultReceived(int)&#39;在null对象引用上                                                                             在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)                                                                             at 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)

编辑: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);

}

}

3 个答案:

答案 0 :(得分:4)

实现此目标的最佳方法是使用HttpURLConnectionAsyncTask内进行网络调用,然后通过回调将结果传回给您的调用活动。这里有一些代码可以帮助您入门:

您应该了解的第一件事是如何正确使用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);
    }
}

这样做的方法是,定义一个公共接口,然后在Activity中实现。这充当“监听器”,等待发送给它的任何数据。我们定义了接口TestTaskCallback,因为我们要将数据从AsyncTask发送到我们的调用活动。

然后在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);
    }
}

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

唯一剩下的就是实际进行网络通话。我建议使用onPostExecute()。您可以将此代码放在HttpURLConnection的{​​{1}}方法中。

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

doInBackground()

这几乎是你需要知道的,你要做的就是你要做的事情。我意识到这有很多信息可以立即引发你的注意,但是如果你花时间一点一点地完成它,你会发现它毕竟并不太难,实际上它是一个非常强大的工具,你'我会一直使用Android应用编程!

希望这会有所帮助。您可以随意为您尚未完全理解的任何部分提问:

答案 1 :(得分:1)

最好使用AsyncTask将数据传播到您的UI线程,只需使用onPostExecute()在您的活动类中设置结果。

答案 2 :(得分:0)

您获得的错误是因为从后台线程访问UI元素。

  

AsyncTask是一个基于线程池的api,它在一个单独的线程中运行你的任务   ,但您的UI部分在通常称为UI thread的线程中运行,   要更新ui的任何更改,请输入逻辑onPostExecute()

注意:使用okhttp获取一致的http api,它也支持http2。他们的github wiki非常有用,请查看here示例。