【发布时间】:2020-12-12 14:13:07
【问题描述】:
我正在尝试将一个字符串从 AsyncTask 传递回我的 Activity。浏览了其他类似的问题(例如here),我决定使用接口监听器。
界面:
package com.example.myapplication;
public interface GetListener {
void passJSONGet(String s);
}
AsyncTask 类:
package com.example.myapplication;
import android.content.Context;
import android.os.AsyncTask;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
public class DataGetter extends AsyncTask<String, Void, String> {
Context context;
private GetListener GetListener;
public String jsonString;
DataGetter(Context ctx, GetListener listener) {
this.context = ctx;
this.GetListener = listener;
}
@Override
protected String doInBackground(String... params) {
String ip = params[0];
String scriptname = params[1];
String db = params[2];
String urladress = "http://" + ip + "/"+ scriptname +".php";
try {
URL url = new URL(urladress);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setDoInput(true);
connection.setDoOutput(true);
OutputStream os = connection.getOutputStream();
OutputStreamWriter writer = new OutputStreamWriter(os, "UTF-8");
String data = URLEncoder.encode("database", "UTF-8") + "=" + URLEncoder.encode(db, "UTF-8");
writer.write(data);
writer.flush();
writer.close();
BufferedReader reader = new BufferedReader(new
InputStreamReader(connection.getInputStream()));
StringBuilder sb = new StringBuilder();
String line = null;
while ((line = reader.readLine()) != null) {
sb.append(line);
break;
}
return sb.toString();
} catch (Exception e) {
return e.getMessage();
}
}
@Override
protected void onPostExecute(String result) {
GetListener.passJSONGet(result);
}
}
我的活动:
import android.os.Bundle;
import android.widget.TextView;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
import org.json.JSONArray;
import org.json.JSONException;
public class WeatherDisplay extends AppCompatActivity implements GetListener {
private JSONArray jsonArray;
private String jsonString;
@Override
protected void onCreate(Bundle savedInstanceState) {
// other code
DataGetter dataGetter = new DataGetter(this, WeatherDisplay.this);
dataGetter.execute(ip, "readLatestOutside", "weather");
Toast.makeText(this, this.jsonString, Toast.LENGTH_LONG).show();
this.jsonArray = new JSONArray(this.jsonString);
// furter code
}
@Override
public void passJSONGet(String jsonstring) {
this.jsonString = jsonstring;
}
JSON 是从服务器正确获取的,通常可以在 onPostExecute 中看到,但是稍后在 WeatherDisplay 中不可见(Toast 显示为空,变量仍然是空指针)。
我该如何解决这个问题?我缺乏经验,可能错过了一些琐碎的事情。
【问题讨论】:
-
您的
onCreate代码创建AsyncTask,将其设置为在后台运行,然后立即跳转到下一行并显示Toast- 您还没有准备好!稍后任务完成,运行onPostExecute,这基本上最终将您的变量设置在Activity中,仅此而已。您应该在passJSONGet中创建 toast,因为那是您实际接收要显示的信息的地方 -
以防万一您不知道,代码通常会逐行执行,如果您要获取一些数据,则必须等待结果返回才能继续(它会阻塞线程)。这就是所谓的同步执行,这一切都是一起发生的。相反的是异步执行,它通常被称为async,基本上是“东西可以在不同的时间运行和完成”,所以你可以继续做其他事情。
AsyncTasks 是一种在后台做一些事情的方法 - 你将它们关闭,然后它们会返回结果并做任何事情 -
@cactustictacs 我附加了
passJSONGet以在WeatherDisplay活动中设置一个布尔标志,在该标志上的“无所事事”循环使应用程序崩溃。我怎么能等待AsyncTask返回字符串,以便我可以将其转换为JSON array(根据代码,暂时忽略Toast)? -
好的,我添加了一个带有大量背景的答案,以帮助您了解一般情况,但您根本不应该等待结果 - 您的代码旨在对 @ 做出反应987654339@ 完成,通过运行
onPostExecute中的任何内容。这就是你对结果做任何你需要做的事情的地方。看看,希望对你有帮助!
标签: java android android-asynctask