如何在两个活动之间显示进度对话框?

11

我有一个问题。我需要从一个Activity跳转到另一个Activity。我的第二个Activity具有大量元素的xml布局(我说的是大约四百个元素),因此它需要几秒钟(太久了)才能显示这个第二个Activity。

如何在两个Activity之间显示进度对话框?

我试图使用后台任务来做到这一点。

我在我的Activity A中有这个方法:

  private void goToYear() {
   Intent intent = new Intent();
   intent.setClass (getBaseContext(), YearActivity.class);
   startActivity( intent);
  }

然后在我的 Activity B 中:

public class YearActivity extends Activity {

 private String  TAG = "YearActivity ::";

 private ProgressDialog pd = null;


    @Override
    public void onCreate( Bundle savedInstanceState) {
        super.onCreate( savedInstanceState);

        // Show the ProgressDialog on this thread
        this.pd = ProgressDialog.show(this, "Working...", "Calculating the screen...", true, false);

        // Start a new thread that will download all the data
        new MakeYearTask().execute();

    }

    private void initCalendar () {
      this.setContentView( R.layout.calendar_year);   

   ...
   ...
   initialize values
   ...
   ...

    }


    private class MakeYearTask extends AsyncTask<String, Void, Object> {
        protected Void doInBackground(String... args) {
            Log.i("YearActivity::MakeYearTask", "MakeYearTask Background thread starting");

   YearActivity.this.initCalendar();


        }

        protected void onPostExecute(Object result) {

            if (YearActivity.this.pd != null) {
             YearActivity.this.pd.dismiss();
            }
        }
   } 
}

你可以看到我将setContentView方法放在了onCreate方法之外。

但这样做是行不通的,会导致一个异常,就像这样:

12-09 19:49:17.729: ERROR/AndroidRuntime(218): java.lang.RuntimeException: An error occured while executing doInBackground()
12-09 19:49:17.729: ERROR/AndroidRuntime(218):     at android.os.AsyncTask$3.done(AsyncTask.java:200)
12-09 19:49:17.729: ERROR/AndroidRuntime(218):     at java.util.concurrent.FutureTask$Sync.innerSetException(FutureTask.java:234)
12-09 19:49:17.729: ERROR/AndroidRuntime(218):     at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:258)
12-09 19:49:17.729: ERROR/AndroidRuntime(218):     at java.util.concurrent.FutureTask.run(FutureTask.java:122)
12-09 19:49:17.729: ERROR/AndroidRuntime(218):     at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:648)
12-09 19:49:17.729: ERROR/AndroidRuntime(218):     at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:673)
12-09 19:49:17.729: ERROR/AndroidRuntime(218):     at java.lang.Thread.run(Thread.java:1060)
12-09 19:49:17.729: ERROR/AndroidRuntime(218): Caused by: android.view.ViewRoot$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
12-09 19:49:17.729: ERROR/AndroidRuntime(218):     at android.view.ViewRoot.checkThread(ViewRoot.java:2629)
12-09 19:49:17.729: ERROR/AndroidRuntime(218):     at android.view.ViewRoot.requestLayout(ViewRoot.java:545)
12-09 19:49:17.729: ERROR/AndroidRuntime(218):     at android.view.View.requestLayout(View.java:7657)
12-09 19:49:17.729: ERROR/AndroidRuntime(218):     at android.view.ViewGroup.addView(ViewGroup.java:1749)
12-09 19:49:17.729: ERROR/AndroidRuntime(218):     at android.view.ViewGroup.addView(ViewGroup.java:1731)
12-09 19:49:17.729: ERROR/AndroidRuntime(218):     at com.android.internal.policy.impl.PhoneWindow.generateLayout(PhoneWindow.java:2186)
12-09 19:49:17.729: ERROR/AndroidRuntime(218):     at com.android.internal.policy.impl.PhoneWindow.installDecor(PhoneWindow.java:2239)
12-09 19:49:17.729: ERROR/AndroidRuntime(218):     at com.android.internal.policy.impl.PhoneWindow.setContentView(PhoneWindow.java:309)
12-09 19:49:17.729: ERROR/AndroidRuntime(218):     at android.app.Activity.setContentView(Activity.java:1620)
12-09 19:49:17.729: ERROR/AndroidRuntime(218):     at es.jota.app.YearActivity.initCalendar(YearActivity.java:42)
12-09 19:49:17.729: ERROR/AndroidRuntime(218):     at es.jota.app.YearActivity.access$0(YearActivity.java:41)
12-09 19:49:17.729: ERROR/AndroidRuntime(218):     at es.jota.app.YearActivity.initCalendar$MakeYearTask.doInBackground(YearActivity.java:120)
12-09 19:49:17.729: ERROR/AndroidRuntime(218):     at es.jota.app.YearActivity.initCalendar$MakeYearTask.doInBackground(YearActivity.java:1)
12-09 19:49:17.729: ERROR/AndroidRuntime(218):     at android.os.AsyncTask$2.call(AsyncTask.java:185)
12-09 19:49:17.729: ERROR/AndroidRuntime(218):     at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:256)
12-09 19:49:17.729: ERROR/AndroidRuntime(218):     ... 4 more

