来自AsyncTask的工作线程阻止UI线程

时间:2012-10-31 16:35:23

标签: android android-asynctask ui-thread

我正在创建一个Android应用程序,在单击Activity中的SEARCH BUTTON后,在AsyncTask类中下载JSON文件。我想在下载数据时在Activity上显示Progress Dialog。但是在我的AVD和设备上,实际操作与我的想法不同。观看此视频(约1分钟)我上传了。 https://www.youtube.com/watch?v=qKyVGZ1FxIo&feature=youtube_gdata_player

在此视频中,在SEARCH BUTTON点击UI冻结一段时间后,然后显示ProgressDialog很短的时间并显示Toast。

我希望在点击后立即显示ProgressDialog,并在显示Toast之前立即关闭。

活动中的ClickListner:

@Override
public void onClick(View v) {
    DownloadJSONFile task = new DownloadJSONFile(MainActivity.this);
    task.execute("1", "class", lectureName, teacherName, date, period, "");
}

的AsyncTask:

import org.json.JSONArray;

import com.fc2.wiki.ap2012.komari.SearchResultActivity;

import android.app.ProgressDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.os.AsyncTask;
import android.widget.Toast;

public class DownloadJSONFile extends AsyncTask<String, Integer, JSONArray> {

private ProgressDialog dialog;
Context context;
JSONArray jsonArray;
boolean makeNewActivityFlag = true;

public DownloadJSONFile(Context context, boolean flag) {
    this.context = context;
    this.makeNewActivityFlag = flag;
}

@Override
protected void onPreExecute() {
    dialog = new ProgressDialog(this.context);
    dialog.setTitle("こまり");    //it's Japanese
    dialog.setMessage("通信中…");
    dialog.setIndeterminate(true);
    dialog.setCancelable(true);
    dialog.show();
}

doInBackground:

@Override
protected JSONArray doInBackground(String... keywords) {

    try {
        //for test
        while(!this.dialog.isShowing()){
            Thread.sleep(500);
        }

        //I will load JSON file here
        /*
        JSONArray jsonArray = UTaisakuDatabaseUtil.getInstance()
                .getJSONSearchResult(version, method, searchedLectureName,
                        searchedTeacherName, date, period, assessment);
        */

        //for test
        Thread.sleep(5000);

    } catch (NumberFormatException e) {
        // TODO 自動生成された catch ブロック
        e.printStackTrace();
    } catch (InterruptedException e) {
        // TODO 自動生成された catch ブロック
        e.printStackTrace();
    }

    return jsonArray;
}

onPostExecute:

@Override
protected void onPostExecute(JSONArray jsonArray) {

    this.jsonArray = jsonArray;
    if (this.dialog.isShowing())
        dialog.dismiss();

    if (this.makeNewActivityFlag) {

        // Intentを作成してSearchResultActivityへ
        if (jsonArray != null) {
            Intent intent = new Intent(this.context,
                    SearchResultActivity.class);
            intent.putExtra("LECTURE_NAME", searchedLectureName);
            intent.putExtra("TEACHER_NAME", searchedTeacherName);
            intent.putExtra("YOUBI", searchedDateString);
            intent.putExtra("PERIOD", searchedPeriodString);
            intent.putExtra("JSONARRAY", jsonArray.toString());
            context.startActivity(intent);
        } else

//in this test case,jsonArray is always null.So this Toast is always called
            Toast.makeText(context, "ファイルが取得できませんでした。", Toast.LENGTH_SHORT)
                    .show();
        }
    }
}

有什么想法吗?

2 个答案:

答案 0 :(得分:3)

我找到了解决自己问题的方法!我在Context的字段参数中使用了AsyncTask类。我使用Activity类而不是Context!所有事情都运行良好。

public class DownloadJSONFile extends AsyncTask<String, Integer, JSONArray> {

    private ProgressDialog dialog;

    //this is the cause of bug
    //Context context;        

    //this is the answer
    Activity activity;

    JSONArray jsonArray;
    boolean makeNewActivityFlag = true;

    public DownloadJSONFile(Activity activity, boolean flag) {
        this.activity = activity;
        this.makeNewActivityFlag = flag;
    }
…
…
}

但我无法解释为什么在使用Activity类时工作正常并且在使用Context类时工作不正常。有人可以解释一下吗?如果您有任何想法,请在此处发表评论。

答案 1 :(得分:0)

感谢发布解决方案,我采用了从zxing / BarCodeReader获取的代码时遇到了类似的问题。从构造函数参数中删除上下文后,睡眠被正确中断并且不再停止UI线程:

  AutoFocusManager(Context context, Camera camera) {
    this.camera = camera;
    taskExec = new AsyncTaskExecManager().build();
    SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(context);
    String currentFocusMode = camera.getParameters().getFocusMode();
    useAutoFocus =

        FOCUS_MODES_CALLING_AF.contains(currentFocusMode);
    Log.i(TAG, "Current focus mode '" + currentFocusMode + "'; use auto focus? " + useAutoFocus);
    start();
  }

       protected Object doInBackground(Object... voids) {
      try {
        Thread.sleep(AUTO_FOCUS_INTERVAL_MS);
      } catch (InterruptedException e) {
        // continue
      }
      synchronized (AutoFocusManager.this) {
        if (active) {
          start();
        }
      }
      return null;
    }