在AsyncTask完成之前,不会绘制UI

时间:2014-07-23 23:46:08

标签: java android android-fragments android-asynctask android-handler

我的活动中有一些片段。每个片段都调用一个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();
        }
    }
}
}

1 个答案:

答案 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,如果你不是以某种方式管理那个线程,这是一个不好的做法。