我的活动中有一些片段。每个片段都调用一个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();
}
}
...
}
为什么在Runnable中调用传递给Handler工作? AsyncTask不应该在后台运行,因此UI应该在它完成之前绘制吗?
感谢您的帮助。
更新:添加更多信息。 这是DataLoaderTask()的构造函数:
public DataLoaderTask(Object object) {
mObject = object;
mListeners = new ArrayList<OnUpdateListener>();
}
DataLoaderTask NOT 覆盖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();
}
}
}
}
答案 0 :(得分:0)
正如您所提到的,任何资源密集型或需要花费一些时间的事情都应该在 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中创建一个Thread,如果你不是以某种方式管理那个线程,这是一个不好的做法。