Can't create handler inside thread that has not called Looper.prepare() with AsyncTask

流过昼夜 提交于 2020-01-11 12:18:32

问题


I am trying to use the AsyncTask class on android but I have a problem.

Here is my code:

 public void CheckIfUserIsLogedIn ()
{
    int userPresence = localDatabase.CheckUserPresence();
    if (userPresence == 0) 
    {
        setContentView(R.layout.main);
        new checkCountryAsync().execute();
    }
    else
    {
        setContentView(R.layout.userlogedon);
    }
}  

class checkCountryAsync extends AsyncTask<String, String, String> {

    @Override
    protected void onPreExecute() {
        super.onPreExecute(); 
    }
    @Override
    protected String doInBackground(String... aurl) {
        int countryPresence = localDatabase.CheckCountryPresence();
        if (countryPresence == 0) 
        {
            CountryTable country = new CountryTable() ;
            country.EnterCountry();
        }
        return null;
    }
}

I don't know where I am doing something wrong. The method CheckCountryPresence() from the LocalDatabase class is only making a query and returns a result.

Thank you.

Edit: Here is the logCat:

02-20 08:41:25.804: W/dalvikvm(26458): threadid=10: thread exiting with uncaught exception (group=0x4001d5a0)
02-20 08:41:25.834: E/AndroidRuntime(26458): FATAL EXCEPTION: AsyncTask #1
02-20 08:41:25.834: E/AndroidRuntime(26458): java.lang.RuntimeException: An error occured while executing doInBackground()
02-20 08:41:25.834: E/AndroidRuntime(26458):    at android.os.AsyncTask$3.done(AsyncTask.java:200)
02-20 08:41:25.834: E/AndroidRuntime(26458):    at java.util.concurrent.FutureTask$Sync.innerSetException(FutureTask.java:274)
02-20 08:41:25.834: E/AndroidRuntime(26458):    at java.util.concurrent.FutureTask.setException(FutureTask.java:125)
02-20 08:41:25.834: E/AndroidRuntime(26458):    at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:308)
02-20 08:41:25.834: E/AndroidRuntime(26458):    at java.util.concurrent.FutureTask.run(FutureTask.java:138)
02-20 08:41:25.834: E/AndroidRuntime(26458):    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1088)
02-20 08:41:25.834: E/AndroidRuntime(26458):    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:581)
02-20 08:41:25.834: E/AndroidRuntime(26458):    at java.lang.Thread.run(Thread.java:1027)
02-20 08:41:25.834: E/AndroidRuntime(26458): Caused by: java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
02-20 08:41:25.834: E/AndroidRuntime(26458):    at android.os.Handler.<init>(Handler.java:121)
02-20 08:41:25.834: E/AndroidRuntime(26458):    at android.app.Activity.<init>(Activity.java:717)
02-20 08:41:25.834: E/AndroidRuntime(26458):    at milos.mdpi.CountryTable.<init>(CountryTable.java:5)
02-20 08:41:25.834: E/AndroidRuntime(26458):    at milos.mdpi.MDPIActivity$checkCountryAsync.doInBackground(MDPIActivity.java:367)
02-20 08:41:25.834: E/AndroidRuntime(26458):    at milos.mdpi.MDPIActivity$checkCountryAsync.doInBackground(MDPIActivity.java:1)
02-20 08:41:25.834: E/AndroidRuntime(26458):    at android.os.AsyncTask$2.call(AsyncTask.java:185)
02-20 08:41:25.834: E/AndroidRuntime(26458):    at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:306)
02-20 08:41:25.834: E/AndroidRuntime(26458):    ... 4 more

回答1:


Seems you are doing some stuff to Update your UI from a Non-UI thread. So, you should put your stuff to update the UI inside runOnUiThread() so that it executes the stuff on your UI hread itself.

UPDATE:

Just try to put your stuff for getting CheckCountryPresence(); inside onPreExecute(). So your edited class should be like,

class checkCountryAsync extends AsyncTask<String, String, String> {

    int countryPresence = 0;
    @Override
    protected void onPreExecute() {
       countryPresence = localDatabase.CheckCountryPresence();
    }
    @Override
    protected String doInBackground(String... aurl) {

        Activity_name.this.runOnUiThread(new Runnable() {

        @Override
        public void run() {
            if (countryPresence == 0) 
            {
              CountryTable country = new CountryTable() ;
              country.EnterCountry();
            }
        }
    });
        return null;
    }
}



回答2:


Has your CountryTable class any interaction with the UI activity/class? Even fetching new rows for your adapter object? If yes, you cannot update your activity from outside the activity itself.

Fortunately you can overcome this pretty easily once you figure out the solution ;)

step 1:

Define an interface, like CheckCountryCallback with a single method called onCheckCountryFinished(String taskResult);

Step 2: let the activity which call your asynctask implement this interface and its method.

Step 3: define a constructor for your asyncTask with a single parameter of type CheckCountryCallback

Step 4: override onPostExecute of your AT, and simply write mCaller.onCheckCountryFinished(result).

This is not enough sadly because you'd still be updating the ui from another thread but we're getting close!

In your implemented onCheckCountryFinished you should redirect the call to a handler you've to define in your activity. Send a message to that handler and you can update the UI (or the adapter or whatnot) from the handle message method of the handler.

Handler example:

private static final int UPDATE = 2;
private Handler handler = new Handler() {

    public void handleMessage(Message msg) {
        if (msg.what == UPDATE) {
               //do something with m.obj
               myAdapter.notifyDataSetChanged();
        }
    }
};

callback example

public void onCheckCountryFinished(String result){
    Message m = Message.obtain();
    m.what = UPDATE;
    m.obj = result;
    handler.sendMessage(m);
}



回答3:


You are not passing your AsyncTask anything so make the parameters of AsyncTask all Void like this AsyncTask<Void, Void, Void> then change doInBackground to this protected Void doInBackground(Void... voids). Also, get rid of the onPreExecute method since you are not even using it.

Also, it is unclear with you code provided, but CheckIfUserIsLogedIn needs to be called from the UI thread. AsyncTask is really only meant to be run off of the UI thread.




回答4:


one of the problem that i faced, simpleCursorAdapter also returns same error of looper when called from thread. So to remove that error, inside thread

ActivityName.this.runOnUiThread(new Runnable() {
 public void run() {
   String[] FROM = {/*your data here*/};
int[] TO = { /*your data here*/ };
adapter = new SimpleCursorAdapter(ActivityName.this, R.layout.row, cursor, FROM, TO);   
listTimeline.setAdapter(adapter); //your own code here.
}
});


来源:https://stackoverflow.com/questions/9357513/cant-create-handler-inside-thread-that-has-not-called-looper-prepare-with-asy

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!