我已经阅读了所有与此有关的问题。而且情况也不一样。相信我。

我知道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

            }
    }

}


如你看到的:


视图的触摸位于onPostExecute中
如果用户取消退出屏幕的任务,我会使用“ isCancelled”
与“ isFinishing”相同


甚至现在,当我尝试更改视图的某些内容时(在示例中为简单文本),该行中仍然出现错误“只有创建视图层次结构的原始线程才能触摸其视图”。

如果我在尝试获取API结果时取消(例如按回去)就可以了,并且可以正常工作。
如果我恰好在API结果到达时取消了它,并且在它开始更改之前,它崩溃了(我在onPostExecute中插入了“ sleep”以完成此测试)。

错误代码在第112行中,即“ findViewById(R.id.panelViews).removeAllViews();”。如上所述:

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)

最佳答案

查看调用堆栈,以下调用表明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

10-08 03:16