Лучший способ запросить данные с сервера
Мне нужно получить некоторые данные с моего сервера, чтобы заставить мое приложение работать. Для этого я буду использовать 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 очень полезен, посмотрите здесь примеры.