回答如何在两个活动之间创建进度条 [链接](https://dev59.com/h3I-5IYBdhLWcg3wMFMf) - sagus_helgy
4个回答

1
这是一个很糟糕的设计。如果你有大量数据要呈现给用户,并且需要滚动查看,那么你应该使用一个AdapterView子类,例如ListView或GridView。几乎含有400个元素的XML布局非常庞大。
我理解你的意图(你试图在单独的线程上使用AsyncTask执行大量View层次结构的构建,但你发现它已经因为尝试在非UI线程上触摸View层次结构而崩溃)。
即使你成功地在前台实现了某种进度条,同时层次结构正在被构建,我也不确定系统是否提供了一种调用进度信息的方法,同时它还会膨胀View层次结构(但我可能是错的)。

AdapterView是专门为解决这种问题而创建的。使用AdapterView,通常只有一个屏幕大小的Views存在于内存中。例如,你可以有一张包含一千行数据的表格,但是由于屏幕一次只能显示七行,因此仅有八行View会同时存在于内存中。此外,适配器还应该回收View,进一步优化性能。


如果您需要设计一个包含可水平和垂直滚动的表格的屏幕,您将如何使用适配器来解决? - Emil Adz
好的观点。我简要搜索了一下,并找到了几个SO问题,这些问题建议使用基于适配器的水平和垂直可滚动布局是可能的,只需要做一点点工作(例如http://stackoverflow.com/questions/7681581/android-listview-in-horizontalscrollview-performance-issues)。我认为,如果OP在`.setContentView()`中遇到过多的延迟,则整体性能可能会变得缓慢(也许在较慢的设备上),因此即使意味着需要付出一些努力来使其正常工作或重新思考UI,使用基于适配器的布局也是值得的。 - Trevor
其实我同意,我只是在这里遇到了这个问题:https://dev59.com/F2_Xa4cB1Zd3GeqP7Ptv,仍在寻找解决方案。但还是谢谢:) - Emil Adz
1
啊!这很有趣——事实上,就在前几天我还收藏并点赞了你的那个问题。我的一个应用程序也有非常类似的UI结构(带有包含TableLayouts的Fragment的分页器,在使用适配器比较棘手的情况下),有时会非常缓慢,所以我对看到给你提供的建议很感兴趣。我一定会反馈任何我能提供的帮助。 - Trevor

0
你尝试过在onResume()中执行new MakeYearTask().execute();吗?
虽然不太优雅,但你可以在onCreate()中触发一个延迟的线程post来等待几毫秒。
编辑:
我刚刚遇到了这个错误:
(Caused by: android.view.ViewRoot$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views)

你是在AsyncTask中修改UI吗?

你应该只在doInBackground()中构建数据,然后在onPostExecute()中更新UI。


是的,现在就是这个结果。:( 无论如何,谢谢。 - Jose Manuel
我编辑了我的答案并添加了额外的信息。也许是这个原因。 - blindstuff

0

这可能不是最好的解决方案,但你可以扩展 Android 中使用的基本主题,并将窗口背景设置为指示活动正在加载的图像。然后将该主题设置为 Activity B。现在,在 Activity B 加载时,它将显示你的可绘制对象而不是黑色窗口。你甚至可以使用 animation-list 进行创意设计,获得某种不确定的加载效果。


嗯,我和你想法一样,但如果它能够正常工作,那对我来说就可以了 :)我会尝试一下,然后告诉你发生了什么。谢谢。 - Jose Manuel
我还没有尝试过这个,但我已经把它放在我的“待办事项”清单中了。当我尝试后,我会告诉你结果的。谢谢! - Jose Manuel
期待收到结果。 - Nathan Schwermann

0

你的格式有点问题,但如果我理解正确,你正在AsyncTaskdoInBackground()中调用initCalendar()。使用AsyncTask时,不能这样做。

使用doInBackground()执行长时间运行的操作,例如HTTP调用、数据库访问等等。一旦你有了需要的东西,就从onPostExecute()中调用initCalendar()


我会尝试理解你的回答。我是西班牙人,我的英语不太好。 - Jose Manuel
基本上,我的意思是将这个 YearActivity.this.initCalendar(); 移动到 onPostExecute() 方法中,并且我正在尝试解释为什么。 :) - Zarah
嗨Zarah!对我来说很难解释。如果我将YearActivity.this.initCalendar()放在onPostExecute()上,我不会有任何错误,但ProgressDialog不会显示......活动之间的转换需要几秒钟,这就是我想要防止的事情。我想展示progressdialog以使等待更加舒适。你知道我的意思吗?为此,我使用AsyncTask。也许存在另一种方法来实现这一点,但我不知道。:( - Jose Manuel
onPreExecute() 中显示进度条,并在 onPostExecute() 中关闭它。 - Zarah

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