繁体   English   中英

在AsyncTask完成之前不会绘制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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM