【发布时间】:2015-08-16 11:53:34
【问题描述】:
我在容器 Activity 中有一个选项卡片段。
我想下载一些数据以显示在选项卡中。在选项卡中,我创建了一个异步任务,我在 onCreateView 中填充片段布局后执行该任务。当我这样做时,AsyncTask 的 doInBackground... 工作发生在主线程上,并且视图在完成之前不会加载。我的所有进度...任务完成后,日志会同时显示。
但是,如果我在片段布局中放置一个按钮并启动 asynctask 作为对按钮单击的响应,它会按预期工作,我会得到正常间隔的进度更新。
那么,如果 AsyncTask 是我的 Fragment 启动时发生的第一件事,为什么还要在主线程上运行呢?而且,我怎样才能防止这种情况发生?我的最终目标是在数据下载时显示进度轮。
编辑。这是我调用 AsyncTask 的地方。
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
final View rootView = inflater.inflate(R.layout.temp_my_moments, container, false);
getMyClips(getActivity(), rootView, p_session, p_person,progressBar);
//If I use this button, it works fine:
// test = (Button) rootView.findViewById(R.id.testbutton);
// test.setOnClickListener(new View.OnClickListener() {
// @Override
// public void onClick(View v) {
// progressBar =(ProgressBar) rootView.findViewById(R.id.myMomentsProgress);
// getMyClips(getActivity(), rootView, p_session, p_person, progressBar);
// }
// });
return rootView;
}
这里是 getMyClips():
public void getMyClips(Context context,View view,String thisSession,String thisPerson,ProgressBar progressBar) {
Log.d("Currently running", "getMyClips");
JSONObject params = new JSONObject();
try {
params.put("Function", clipsMine_apiCall);
params.put("p_session", thisSession);
params.put("p_person", thisPerson);
} catch (JSONException e1) {
e1.printStackTrace();
}
ApiClipCaller webServiceTask = new ApiClipCaller(context,view,progressBar);
if (webServiceTask.hasConnection()) {
webServiceTask.execute(params);
} else {
//TODO no internet connection
}
}
编辑这是我的 AsyncTask。这是在 Fragment 内部:
public class ApiClipCaller extends AsyncTask<JSONObject, Integer, ApiResponse> {
public Context context;
public String clipID;
public String sessionID;
public String personID;
public String functionName;
public View view;
public ProgressBar progressBar;
public final String apiURL = "...."; //need to keep private
LinearLayout loading;
public ApiClipCaller(Context c, View v,ProgressBar progressBar) {
this.context = c;
this.view = v;
this.progressBar = progressBar;
loading = (LinearLayout) view.findViewById(R.id.loadingMyMoments);
}
@Override
protected ApiResponse doInBackground(JSONObject... params) {
JSONObject realParams = params[0];
try {
functionName = realParams.getString("Function");
} catch (JSONException e) {
e.printStackTrace();
}
ApiResponse responseObject = masterFunction(realParams);
//making some work to see if it is running correctly
for (int i=10;i<=100;i += 10)
{
try {
Thread.sleep(1000);
publishProgress(i);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
return responseObject;
}
@Override
protected void onProgressUpdate(Integer... progress) {
loading.setVisibility(View.VISIBLE);
progressBar.setProgress(progress[0]);
Log.d("progress",Integer.toString(progress[0]));
}
@Override
protected void onPostExecute(ApiResponse responseObject) {
loading.setVisibility(View.GONE);
if (functionName.equals(clipsMine_apiCall)) {
JSONObject clipObject = responseObject.getResponseJSONObject();
//just testing here to see if I can get data back in the fragment view when it is done.
///This works as expected.
String responseString = responseObject.getResponseString();
TextView showAsyncResults = (TextView) view.findViewById(R.id.testAsyncTask);
showAsyncResults.setText(responseString);
}
super.onPostExecute(responseObject);
}
}
【问题讨论】:
-
向我们展示您的 AsyncTask 代码。
-
我不知道为什么这个问题值得这么多反对?
-
向我们展示您如何在片段中调用 asyncTask。你是直接调用 doInBackground 吗?
-
那么您到底对什么感兴趣?对这种现象的解释(这样它就不会再次发生)?或者深入回答为什么
AsyncTask是这样设计的? -
@fullmeriffic
execute(...)方法上的 javadoc 明确指出:This method must be invoked on the UI thread。您通过在错误的线程上调用它来破坏该方法的合同,因此您会得到不正确的行为。如果你想从主线程开始你的AsyncTask- 将它作为一个事件发布在 UI 线程上(老实说我不知道是什么方法,但我对 Swing 的经验告诉我这应该很容易)跨度>
标签: java android multithreading android-fragments android-asynctask