不能碰从onPostExecute的AsyncTask的意见 [英] Can't touch views from onPostExecute's AsyncTask

查看:174
本文介绍了不能碰从onPostExecute的AsyncTask的意见的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已经读到这一切的问题。它是不一样的情况。相信我。

我认识一个AsyncTask的doInBackground功能有自己的线程,你必须接触的观点在preExecute和onPostExecute。

此外,我使用isCancelled和isFinishing真正确保任务是活着的。并与所有这些东西,应用程序仍然会崩溃。

这是code:

 公共类MainActivity {    私人活动活动;    @覆盖
    保护无效的onCreate(捆绑savedInstanceState){
        super.onCreate(savedInstanceState);
        的setContentView(R.layout.Main);
        活性=这一点;
        新MyTask(活性).execute();
    }
    私有类MyTask扩展的AsyncTask<太虚,太虚,用户[]> {            // ...            @覆盖
            在preExecute保护无效(){
            }            @覆盖
            保护用户[] doInBackground(字符串... PARAMS){
                    // API调用
                    //返回结果
            }            @覆盖
            保护无效onPostExecute(用户[]用户){                    如果(isCancelled()|| isFinishing())回报;                    findViewById(R.id.panelViews).removeAllViews();
                    findViewById(R.id.element).setText(东西);                    // ... 更多            }
    }}

正如你所看到的:


  • 视图的接触是在onPostExecute

  • 我用的是isCancelled万一用户取消退出屏幕上的任务

  • 与isFinishing
  • 同样

和即使是现在,我得到的错误在该行的时候我试图改变视图的东西(在本例中一个简单的文本)只有创建一个视图层次可以触摸其观点原来的线程

如果我取消(pressing回来为例)时,它试图让API的结果是确定的,和它的作品。
如果我取消什么时候该API结果出来,并开始改变以前的事情,它崩溃(我插在onPostExecute休眠来完成这项测试)。

错误code是在线路112,即findViewById(R.id.panelViews).removeAllViews();上述:

  android.view.ViewRoot $ CalledFromWrongThreadException:只有创建视图层次可以触摸其观点原来的线程。
    在android.view.ViewRoot.checkThread(ViewRoot.java:2988)
    在android.view.ViewRoot.requestLayout(ViewRoot.java:648)
    在android.view.View.requestLayout(View.java:8416)
    在android.view.View.requestLayout(View.java:8416)
    在android.view.View.requestLayout(View.java:8416)
    在android.view.View.requestLayout(View.java:8416)
    在android.view.View.requestLayout(View.java:8416)
    在android.widget.ScrollView.requestLayout(ScrollView.java:1303)
    在android.view.View.requestLayout(View.java:8416)
    在android.view.View.requestLayout(View.java:8416)
    在android.view.ViewGroup.removeAllViews(ViewGroup.java:2354)
    在com.test.activities.MainActivity $ MyTask.onPostExecute(MainActivity.java:112)
    在com.test.activities.MainActivity $ MyTask.onPostExecute(MainActivity.java:1)
    在android.os.AsyncTask.finish(AsyncTask.java:417)
    在android.os.AsyncTask.access $ 300(AsyncTask.java:127)
    在android.os.AsyncTask $ InternalHandler.handleMessage(AsyncTask.java:429)
    在android.os.Handler.dispatchMessage(Handler.java:99)
    在android.os.Looper.loop(Looper.java:130)
    在android.os.HandlerThread.run(HandlerThread.java:60)


解决方案

望着调用堆栈,下面的调用表明AsyncTask的类装载在非UI线程。

在android.os.HandlerThread.run(HandlerThread.java:60)

其中的线程规则 的AsyncTask参考文档是:


  

在AsyncTask的类必须在UI线程加载。这个做完了
  自动JELLY_BEAN的。


下面是与此相关的问题

问题的解决方法是,手动加载的AsyncTask 应用程序的onCreate 方法。这确保了类被加载在主线程,任何应用程序组件使用它了。

 公共类MyApplication的扩展应用{    @覆盖
    公共无效的onCreate(){        尝试{
            的Class.forName(android.os.AsyncTask);
        }赶上(ClassNotFoundException的E){        }        super.onCreate();
    }
}

请记住要指定所有MyApplication AndroidManifest 文件。

I have already read all questions about this. And it's not the same case. Believe me.

I know an AsyncTask doInBackground function has his own thread, and you must touch the view in onPreExecute and onPostExecute.

Besides, I'm using isCancelled and isFinishing to really be sure the task is alive. And with all these things, the app is still crashing.

This is the code:

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

            }
    }

}

As you can see:

  • the touch of the view is in the onPostExecute
  • I use the "isCancelled" in case the user cancels the task exiting the screen
  • The same with "isFinishing"

And even now I'm getting the error "Only the original thread that created a view hierarchy can touch its views" in the line when I try to change something of the view (in the example a simple text)

If I cancel (pressing back for example) when it's trying to get the API results is OK, and it works. If I cancel exactly when the API results come, and before it starts changing things, it crashes (I inserted a "sleep" in the onPostExecute to accomplish this test).

The error code is in line 112, that is the "findViewById(R.id.panelViews).removeAllViews();" described above:

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)

解决方案

Looking at the call stack, following call indicates that AsyncTask class was loaded on non-UI thread.

at android.os.HandlerThread.run(HandlerThread.java:60)

One of the Threading Rules mentioned in AsyncTask reference documentation is:

The AsyncTask class must be loaded on the UI thread. This is done automatically as of JELLY_BEAN.

Here is a bug related to this issue.

One of the solution is, load the AsyncTask class manually in Application onCreate method. This ensures the class gets loaded on main thread, before any application components uses it.

public class MyApplication extends Application {

    @Override
    public void onCreate() {

        try {
            Class.forName("android.os.AsyncTask");
        } catch (ClassNotFoundException e) {

        }

        super.onCreate();
    }
}

Remember to specify MyApplication in AndroidManifest file.

这篇关于不能碰从onPostExecute的AsyncTask的意见的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