外部AsyncTask中的ProgressDialog无法工作

9
我开始认为,要让ProgressDialog正常工作,AsyncTask必须是Activity类的内部类。这是真的吗?[编辑很久以后...答案是否定的,我不确定这是一个bug还是什么问题。我正在使用Android 1.5。我要研究一下Services。]
我有一个使用数据库来操作信息的活动。如果数据库已经被填充了,一切都很好。如果没有填充,则需要从网站下载信息,填充数据库,然后访问填充的数据库以完成onCreate中的视图。
问题是,如果没有办法确定AsyncTask线程何时完成填充数据库,我会收到以下强制关闭错误消息:抱歉!应用程序意外停止。我点击Force Close按钮,后台AsyncTask线程继续工作,数据库得到填充,一切正常。
我需要摆脱这个错误消息,并需要一些帮助来解决这个问题。这里是一些伪代码:
public class ViewStuff extends Activity
{
  onCreate
  { 
    if(database is populated)
      do_stuff
    else
    {
      FillDB task = null;
      if(task == null || task.getStatus().equals(AsyncTask.Status.FINISHED))
       {                
         task = new FillDB(context);
         task.execute(null);
       }
    }

  continue with onCreate using information from database to properly display 

 } // end onCreate
} // end class

在单独的文件中:

public class FillDB extends AsyncTask<Void, Void, Void>
{
    private Context context;

    public FillDB (Context c)  //pass the context in the constructor
{
    context = c;
}

    public void filldb ()
    {
      doInBackground();
    }

    @Override
    protected void onPreExecute()
    {          
       ProgressDialog progressDialog = new ProgressDialog(context);
       //crashes with the following line
       progressDialog.show(context, "Working..", "Retrieving info");
    }

    @Override
    protected Void doInBackground(Void... params)
    {
  // TODO Auto-generated method stub

try
     etc etc etc
    }
 }

以下是模拟器的堆栈跟踪信息:

----- pid 846 at 2010-03-21 19:58:25 -----
Cmd line: com.trial

DALVIK THREADS:
"main" prio=5 tid=3 NATIVE
 | group="main" sCount=1 dsCount=0 s=0 obj=0x40018e70
 | sysTid=846 nice=0 sched=0/0 handle=-1098855268
 at android.os.BinderProxy.transact(Native Method)
 at      android.app.ActivityManagerProxy.handleApplicationError(ActivityManagerNative.java:2103)
 at com.android.internal.os.RuntimeInit.crash(RuntimeInit.java:302)
 at   com.android.internal.os.RuntimeInit$UncaughtHandler.uncaughtException(RuntimeInit.java:75)
 at java.lang.ThreadGroup.uncaughtException(ThreadGroup.java:887)
 at java.lang.ThreadGroup.uncaughtException(ThreadGroup.java:884)
 at dalvik.system.NativeStart.main(Native Method)

 "Binder Thread #3" prio=5 tid=15 NATIVE
 | group="main" sCount=1 dsCount=0 s=0 obj=0x43733d88
 | sysTid=852 nice=0 sched=0/0 handle=1486928
 at dalvik.system.NativeStart.run(Native Method)

"Binder Thread #2" prio=5 tid=13 NATIVE
 | group="main" sCount=1 dsCount=0 s=0 obj=0x437313c8
 | sysTid=851 nice=0 sched=0/0 handle=1492472
 at dalvik.system.NativeStart.run(Native Method)

"Binder Thread #1" prio=5 tid=11 NATIVE
 | group="main" sCount=1 dsCount=0 s=0 obj=0x4372b9b0
 | sysTid=850 nice=0 sched=0/0 handle=1492664
 at dalvik.system.NativeStart.run(Native Method)

"JDWP" daemon prio=5 tid=9 VMWAIT
 | group="system" sCount=1 dsCount=0 s=0 obj=0x4372a2a0
 | sysTid=849 nice=0 sched=0/0 handle=1490176
 at dalvik.system.NativeStart.run(Native Method)

"Signal Catcher" daemon prio=5 tid=7 RUNNABLE
| group="system" sCount=0 dsCount=0 s=0 obj=0x4372a1e8
| sysTid=848 nice=0 sched=0/0 handle=1487888
 at dalvik.system.NativeStart.run(Native Method)

