ListView 的 onProgressUpdate 方法中的 notifyDataSetChanged() 通过 AsyncTask 更新 listView
notifyDataSetChanged() in onProgressUpdate method for ListView to update the listView by AsyncTask
在我的应用程序中。有一个 ListView 并将数据填充到列表视图中抛出使用 ArrayList 的 ArrayAdapter。
我想通过 AsyncTask 将列表视图更新为 doInBackground 方法,所以我使用 onProgressUpdate 方法。在这里,我在适配器上执行 notifyDataSetChanged。
但是当编译器尝试执行代码时aAdapter.notifyDataSetChanged();
然后它抛出错误。
代码:-
private class StatisticsTask extends AsyncTask<String, Integer, Long> {
@Override
protected Long doInBackground(String... params) {
int count = 0;
while(count < dummyClass.getStatisticsClassList().size()){
try {
Thread.sleep(1000);
onProgressUpdate(count);
count++;
} catch (InterruptedException e) {
e.printStackTrace();
}
}
if (count == dummyClass.getStatisticsClassList().size()) {
statisticsTask.cancel(true);
}
return null;
}
@Override
protected void onProgressUpdate(Integer... values) {
updateProgress(values[0]);
}
}
public void updateProgress(Integer... values) {
aListStatisticsClass.add(dummyClass.getStatisticsClassList().get(values[0]));
aAdapterStatisticsClass.notifyDataSetChanged();
}
错误:-
03-04 15:33:49.757: E/AndroidRuntime(1778): FATAL EXCEPTION: AsyncTask #1
03-04 15:33:49.757: E/AndroidRuntime(1778): Process: com.example.elevateapp, PID: 1778
03-04 15:33:49.757: E/AndroidRuntime(1778): java.lang.RuntimeException: An error occured while executing doInBackground()
03-04 15:33:49.757: E/AndroidRuntime(1778): at android.os.AsyncTask.done(AsyncTask.java:300)
03-04 15:33:49.757: E/AndroidRuntime(1778): at java.util.concurrent.FutureTask.finishCompletion(FutureTask.java:355)
03-04 15:33:49.757: E/AndroidRuntime(1778): at java.util.concurrent.FutureTask.setException(FutureTask.java:222)
03-04 15:33:49.757: E/AndroidRuntime(1778): at java.util.concurrent.FutureTask.run(FutureTask.java:242)
03-04 15:33:49.757: E/AndroidRuntime(1778): at android.os.AsyncTask$SerialExecutor.run(AsyncTask.java:231)
03-04 15:33:49.757: E/AndroidRuntime(1778): at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
03-04 15:33:49.757: E/AndroidRuntime(1778): at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
03-04 15:33:49.757: E/AndroidRuntime(1778): at java.lang.Thread.run(Thread.java:841)
03-04 15:33:49.757: E/AndroidRuntime(1778): Caused by: android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
03-04 15:33:49.757: E/AndroidRuntime(1778): at android.view.ViewRootImpl.checkThread(ViewRootImpl.java:6024)
03-04 15:33:49.757: E/AndroidRuntime(1778): at android.view.ViewRootImpl.requestLayout(ViewRootImpl.java:820)
03-04 15:33:49.757: E/AndroidRuntime(1778): at android.view.View.requestLayout(View.java:16431)
03-04 15:33:49.757: E/AndroidRuntime(1778): at android.view.View.requestLayout(View.java:16431)
03-04 15:33:49.757: E/AndroidRuntime(1778): at android.view.View.requestLayout(View.java:16431)
03-04 15:33:49.757: E/AndroidRuntime(1778): at android.view.View.requestLayout(View.java:16431)
03-04 15:33:49.757: E/AndroidRuntime(1778): at android.widget.RelativeLayout.requestLayout(RelativeLayout.java:352)
03-04 15:33:49.757: E/AndroidRuntime(1778): at android.view.View.requestLayout(View.java:16431)
03-04 15:33:49.757: E/AndroidRuntime(1778): at android.widget.RelativeLayout.requestLayout(RelativeLayout.java:352)
03-04 15:33:49.757: E/AndroidRuntime(1778): at android.view.View.requestLayout(View.java:16431)
03-04 15:33:49.757: E/AndroidRuntime(1778): at android.widget.AbsListView.requestLayout(AbsListView.java:1916)
03-04 15:33:49.757: E/AndroidRuntime(1778): at android.widget.AdapterView$AdapterDataSetObserver.onChanged(AdapterView.java:814)
03-04 15:33:49.757: E/AndroidRuntime(1778): at android.widget.AbsListView$AdapterDataSetObserver.onChanged(AbsListView.java:6287)
03-04 15:33:49.757: E/AndroidRuntime(1778): at android.database.DataSetObservable.notifyChanged(DataSetObservable.java:37)
03-04 15:33:49.757: E/AndroidRuntime(1778): at android.widget.BaseAdapter.notifyDataSetChanged(BaseAdapter.java:50)
03-04 15:33:49.757: E/AndroidRuntime(1778): at android.widget.ArrayAdapter.notifyDataSetChanged(ArrayAdapter.java:286)
03-04 15:33:49.757: E/AndroidRuntime(1778): at com.example.elevateapp.MainActivity.updateProgress(MainActivity.java:94)
03-04 15:33:49.757: E/AndroidRuntime(1778): at com.example.elevateapp.MainActivity$StatisticsTask.onProgressUpdate(MainActivity.java:81)
03-04 15:33:49.757: E/AndroidRuntime(1778): at com.example.elevateapp.MainActivity$StatisticsTask.doInBackground(MainActivity.java:67)
03-04 15:33:49.757: E/AndroidRuntime(1778): at com.example.elevateapp.MainActivity$StatisticsTask.doInBackground(MainActivity.java:1)
03-04 15:33:49.757: E/AndroidRuntime(1778): at android.os.AsyncTask.call(AsyncTask.java:288)
03-04 15:33:49.757: E/AndroidRuntime(1778): at java.util.concurrent.FutureTask.run(FutureTask.java:237)
03-04 15:33:49.757: E/AndroidRuntime(1778): ... 4 more
notifyDataSetChanged()
以及所有其他 UI 相关的方法必须在主 (UI) 线程上执行。
另一方面,AsyncTask
创建并 运行 自己的线程,以便消除主线程的压力并让应用程序保持用户响应。
根据 documentation,onProgressUpdate(...)
方法是 UI 线程上的 运行,但您应该调用 publishProgress(...)
方法,并且您是直接从导致错误的非 UI 线程调用 onProgressUpdate(...)
。
要解决此问题,只需将 onProgressUpdate(count)
替换为 publishProgress(count)
即可。干杯 :D
在我的应用程序中。有一个 ListView 并将数据填充到列表视图中抛出使用 ArrayList 的 ArrayAdapter。
我想通过 AsyncTask 将列表视图更新为 doInBackground 方法,所以我使用 onProgressUpdate 方法。在这里,我在适配器上执行 notifyDataSetChanged。
但是当编译器尝试执行代码时aAdapter.notifyDataSetChanged();
然后它抛出错误。
代码:-
private class StatisticsTask extends AsyncTask<String, Integer, Long> {
@Override
protected Long doInBackground(String... params) {
int count = 0;
while(count < dummyClass.getStatisticsClassList().size()){
try {
Thread.sleep(1000);
onProgressUpdate(count);
count++;
} catch (InterruptedException e) {
e.printStackTrace();
}
}
if (count == dummyClass.getStatisticsClassList().size()) {
statisticsTask.cancel(true);
}
return null;
}
@Override
protected void onProgressUpdate(Integer... values) {
updateProgress(values[0]);
}
}
public void updateProgress(Integer... values) {
aListStatisticsClass.add(dummyClass.getStatisticsClassList().get(values[0]));
aAdapterStatisticsClass.notifyDataSetChanged();
}
错误:-
03-04 15:33:49.757: E/AndroidRuntime(1778): FATAL EXCEPTION: AsyncTask #1
03-04 15:33:49.757: E/AndroidRuntime(1778): Process: com.example.elevateapp, PID: 1778
03-04 15:33:49.757: E/AndroidRuntime(1778): java.lang.RuntimeException: An error occured while executing doInBackground()
03-04 15:33:49.757: E/AndroidRuntime(1778): at android.os.AsyncTask.done(AsyncTask.java:300)
03-04 15:33:49.757: E/AndroidRuntime(1778): at java.util.concurrent.FutureTask.finishCompletion(FutureTask.java:355)
03-04 15:33:49.757: E/AndroidRuntime(1778): at java.util.concurrent.FutureTask.setException(FutureTask.java:222)
03-04 15:33:49.757: E/AndroidRuntime(1778): at java.util.concurrent.FutureTask.run(FutureTask.java:242)
03-04 15:33:49.757: E/AndroidRuntime(1778): at android.os.AsyncTask$SerialExecutor.run(AsyncTask.java:231)
03-04 15:33:49.757: E/AndroidRuntime(1778): at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
03-04 15:33:49.757: E/AndroidRuntime(1778): at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
03-04 15:33:49.757: E/AndroidRuntime(1778): at java.lang.Thread.run(Thread.java:841)
03-04 15:33:49.757: E/AndroidRuntime(1778): Caused by: android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
03-04 15:33:49.757: E/AndroidRuntime(1778): at android.view.ViewRootImpl.checkThread(ViewRootImpl.java:6024)
03-04 15:33:49.757: E/AndroidRuntime(1778): at android.view.ViewRootImpl.requestLayout(ViewRootImpl.java:820)
03-04 15:33:49.757: E/AndroidRuntime(1778): at android.view.View.requestLayout(View.java:16431)
03-04 15:33:49.757: E/AndroidRuntime(1778): at android.view.View.requestLayout(View.java:16431)
03-04 15:33:49.757: E/AndroidRuntime(1778): at android.view.View.requestLayout(View.java:16431)
03-04 15:33:49.757: E/AndroidRuntime(1778): at android.view.View.requestLayout(View.java:16431)
03-04 15:33:49.757: E/AndroidRuntime(1778): at android.widget.RelativeLayout.requestLayout(RelativeLayout.java:352)
03-04 15:33:49.757: E/AndroidRuntime(1778): at android.view.View.requestLayout(View.java:16431)
03-04 15:33:49.757: E/AndroidRuntime(1778): at android.widget.RelativeLayout.requestLayout(RelativeLayout.java:352)
03-04 15:33:49.757: E/AndroidRuntime(1778): at android.view.View.requestLayout(View.java:16431)
03-04 15:33:49.757: E/AndroidRuntime(1778): at android.widget.AbsListView.requestLayout(AbsListView.java:1916)
03-04 15:33:49.757: E/AndroidRuntime(1778): at android.widget.AdapterView$AdapterDataSetObserver.onChanged(AdapterView.java:814)
03-04 15:33:49.757: E/AndroidRuntime(1778): at android.widget.AbsListView$AdapterDataSetObserver.onChanged(AbsListView.java:6287)
03-04 15:33:49.757: E/AndroidRuntime(1778): at android.database.DataSetObservable.notifyChanged(DataSetObservable.java:37)
03-04 15:33:49.757: E/AndroidRuntime(1778): at android.widget.BaseAdapter.notifyDataSetChanged(BaseAdapter.java:50)
03-04 15:33:49.757: E/AndroidRuntime(1778): at android.widget.ArrayAdapter.notifyDataSetChanged(ArrayAdapter.java:286)
03-04 15:33:49.757: E/AndroidRuntime(1778): at com.example.elevateapp.MainActivity.updateProgress(MainActivity.java:94)
03-04 15:33:49.757: E/AndroidRuntime(1778): at com.example.elevateapp.MainActivity$StatisticsTask.onProgressUpdate(MainActivity.java:81)
03-04 15:33:49.757: E/AndroidRuntime(1778): at com.example.elevateapp.MainActivity$StatisticsTask.doInBackground(MainActivity.java:67)
03-04 15:33:49.757: E/AndroidRuntime(1778): at com.example.elevateapp.MainActivity$StatisticsTask.doInBackground(MainActivity.java:1)
03-04 15:33:49.757: E/AndroidRuntime(1778): at android.os.AsyncTask.call(AsyncTask.java:288)
03-04 15:33:49.757: E/AndroidRuntime(1778): at java.util.concurrent.FutureTask.run(FutureTask.java:237)
03-04 15:33:49.757: E/AndroidRuntime(1778): ... 4 more
notifyDataSetChanged()
以及所有其他 UI 相关的方法必须在主 (UI) 线程上执行。
AsyncTask
创建并 运行 自己的线程,以便消除主线程的压力并让应用程序保持用户响应。
根据 documentation,onProgressUpdate(...)
方法是 UI 线程上的 运行,但您应该调用 publishProgress(...)
方法,并且您是直接从导致错误的非 UI 线程调用 onProgressUpdate(...)
。
要解决此问题,只需将 onProgressUpdate(count)
替换为 publishProgress(count)
即可。干杯 :D