如何在主线程中处理一些代码时显示进度对话框(在单独的线程中?)

时间:2011-04-12 09:57:15

标签: android android-asynctask progressdialog


我需要执行以下操作:当应用程序启动时,它会运行一个活动(splashActivity),它尝试创建一个DBHelper(SQLiteDatabase)实例,该实例在创建时检查数据库是否存在,如果不存在则创建一个。
在这个数据库创建过程中,我想显示ProgressDialog并且阻止主线程在DB未就绪时进行处理

splashActivity:

public class SplashActivity extends Activity {
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.splash);
        showSplash();
        DBHelper dbHelper = new DBHelper(this);
        dbHelper.close();
  }
}

DBHelper类:

public class DBHelper extends SQLiteOpenHelper { 
...
    private ProgressDialog mProgressDialog;
...
  public DBHelper(Context context) { 
    super(context, DB_NAME, null, 1);
    appContext=context;
    dbReadable = getReadableDatabase();
    if (createDB)
        initDB();
  } 
  @Override 
  public void onCreate(SQLiteDatabase db) {
      createDB=true;
  } 
  public void initDB() {
      ...
      if (createDB) 
          restoreDB();
      ...
  }

  private void restoreDB(){
   // place for db creation/restoring method call (restoreDBFromFile() etc)
   // and displaying the progress
  }

我试图将AsyncTask作为DBHelper的内部类:

  private class RestoreDBTask extends AsyncTask <Void, Void, String>
    {
        private ProgressDialog dialog;

        @Override
        protected void onPreExecute()
        {
            this.dialog = ProgressDialog.show(DBHelper.this.appContext, DBHelper.this.appContext.getResources().getString(R.string.progress_wait), 
                    DBHelper.this.appContext.getResources().getString(R.string.progress_db_installing), true);
        }

        @Override
        protected String doInBackground(Void... params)
        {
            restoreDBFromFile();
            return "";
        }

        @Override
        protected void onPostExecute(String result)
        {
            this.dialog.dismiss();
        }
    }

所以restoreDB()是:

restoreDB() {
      RestoreDBTask task = new RestoreDBTask();
      task.execute();
}

它启动显示PD的任务,但同时主线程继续,因此崩溃导致DB未准备好。这意味着主要线程应该暂停,而DB没有准备好所以我试图睡眠/等待/加入没有成功。好。反正它也不好 下次我从restoreDB()调用restoreDBFromFile(),以便异步任务仅用于PD显示:

restoreDB() {
  RestoreDBTask task = new RestoreDBTask();
  task.execute();
  restoreDBFromFile();    
}

它不显示任何PD。所以我尝试在restoreDB()中创建PD:

restoreDB() {
   mProgressDialog = ProgressDialog.show(appContext, 
          appContext.getResources().getString(R.string.progress_wait), 
          appContext.getResources().getString(R.string.progress_db_installing), 
          true);
  restoreDBFromFile();    
}

但也没有PD!下次我尝试以下内容:

    restoreDB() {
      Thread thread =  new Thread(null, new Runnable(){
              @Override
              public void run() {
                  mProgressDialog = ProgressDialog.show(appContext, 
                          appContext.getResources().getString(R.string.progress_wait), 
                          appContext.getResources().getString(R.string.progress_db_installing), 
                          true);
              }
          }, "ProgressDialog");
      thread.start();
      restoreDBFromFile();
}

再次没有PD而立即崩溃:

  

04-12 08:40:38.894:   错误/ AndroidRuntime(2448):错误:   线程附加失败04-12   08:40:38.913:DEBUG / dalvikvm(2448):   LinearAlloc 0x0使用5239880的639500   (12%)04-12 08:40:39.094:   DEBUG / ddm-heap(2454):获得了功能列表   要求04-12 08:40:39.492:   WARN / dalvikvm(2454):threadid = 15:   线程退出与未捕获的异常   (group = 0x4001b188)04-12 08:40:39.492:   错误/ AndroidRuntime(2454):未捕获   handler:线程ProgressDialog退出   由于04-12未被捕获的例外   08:40:39.504:   ERROR / AndroidRuntime(2454):   java.lang.RuntimeException:不能   在具有的线程内创建处理程序   不叫做Looper.prepare()04-12   08:40:39.504:   错误/ AndroidRuntime(2454):at   android.os.Handler。(Handler.java:121)   04-12 08:40:39.504:   错误/ AndroidRuntime(2454):at   android.app.Dialog。(Dialog.java:105)   04-12 08:40:39.504:   错误/ AndroidRuntime(2454):at   android.app.AlertDialog。(AlertDialog.java:63)   04-12 08:40:39.504:   错误/ AndroidRuntime(2454):at   android.app.ProgressDialog。(ProgressDialog.java:80)   04-12 08:40:39.504:   错误/ AndroidRuntime(2454):at   android.app.ProgressDialog。(ProgressDialog.java:76)   04-12 08:40:39.504:   错误/ AndroidRuntime(2454):at   android.app.ProgressDialog.show(ProgressDialog.java:101)   04-12 08:40:39.504:   错误/ AndroidRuntime(2454):at   android.app.ProgressDialog.show(ProgressDialog.java:90)   04-12 08:40:39.504:   错误/ AndroidRuntime(2454):at   com.taxiorder.DBHelper $ 1.run(DBHelper.java:157)   04-12 08:40:39.504:   错误/ AndroidRuntime(2454):at   java.lang.Thread.run(Thread.java:1096)


尝试了一些没有结果的事情......所以我无法弄清楚出了什么问题。

再次 - 我只需要在restoreDB()执行时显示PD。我不能在单独的线程中运行restoreDB(),因为我需要在app继续之前完成它。我可以看到PD应该只在单独的线程中运行,但我无法管理它。

现在我还有两个问题:

1)如果PD应该在单独的线程中创建,那么它是否可以创建并显示它的线程什么都不做。我的意思是这样的:

    new Thread(){
          public void run(){
              mProgressDialog = ProgressDialog.show(appContext, 
                      appContext.getResources().getString(R.string.progress_wait), 
                      appContext.getResources().getString(R.string.progress_db_installing), 
                      true);

      }.start();

据我所知,线程在执行run()后立即死亡导致无事可做,因此PD不会显示 2)PD本身在显示时不会挂起任何线程,是吗?

1 个答案:

答案 0 :(得分:5)

尝试将AsyncTask声明为活动的内部类,在那里实例化并执行它。我认为问题出在ProgressDialog创建它的上下文中,这样做的逻辑太复杂了。在活动中声明AsyncTask是更常见的做法。

然后,AsyncTask必须在doInBackground方法

中使用DB完成所需的一切
public class SplashActivity extends Activity {
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.splash);

        new RestoreDBTask().execute();
    }

}

private class RestoreDBTask extends AsyncTask <Void, Void, String>
{
    private ProgressDialog dialog;

    @Override
    protected void onPreExecute()
    {
        dialog = ProgressDialog.show(
            SplashActivity.this,
            getString(R.string.progress_wait),
            getString(R.string.progress_db_installing), 
            true);
    }

    @Override
    protected String doInBackground(Void... params)
    {
        // do all the things with DB
        DBHelper dbHelper = new DBHelper(SplashActivity.this);
        dbHelper.close();
        return "";
    }

    @Override
    protected void onPostExecute(String result)
    {
        dialog.dismiss();
    }
}