2

我有一个应用程序流程不同于 Android 标准的应用程序:

  • 标准:在活动 A 上按下按钮并在加载数据并构建活动 B 的视图时显示此活动的加载,然后才显示下一个活动。 (在活动 A 上调用 AsyncTask,完成发送数据并调用活动 B)

  • 我需要什么:按下活动 A 上的按钮,转到活动 B,在显示加载时,更新加载后活动 B 的视图。 (从活动 A 移动到 B 并在显示加载时调用 AsyncTask。当 AsyncTask 完成后,在加载在前面时更新视图,从而显示视图更新过程)

问题:这将使加载图标停止。有时会显示无响应的对话框(由于操作时间较长)并使用 UI 线程更改正在构建的视图。

我读过一些关于同一问题的问题:Android:如何动态更新 UI?

但没有人提供一个通用的答案。

如果你的回答是“这不是推荐的行为”,我会同意......但这些是要求,所以我真的很感激一些帮助:-D

4

4 回答 4

4

一年前,我在一个项目中第一次这样做了。我遇到了同样的问题,因为我尝试使用一个图标,并且有很多要更新的图标有时会冻结,所以我最终使用了HandlerAsyncTask. 这实际上是预设置活动中非常常见的模式。

这些是步骤:

  1. 创建一个加载对话框,将其发布到一个Handler对象。您可以使用类似这样的东西(显然,使用 Loading 对话框而不是Toast)。
  2. 开始你AsyncTask的计算。
  3. 每当计算的部分准备就绪时,您publishProgress. 为代码提供标志,以便准确告诉它需要构建 UI 的哪些部分。当您的加载对话框正在显示和旋转时,您将看到正在构建的 UI。
  4. 一切完成后,您关闭 中的对话框onPostExecute

以下是完全符合您描述的示例代码:

private void settingsAndPlaceTaskStart() {

    // loading dialog
    startLoading();

    new AsyncTask<Context, Integer, Void>() {
        @Override
        protected Void doInBackground(Context... context) {

            // check and prepare settings integrity
            Settings st = new Settings(context[0], false);
            st.checkPreferencesIntegrity();

            // set text for each view / paired object
            // this will take a long time
            do {
                // ... removed for clarity
                int code = ...;
                publishProgress(mObjects.getViewByCode(code));    
                while (mObjects.getNext());
            return null;
        }

        @Override
        protected void onPostExecute(Void void) {
            // finish stuff
        }

        @Override
        protected void onProgressUpdate(Integer... message) {
            prepareView(message[0]);
        }

    }.execute(getActivity());
}

在这里,当对话框中的进度在旋转时,加载不会出现任何卡顿。对话框一直停留在前台,直到onPostExecute. 您应该在任务结束后关闭其中的对话框。

于 2012-03-04T14:30:39.153 回答
2

让我确保我有这个权利:活动 A 是你的第一个,B 你的第二个。您需要 A 上的一个按钮来触发两件事:异步数据加载和 B 在 Activity 堆栈上的推送。这一切都很好。

在“我需要什么”中,您使用动词短语“在后台更新视图”。这是不可能的——您只能更新主 UI 线程上的视图。此外,一旦onPause()调用了 A(由 B 的推送触发),您确实应该认为 A 不可用于处理。你可以做的是在后台加载数据,而 B 做它的事情,然后 AonResume()可以适当地更新它的 UI。

如果我错了,并且您在 B 出现时让 A 做一些 UI 工作,那么对您有好处,但是如果您作为一个块的处理时间太长,那么我想您将不得不将它分解成更小的块并一点一点地安排它们,以免干扰用户对 B. 的体验。

更新

我不确定您将如何在 Activity X 的范围内完成使用 Activity Y 的 UI 资源,尤其是在 Y 尚未完成的情况下onCreate()d。我不知道是否可以在活动之间共享布局资源,尽管可能。

您在上面发布的链接得到了它 - 我认为有关使用Handler类的答案是您解决方案的一部分。另外,请阅读LooperDesigning for Responsiveness。我认为,简而言之,您将希望在主线程上实现一个处理程序,它允许您以 100-200 毫秒的小块更新 UI(如Responsiveness中所建议的那样),并以高粒度向该处理程序发送消息在后台线程上处理少量数据。例如,如果您正在更新 a ListView,您应该能够一次膨胀一行。同样,如果您将图像添加到GridView. 另外,考虑-加载资源,但不显示它们,这样您可以在时间紧迫时花更少的时间进行膨胀。

这是我目前的想法,但我将其标记为最喜欢的,因为我认为我必须在几周内做类似的事情。让我们了解什么对您有用。祝你好运!

于 2012-03-04T13:11:40.297 回答
2

A. 查看 android 市场应用程序(我不确定它如何在“播放”中工作) - 当您单击应用程序时 - 仅显示循环栏的空活动,并且在完全下载后显示任何其他数据。你想要同样的行为吗?如果是 - 以下将起作用:

您为 B 活动布局:

<RelativeLayout>
    <common_layout_of_your_view_that_covers_all_space />
    <layout_for_progress />
</RelativeLayout>

layout_for_progress 可以是任何布局,如果你想让它透明 - 放置特殊背景。

您的活动 B 不仅仅是为后台数据加载启动线程:

onCreate(...) {
    //call super
    //set content view

    new Thread(new Runnable() {
        public void run() {
            while(!downloadComplete) {
                //ask some portion of data
                ActivityB.this.runOnUIThread(new Runnable(){
                    public void run() {
                        //update your main view
                    }
                });
            }
            findViewById(R.id.layout_for_progress).setVisibility(View.GONE);
        }
    }).start();
}
于 2012-03-07T13:42:34.063 回答
1

您可以在 onCreate 中启动一个 asyncTask 并让它完成您的所有计算。同时你可以显示一个加载栏。然后在 onPostExecute 中,您可以使用收集的信息更新视图并关闭进度条

于 2012-02-29T19:21:26.700 回答