Лучший способ запросить данные с сервера

Мне нужно получить некоторые данные с моего сервера, чтобы заставить мое приложение работать. Для этого я буду использовать POST. Насколько я знаю, я должен запросить эти данные в потоке, который не может быть основным потоком. Я нахожу немного трудным поместить данные, которые я получаю, в переменную, определенную в потоке пользовательского интерфейса. Итак, мой вопрос, каков наилучший способ сделать это? Правильно ли установить значение переменной, определенной, например, в моей основной деятельности, с установщиком, вызываемым внутри AsyncTask? Или может быть лучше этот вариант?

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

Я читал, что я могу использовать интерфейсы для архивирования, но это концепция, которую я пока не очень хорошо понимаю. Я хотел бы напрямую использовать метод, который возвращает данные, но, насколько я знаю, это невозможно. 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: попытка вызвать метод интерфейса void com.pitazzo.geomoments.Handlers.LoginHandler$LoginCallback.onResultReceived(int)'для пустой ссылки на объект в com.pitazzo.geomoments.Handlers.LoginHandler$Login.onPostExecute(LoginHandler.java:65) в com.pitazzo.geomoments.LoginHandler$Login.onPostExecute(LoginHandler.java:17) на android.os.AsyncTask.finish(AsyncTask.java:636) на android.os.AsyncTask.access$500(AsyncTask.java:177) на android.os.Async $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. выполнить (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 ответа

Решение

Лучший способ добиться этого - использовать HttpURLConnection сделать ваши веб-звонки внутри AsyncTask а затем передать результат обратно в вызывающую активность через обратный вызов. Вот некоторый код, который поможет вам начать:

Первое, что вы должны понять, это как правильно использовать обратный вызов с 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);
    }
}

Как это работает, вы определяете открытый интерфейс, который затем внедряете в свою активность. Это действует как "слушатель", который ожидает любые данные, которые передаются на него. Определяем интерфейс TestTaskCallback потому что мы будем отправлять наши данные от нашего AsyncTask к нашему призванию

Затем в 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);
    }
}

Таким образом, наша деятельность реализует интерфейс, который мы определили внутри AsyncTaskи обратите внимание, что наши AsyncTask принимает ссылку на эту реализацию (передается через конструктор) и отправляет данные в onPostExecute() метод. Это позволит отправить ваш результат в основной поток пользовательского интерфейса, чтобы вы могли соответствующим образом обновить свою активность.

Осталось только сделать веб-звонки. Я бы порекомендовал использовать HttpURLConnection за это. Вы бы поместили этот код внутри doInBackground() метод вашего AsyncTask,

Я покажу вам пример вызова веб-службы, который я настроил. Здесь показано, как выполнить вызов веб-службы для получения ответа 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;

Это почти все, что вам нужно знать, чтобы делать именно то, что вы пытаетесь сделать. Я понимаю, что это тонна информации, которая сразу бросается на вас, но если вы потратите время и поработаете над ней по кусочкам, вы обнаружите, что это не так уж сложно, и на самом деле это ОЧЕНЬ мощный инструмент, который вы Я буду использовать все время программирования приложений Android!

Надеюсь это поможет. Не стесняйтесь задавать вопросы для любых частей, которые вы еще не до конца понимаете!

Лучше использовать AsyncTask для распространения данных в ваш поток пользовательского интерфейса, просто используйте onPostExecute() установить результат в классе вашей деятельности.

Ошибка, которую вы получаете из-за доступа к элементам пользовательского интерфейса из фонового потока.

AsyncTask - это API-интерфейс на основе пула потоков, который выполняет вашу задачу в отдельном потоке, но ваша часть пользовательского интерфейса выполняется в потоке, обычно называемом UI thread, чтобы обновить любые изменения пользовательского интерфейса поставить логику onPostExecute()

ПРИМЕЧАНИЕ: используйте okhttp для получения согласованного http api, он также поддерживает http2.Their github wiki очень полезен, посмотрите здесь примеры.

Другие вопросы по тегам