我的应用流程与Android标准不同:
标准:按下活动A上的按钮,在加载数据和构建活动B的视图时显示此活动的加载,然后才显示下一个活动。 (在活动A上调用AsyncTask,完成发送数据和调用活动B后)
我需要的内容:按活动A上的按钮,转到活动B,在显示加载时,更新加载后面的活动B视图。 (从活动A移动到B,并在显示加载时调用AsyncTask。当AsyncTask完成时,在加载前面时更新视图,从而显示视图更新过程)
问题:这会使加载图标停止..有时会显示无响应的对话框(由于长时间操作)并使用UI线程更改正在构建的视图。
我已经阅读了有关同一事项的一些问题:Android: how to update UI dynamically?
但没有人提供通用答案。
如果您的回答是“这不是推荐的行为”我会同意......但这些是要求,所以我真的很感激一些帮助:-D
答案 0 :(得分:4)
我在一年前的一个项目中首先做到了这一点。我遇到了同样的问题,因为我试图使用一个图标,并且有很多要更新的图标有时会冻结,所以我最终使用Handler
与AsyncTask
配对。它实际上是预先设置活动中非常常见的模式。
这些是步骤:
Handler
对象。您可以使用类似this的内容(显然是加载对话框而不是Toast
)。AsyncTask
进行计算。publishProgress
。为代码提供标志,以便准确地告诉它需要构建UI的哪些部分。在加载对话框显示和旋转时,您将看到正在构建的UI。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
。在任务结束后,你应该忽略那里的对话框。
答案 1 :(得分:2)
让我确保我有这个权利:活动A是你的第一个,B是你的第二个。您希望A上的按钮触发两件事:异步数据加载和活动堆栈上的B推送。这一切都很好。
In&#34; 我需要什么&#34;你使用动词短语&#34;在后台更新视图&#34;。这是不可能的 - 您只能更新主UI线程上的视图。此外,一旦调用A onPause()
(由B推动触发),您真的应该考虑A不可用于处理。你可以做的是在后台加载数据,而B做它的事情,然后在onResume()
中的A可以适当地更新它的UI。
如果我错了,并且你在A出现时有A做一些UI工作,那么对你很好,但是如果你的处理时间过长,那么我想你会这样做必须将其分解成更小的块并逐步安排它们,以免中断用户对B的体验。
更新
我不确定在Activity X的范围内如何使用Activity Y的UI资源,尤其是如果Y尚未onCreate()d
。我不知道是否可以在活动之间共享布局资源,尽管它可能是。
您在上面发布的链接指向它 - 我认为使用Handler类的答案是您解决方案的一部分。另请阅读Looper和Designing for Responsiveness。我想,简而言之,您需要在主线程上实现一个Handler,它允许您以100-200ms的小块更新UI(如响应性中所述),并且具有高粒度,当您在后台线程上处理少量数据时,将消息发送到该Handler。例如,如果您要更新ListView
,则应该能够一次扩充一行。同样,如果您要将图片添加到GridView
。另外,考虑 pre - 加载资源,但不要显示它们,以便在时间短的时候花更少的时间进行充气。
就目前我的想法而言,这是我的最爱,因为我认为我必须在几周内做一些类似的事情。让我们发布适合您的内容。祝你好运!
答案 2 :(得分:2)
一个。看看Android市场应用程序(我不确定它在“播放”中是如何工作的) - 当你点击app时 - 显示只有循环条的空活动,并且在完全下载后显示任何其他数据。 你想要同样的行为吗?如果是 - 以下内容将起作用:
您为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();
}
答案 3 :(得分:1)
您可以在onCreate中启动asyncTask并让它完成所有计算。同时你可以显示一个加载栏。然后在onPostExecute中,您可以使用收集的信息更新视图并关闭进度条