如何解决Android-将数据从AsyncTask传递到Activity
我正在尝试将字符串从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显示为空,变量仍然是nullpointer)。
如何解决此问题?我没有经验,可能错过了一些琐碎的东西。
解决方法
我认为有关Android如何运行代码的一些解释可能会有所帮助。
因此,在后台,Android不断循环运行一些代码。该循环的一部分是检查消息队列,该队列基本上是任务交付的地方-它需要执行的代码。理想情况下,它将足够快地完成每个循环中所需的所有工作,使其每秒可以管理60个循环。如果有太多事情要做,那它就会开始放慢速度,并变得有些僵硬。
一些可能要执行的任务类似于正在创建的Activity
,因此它可能希望系统运行其onCreate
代码-每个Activity
都执行一次。您可能已经注意到,它只会发生一次,而那正是您不断循环的地方,对吗?要在其中捕获执行,直到AsyncTask
传递其结果?
问题在于您正在停止主循环的工作-在完成该任务之前,它无法继续执行任何操作,并且您故意阻止了它。通常这很糟糕,这就是为什么我们鼓励您不要在该主线程(运行主循环程序的线程)上进行慢速操作-它创建的工作时间太长,并使整个UI的响应速度变慢(UI处理)也是需要运行的任务)
因此,这通常是不好的,但是AsyncTask
的实际工作方式是它们在另一个线程上运行(因此,它们不会阻塞主要线程,就像让另一个独立的人在处理东西一样)-但是它们在主线程上传递结果。他们将消息发布到主线程的消息队列中,告诉它运行onPostExecute
代码。
但是,在处理队列中较早的任务之前,系统无法获取该消息。而且,如果它正在忙于运行一个无休止的循环,等待AsyncTask
的结果,它将永远不会到达该消息,该变量将永远不会被更新,并且循环将永远不会看到它正在等待的更改。就像有人高举一条线,拒绝移动直到他们看到线下的某人试图传递的东西
这是一堆背景,但是重点是,您永远都不应阻塞这样的线程,除非它是您创建的特殊线程,这样您就可以了,并且不会干扰任何其他线程。将Android视为事件驱动的系统-您编写的代码应在发生某些事情时执行,例如创建活动(ònCreate
)或按下按钮(onClick
)或AsyncTask
完成(onPostExecute
)。所有这些方法都以“ on”开头是有原因的! “当事情发生时,执行此操作……”
因此,当您的任务完成时,它将运行onPostExecute
,这是您处理接收结果的所有代码的位置。实际上,它不需要放在onPostExecute
方法内-就像您已经将自己放在passJSONGet
方法内以保持事物井然有序,但这是从onPostExecute
调用的,这是事件触发代码运行。
因此,无论您需要如何处理结果,都可以从onPostExecute
调用它。发生这种情况时,它将执行您已告诉它要做的事情。更新变量,举杯,用一些新数据填充布局中的视图!
将代码更改为:
@Override
protected void onCreate(Bundle savedInstanceState) {
// other code
DataGetter dataGetter = new DataGetter(this,WeatherDisplay.this);
dataGetter.execute(ip,"readLatestOutside","weather");
// furter code
}
@Override
public void passJSONGet(String jsonstring) {
this.jsonString = jsonstring;
this.jsonArray = new JSONArray(this.jsonString);
Toast.makeText(this,this.jsonString,Toast.LENGTH_LONG).show();
}
您的流程有误。所有UI工作都应在onPostExecute之后完成
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。