我已经阅读了有关此内容的所有问题。而且情况并非如此。相信我。
我知道AsyncTask doInBackground函数有自己的线程,你必须触摸onPreExecute和onPostExecute中的视图。
此外,我使用isCancelled和isFinishing来确保任务是活的。所有这些东西,应用程序仍在崩溃。
这是代码:
public class MainActivity {
private Activity activity;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.Main);
activity = this;
new MyTask(activity).execute();
}
private class MyTask extends AsyncTask<Void, Void, User[]> {
// ...
@Override
protected void onPreExecute() {
}
@Override
protected User[] doInBackground(String... params) {
// Api call
// return results
}
@Override
protected void onPostExecute(User[] users) {
if (isCancelled() || isFinishing()) return;
findViewById(R.id.panelViews).removeAllViews();
findViewById(R.id.element).setText("something");
// ... more
}
}
}
如你所见:
即使现在我收到错误&#34;只有创建视图层次结构的原始线程才能触及其视图&#34;在我尝试更改视图的某些内容时(在示例中为简单文本)
如果我在尝试获取API结果时取消(例如后退),则可以正常工作。 如果我确切地取消API结果的时间,并且在它开始更改之前,它会崩溃(我在onPostExecute中插入一个&#34; sleep&#34;来完成此测试)。
错误代码在第112行,即&#34; findViewById(R.id.panelViews).removeAllViews();&#34;如上所述:
android.view.ViewRoot$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
at android.view.ViewRoot.checkThread(ViewRoot.java:2988)
at android.view.ViewRoot.requestLayout(ViewRoot.java:648)
at android.view.View.requestLayout(View.java:8416)
at android.view.View.requestLayout(View.java:8416)
at android.view.View.requestLayout(View.java:8416)
at android.view.View.requestLayout(View.java:8416)
at android.view.View.requestLayout(View.java:8416)
at android.widget.ScrollView.requestLayout(ScrollView.java:1303)
at android.view.View.requestLayout(View.java:8416)
at android.view.View.requestLayout(View.java:8416)
at android.view.ViewGroup.removeAllViews(ViewGroup.java:2354)
at com.test.activities.MainActivity$MyTask.onPostExecute(MainActivity.java:112)
at com.test.activities.MainActivity$MyTask.onPostExecute(MainActivity.java:1)
at android.os.AsyncTask.finish(AsyncTask.java:417)
at android.os.AsyncTask.access$300(AsyncTask.java:127)
at android.os.AsyncTask$InternalHandler.handleMessage(AsyncTask.java:429)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:130)
at android.os.HandlerThread.run(HandlerThread.java:60)
答案 0 :(得分:2)
查看调用堆栈,以下调用表明AsyncTask类已加载到非UI线程上。
at android.os.HandlerThread.run(HandlerThread.java:60)
AsyncTask reference documentation中提到的线程规则之一是:
必须在UI线程上加载AsyncTask类。这个完成了 自JELLY_BEAN起。
以下是与此issue相关的错误。
其中一个解决方案是,在AsyncTask
方法中手动加载Application onCreate
类。这可确保在任何应用程序组件使用它之前,类在主线程上加载。
public class MyApplication extends Application {
@Override
public void onCreate() {
try {
Class.forName("android.os.AsyncTask");
} catch (ClassNotFoundException e) {
}
super.onCreate();
}
}
请务必在MyApplication
文件中指定AndroidManifest
。
答案 1 :(得分:2)
this answer中的解决方案应该强制代码在ui线程上运行。它使用Activity#runOnUiThread(Runnable)
函数。你的代码最终会像这样:
@Override
protected void onPostExecute(User[] users) {
if (isCancelled() || isFinishing()) return;
runOnUiThread(new Runnable() {
@Override
public void run() {
findViewById(R.id.panelViews).removeAllViews();
findViewById(R.id.element).setText("something");
// ... more
}
});
}
答案 2 :(得分:1)
从后台线程启动AsyncTask
时会发生这种情况。 onPreExecute
和onPostExecute
不会自动在主线程上运行,但实际上是AsyncTask
启动的线程。
换句话说,如果您在execute
上调用AsyncTask
时已经在后台线程中,那么同一个线程就是调用onPostExecute
方法的意思那个例外。
答案 3 :(得分:0)
试试这个,这应该解决你的问题,在runOnUiThread()中执行你的任务
@Override
protected void onPostExecute(User[] users) {
runOnUiThread(new Runnable() {
public void run() {
if (isCancelled() || isFinishing()) return;
findViewById(R.id.panelViews).removeAllViews();
findViewById(R.id.element).setText("something");
}//run
}//runOnUiThread
}//onPostExecute