"HeapWorker" daemon prio=5 tid=5 VMWAIT
 | group="system" sCount=1 dsCount=0 s=0 obj=0x427d03c0
 | sysTid=847 nice=0 sched=0/0 handle=1487592
 at dalvik.system.NativeStart.run(Native Method)

 ----- end 846 -----

我应该做什么才能解决问题?

Snowflake先生,

尝试过的方法:

@Override
protected void onPreExecute()
{

Activity.this.runOnUiThread(new Runnable() {
      public void run() {
        ProgressDialog progressDialog = new ProgressDialog(context);
        //crashes with the following line
        progressDialog.show(context, "Working..", "Retrieving info");
      }
    });
}

Activity.this被标记为错误:在范围内无法访问Activity的封闭实例。

我认为我需要创建一个FillDB扩展Activity,然后在FillDB中创建一个扩展AsyncTask的私有类?但这样行不通。不能保证何时会启动FillDB活动,也不能使用startActivityForResult,因为当AsyncTask完成时不返回任何结果。

更新:尝试在调用类中创建一个私有类。仍然无法显示ProgressDialog。其中一个错误是:无法添加窗口--令牌null不适用于应用程序。我不知道所指的令牌是什么。


使用adb logcat、DDMS或Eclipse中的DDMS透视图来查看与强制关闭对话框相关联的Java堆栈跟踪,因为该堆栈跟踪应该会提供有关出现问题的更多信息。 - CommonsWare
CommonsWare - 我对adb不够了解,无法在/data/anr/traces.txt中找到堆栈跟踪。但是通过查看Eclipse中的Logcat和DDMS,似乎我有一个未捕获的运行时异常。java.lang.reflect.InvocationTargetException java.lang.RuntimeExceptionWindowMai尝试添加具有非应用程序令牌WindowToken(43711b88 token=null)的窗口。中止。我查看了上下文是否为空,但它似乎不是: this.context显示:context android.app.Application(id=830060323048) - eric
你正在将什么上下文传递给你的AsyncTask?它是Activity还是其他什么东西? - Romain Guy
Romain,我正在传递应用程序上下文: context = getApplicationContext();如果任务为null或任务状态为AsyncTask.Status.FINISHED,则执行以下操作: task = new FillNYLottoDB(context); task.execute(null); - eric
如果在任务运行时更改横向/纵向模式,对话框会发生什么?使用runOnUiThread(...)在Runnable中创建对话框是否安全? - user551888
4个回答

2

我放弃了AsyncTask,改用Handler来处理线程,现在一切都很好。

不确定是1.5版本中AsyncTask的一个错误还是我没有做其他事情。


2
你是否考虑过重写onCreateDialog()方法来实现对话框?这样可以很容易地创建和控制它们,因为Android已经为你完成了大部分工作。我在下面提供了一个实例,正好符合你要尝试的需求。 http://pastie.org/880540

Jason,那也不行。也许我还有其他问题?你用的是哪个Android版本? - eric

0

尝试运行

   ProgressDialog progressDialog = new ProgressDialog(context);
   //crashes with the following line
   progressDialog.show(context, "Working..", "Retrieving info");

作为可运行的参数传递给Activity.runOnUiThread()。用户界面元素应该在UI线程中创建和操作。我想这对于Dialog也是正确的。
[编辑] 代码:
Activity.this.runOnUiThread(new Runnable() {
  public void run() {
    ProgressDialog progressDialog = new ProgressDialog(context);
    //crashes with the following line
    progressDialog.show(context, "Working..", "Retrieving info");
  }
};

雪花先生,(我该如何格式化注释以避免一切都混在一起?) 我尝试了:Activity.runOnUiThread((Runnable) progressDialog.show(context, "Working..", "Retrieving info"); 它告诉我:无法对Activity类型进行静态引用非静态方法runOnUIThread(Runnable)。 - eric
MrSnowflake - 尝试过了,但不行。我编辑了我的帖子,展示了你的代码并入到我的代码中。谢谢。 - eric

0
我曾经和OP一样遇到了一个公共(外部)AsyncTask的问题。在研究错误信息“尝试添加具有非应用程序令牌的窗口”时,我发现问题在于设置传递给AsyncTask构造函数的上下文。应该传递的上下文是“this”,而不是this.getApplicationContext()或this.getBaseContext()。这解决了我的问题。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接