AsyncTask doInBackground调notifyDataSetChanged异常,onPostExecute正常
为什么AsyncTask的doInBackground调用notifyDataSetChanged会异常?
嗨,这个问题我太熟了!本质上就是Android的UI线程规则在搞事情:
Android明确规定:所有更新UI的操作必须在主线程(也就是UI线程)中执行,任何后台线程直接操作UI都会抛出异常。而AsyncTask的doInBackground()方法,恰恰是运行在后台工作线程里的——它的设计目的就是让你在这里做耗时的IO操作、数据计算,完全不碰UI相关的代码。
那为什么onPostExecute()调用就没问题?因为这个方法是AsyncTask专门设计的「后台任务完成后回到主线程的回调」,它本身就运行在主线程里,所以调用notifyDataSetChanged()(这是更新列表UI的核心方法)完全符合规则,自然不会报错。
给你几个靠谱的解决方案:
方案1:标准AsyncTask用法(推荐)
把数据处理逻辑放在doInBackground()里,处理完后把数据传递给onPostExecute(),再在这个主线程回调里更新Adapter并通知UI:
protected String doInBackground(Void... voids) { String results = ""; if (session != null) { Folder root = session.getRootFolder(); ItemIterable<CmisObject> children = root.getChildren(); map_id = new HashMap(); map_name = new HashMap(); int count = 0; for (CmisObject o : children) { // 这里安心处理你的数据,不用碰UI map_id.put(count, o.getId()); map_name.put(count, o.getName()); count++; } } return results; } @Override protected void onPostExecute(String result) { super.onPostExecute(result); // 主线程里更新Adapter数据 yourAdapter.setData(map_id, map_name); // 安全触发UI更新 yourAdapter.notifyDataSetChanged(); }
方案2:如果需要中途更新UI(比如进度)
要是你想在后台任务执行过程中就更新UI(比如每加载一个item就刷新列表),可以用AsyncTask的publishProgress() + onProgressUpdate()组合,后者同样运行在主线程:
protected String doInBackground(Void... voids) { String results = ""; if (session != null) { Folder root = session.getRootFolder(); ItemIterable<CmisObject> children = root.getChildren(); map_id = new HashMap(); map_name = new HashMap(); int count = 0; for (CmisObject o : children) { map_id.put(count, o.getId()); map_name.put(count, o.getName()); // 发布进度,把当前状态传给主线程 publishProgress(count); count++; } } return results; } @Override protected void onProgressUpdate(Integer... values) { super.onProgressUpdate(values); // 主线程里更新列表 yourAdapter.updateData(map_id, map_name); yourAdapter.notifyDataSetChanged(); }
方案3:临时救急(不推荐)
如果实在要在doInBackground()里调用UI方法,可以用runOnUiThread()把代码包裹起来(仅限Activity环境),但这种方法破坏了AsyncTask的设计逻辑,尽量少用:
// 在doInBackground的某个位置 runOnUiThread(new Runnable() { @Override public void run() { yourAdapter.notifyDataSetChanged(); } });
核心总结
记住这几个AsyncTask方法的线程归属:
doInBackground():后台线程 → 只做耗时操作,别碰UIonPostExecute()/onProgressUpdate():主线程 → 专门处理UI更新
这样就能完美避开跨线程操作UI的异常啦!
内容的提问来源于stack exchange,提问作者Ashish yadav
相关产品推荐
相关产品推荐

