3

I'm making an android application which downloads JSON file in the AsyncTask class after SEARCH BUTTON in Activity is clicked. And I want to display Progress Dialog on the Activity while downloading data. But on my AVD and device, actual action is different from my thought. See this video (about 1 minute) I uploaded. https://www.youtube.com/watch?v=qKyVGZ1FxIo&feature=youtube_gdata_player

In this video,after SEARCH BUTTON clicked the UI freeze for a while, and then ProgressDialog is shown for a very short moment and Toast is shown.

I want ProgressDialog to be shown right after click, and be dismissed right before Toast is shown.

ClickListner in Activity:

@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();
        }
    }
}

Any ideas?

KAKY
  • 61
  • 1
  • 6
  • 4
    Are there any errors in Logcat? Do you see the same behavior when you load the JSON instead of calling `sleep()`? Calling `dialog.isShowing()` from a non-UI thread has unpredictable behavior and may be causing the UI to freeze. – acj Oct 31 '12 at 16:47
  • You should first try initializing the dialog in the activity, not the asynctask. A dialog is not an attribute of a background thread, it belongs to an activity context. – Joel Oct 31 '12 at 20:15
  • @acj I see the same behavior,when loading JSON data and not using dialog.isShowing() or sleep().Thanks. – KAKY Nov 01 '12 at 03:29
  • @Joel I think a method called in `onPreExecute` is an attribute of the UI thread... My thought is not right, isn't it? When I initialize and call PrpgressDialog in UI thread,the behavior is same. – KAKY Nov 01 '12 at 03:40
  • Are you looking for the ProgressBar to display actual progress updates, or just a spinner to indicate that it's working? – Stephen Wylie Nov 01 '12 at 04:05
  • 2
    Hi @KAKY. As per my experience you should not create your dialogue box on `onPreExecure()` method. Just create and start your dialog before calling your asynctask. – sachy Nov 01 '12 at 04:06
  • @StephenWylie.I want to display a spinner to indicate that it's working. – KAKY Nov 01 '12 at 06:38

2 Answers2

3

I found a solution of my own problem! I used Context class in a field parameta of AsyncTask. I use Activity class instead of Context!All things are work fine.

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;
    }
…
…
}

But I can't explain why it's work fine when using Activity class and not work fine when using Context class.Can someone explain this? If you have any ideas,please comment here.

KAKY
  • 61
  • 1
  • 6
  • It is just one of those 'gotchas' that comes with android programming. You need to initialize the dialog as part of the context it is constructed with and launched from that object. For some reason, despite the onPreExecute() getting called on the main thread, constructing the dialog inside the task is not an option. Prolly worth looking at the context documentation. – Joel Nov 02 '12 at 17:34
0

Thanks for posting the solution, I had similar problem adopting the code taken from zxing/BarCodeReader. After removing the context from constructor parameters, sleeping is interrupted properly and does not stall the UI thread anymore:

  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;
    }
Ditto
  • 79
  • 1
  • 2