[英]Display ProgressDialog until AsyncTask finishes, then update UI
[英]UI is not drawn until AsyncTask completes
我的活动中有一些碎片。 每个片段都调用一个AsyncTask,该异步对象通过onCreate()
方法从本地数据库加载数据,如下所示:
@Override
public void onCreate(Bundle savedInstance) {
super.onCreate(savedInstance);
(new DataLoaderTask()).execute();
...
}
我有三个片段可以做到这一点。 这样做时,片段直到DataLoaderTask完成才完成其UI的绘制。 为什么是这样? 我尝试将呼叫更改为此,但不再遇到问题:
@Override
public void onCreate(Bundle savedInstance) {
super.onCreate(savedInstance);
(new Handler()).postDelayed(new Runnable() {
@Override
public void run() {
(new DataLoaderTask()).execute();
}
}
...
}
为什么在传递给Handler的Runnable内部进行调用有效? AsyncTask是否不应该在后台运行,因此应该在完成之前绘制UI?
谢谢你的帮助。
更新:添加更多信息。 这是DataLoaderTask()的构造函数:
public DataLoaderTask(Object object) {
mObject = object;
mListeners = new ArrayList<OnUpdateListener>();
}
DataLoaderTask 不会覆盖onPreExecute()
方法。 它的确覆盖了onPostExecute()
方法。 我已经为我的onPostExecute()
方法计时,大约需要2毫秒。 它所做的就是更新一些对象并在提供的任何侦听器上调用方法。
更新:这是完整的onPostExecute()
方法:
@Override
protected void onPostExecute(Object result) {
synchronized(mDataManagerLock) {
if (Config.isLogging()) {
Log.i(TAG, "*** *** *** *** Finished syncing with database (onPostExecute()).");
}
if (mObject instanceof Playlist && result instanceof Playlist) {
if (((Playlist) result).isMyPlaylist()) {
synchronized(mTmpMyPlaylist) {
if (mTmpMyPlaylist != null && !mTmpMyPlaylist.isEmpty()) {
((Playlist) result).addPlaylistActions(mTmpMyPlaylist.getPlaylistActions());
mTmpMyPlaylist.clear();
}
}
}
if (mergeLocalPlaylistChanges((Playlist) result) && Config.isLogging()) {
Log.i(TAG, "Local playlist changes during sync merged.");
} else if (Config.isLogging()) {
Log.i(TAG, "No local playlist changes were made during sync.");
}
((Playlist) mObject).replace((Playlist) result);
putPlaylist((Playlist) mObject, null /*newClips*/);
} else if (mObject instanceof Catalog && result instanceof Catalog) {
((Catalog) mObject).replace((Catalog) result);
putCatalog((Catalog) mObject, null);
} else if (mObject instanceof NotificationsList) {
// We've synced NotificationsList in Memory with Disk.
mNotificationsList.setLastNetworkFetchTime(mApp.getNotificationsNetworkFetchTime());
} else if (mObject instanceof SetsList) {
// We've synced SetsList in Memory with Disk.
mSetsList.setLastNetworkFetchTime(mApp.getExploreNetworkFetchTime());
}
if (Config.isLogging()) {
Log.i(TAG, mObject.getClass().getSimpleName() + " after sync with database: " + mObject);
}
}
if (Config.isLogging()) {
Log.i(TAG, "Finished syncing in memory object/list with database.\n *** Time taken: " + (System.currentTimeMillis() - mStartTime)/1000 + " milliseconds.");
}
if (mListeners != null) {
for (OnUpdateListener listener : mListeners) {
if (listener != null) {
listener.onUpdated();
}
}
}
}
正如您提到的,任何资源密集型或需要花费一些时间的事情都应该在doInBackground中完成。 这包括不运行任何可能使其无法在onPostExecute中运行的东西,因为我们知道它在主线程中运行(有一些例外),并可能导致类似这样的意外行为。
我已经进行了一些测试,显然主线程由onPostExecute保留 。 我创建了一个虚拟任务:
class MyAsyncTask extends AsyncTask<Void, Void, Void> {
@Override
protected Void doInBackground(Void... params) {
return null;
}
@Override
protected void onPostExecute(Void result) {
try {
Log.i(TAG, "I'm holding the UI back.");
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
super.onPostExecute(result);
}
}
即使您发布到处理程序,它也会接管任务并保留任务。 直到我将其添加到线程中,UI才准时打印:
@Override
protected void onPostExecute(Void result) {
new Thread(new Runnable() {
@Override
public void run() {
try {
Log.i(TAG, "I'm NOT holding the UI back.");
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
super.onPostExecute(result);
}
这个故事的寓意是, 不要做任何可能占据主线的事情。 我并不是说您也应该在onPostExecute中创建一个线程,如果您不以某种方式管理该线程,那将不是一个坏习惯。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.