2

I have the following code but I get an error on this line “userSpinner.setAdapter(adapter);”

 private class Task extends AsyncTask<Void, Void, Void> 
 { 
     protected void onPreExecute() {            
     showDialog(DIALOG_TASKING); 
     } 
     protected Void doInBackground(Void... JSONArray) { 

        try
        {
        HttpGet request = new HttpGet(SERVICE_URI + "/GetBusNames");
        request.setHeader("Accept", "application/json");
        request.setHeader("Content-type", "application/json");

        DefaultHttpClient httpClient = new DefaultHttpClient();
        HttpResponse response = httpClient.execute(request);
        HttpEntity responseEntity = response.getEntity();

        char[] buffer = new char[(int)responseEntity.getContentLength()];
        InputStream stream = responseEntity.getContent();       
        InputStreamReader reader = new InputStreamReader(stream);
        reader.read(buffer);
        stream.close();

        JSONObject jsonResponse = new JSONObject(new String(buffer));
        JSONArray myUsers = jsonResponse.getJSONArray("GetBusNamesResult");

        ArrayAdapter<String> adapter = new ArrayAdapter<String>(RealestateActivity.this, android.R.layout.simple_spinner_item);
        adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);

        adapter.add("Select a Buseness...");                
        for (int i = 0; i < myUsers.length(); ++i)
        {
            adapter.add(myUsers.getString(i));
            adapter.add(myUsers.getJSONObject(i).getString("BusName"));
        }

            userSpinner.setAdapter(adapter); // I get an error here if I wrap these two lines in /*...*/ the whole thing loads as expected but the spinner is empty
            userSpinner.setOnItemSelectedListener(new MyOnItemSelectedListener());

        }
        catch (Exception e) 
        {       
            e.printStackTrace();
            displayExceptionMessage(e.getMessage());
        }
        return null;
    }

    protected void onPostExecute(Void unused) {
        dismissDialog(DIALOG_TASKING);              
    } 

}

The following is the Stack Trace produced,

11-07 19:54:35.300: ERROR/AndroidRuntime(8741): FATAL EXCEPTION: AsyncTask #1
11-07 19:54:35.300: ERROR/AndroidRuntime(8741): java.lang.RuntimeException: An error occured while executing doInBackground()
11-07 19:54:35.300: ERROR/AndroidRuntime(8741):     at android.os.AsyncTask$3.done(AsyncTask.java:200)
11-07 19:54:35.300: ERROR/AndroidRuntime(8741):     at java.util.concurrent.FutureTask$Sync.innerSetException(FutureTask.java:273)
11-07 19:54:35.300: ERROR/AndroidRuntime(8741):     at java.util.concurrent.FutureTask.setException(FutureTask.java:124)
11-07 19:54:35.300: ERROR/AndroidRuntime(8741):     at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:307)
11-07 19:54:35.300: ERROR/AndroidRuntime(8741):     at java.util.concurrent.FutureTask.run(FutureTask.java:137)
11-07 19:54:35.300: ERROR/AndroidRuntime(8741):     at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1068)
11-07 19:54:35.300: ERROR/AndroidRuntime(8741):     at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:561)
11-07 19:54:35.300: ERROR/AndroidRuntime(8741):     at java.lang.Thread.run(Thread.java:1096)
11-07 19:54:35.300: ERROR/AndroidRuntime(8741): Caused by: java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
11-07 19:54:35.300: ERROR/AndroidRuntime(8741):     at android.os.Handler.<init>(Handler.java:121)
11-07 19:54:35.300: ERROR/AndroidRuntime(8741):     at android.widget.Toast.<init>(Toast.java:68)
11-07 19:54:35.300: ERROR/AndroidRuntime(8741):     at android.widget.Toast.makeText(Toast.java:231)
11-07 19:54:35.300: ERROR/AndroidRuntime(8741):     at com.fnesse.realestate.RealestateActivity.displayExceptionMessage(RealestateActivity.java:271)
11-07 19:54:35.300: ERROR/AndroidRuntime(8741):     at com.fnesse.realestate.RealestateActivity$Task.doInBackground(RealestateActivity.java:131)
11-07 19:54:35.300: ERROR/AndroidRuntime(8741):     at com.fnesse.realestate.RealestateActivity$Task.doInBackground(RealestateActivity.java:1)
11-07 19:54:35.300: ERROR/AndroidRuntime(8741):     at android.os.AsyncTask$2.call(AsyncTask.java:185)
11-07 19:54:35.300: ERROR/AndroidRuntime(8741):     at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:305)
11-07 19:54:35.300: ERROR/AndroidRuntime(8741):     ... 4 more
11-07 19:56:22.714: ERROR/PowerManagerService(2464): CurLock p:3 mPS:1
11-07 20:06:26.577: ERROR/libnetutils(2464): dhcp start cmd 11 : [dhcpcd:-ABK] 
11-07 20:06:27.054: ERROR/HierarchicalStateMachine(2464): TetherMaster - unhandledMessage: msg.what=3

The code works in its own method but not in the AsyncTask.

Any idea’s.

Cheers,

Mike.

4 Answers4

6

You can't perform Display/Update UI inside the doInBackground() method, instead either you can perform by implement runOnUIThread() method or write display/Update statement inside the onPostExecute() method.

In your case, write below statement inside the onPostExecute() and declare JSONArray myUsers at class level:

ArrayAdapter<String> adapter = new ArrayAdapter<String>(RealestateActivity.this, android.R.layout.simple_spinner_item);
        adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);

        adapter.add("Select a Buseness...");                
        for (int i = 0; i < myUsers.length(); ++i)
        {
            adapter.add(myUsers.getString(i));
            adapter.add(myUsers.getJSONObject(i).getString("BusName"));
        }

            userSpinner.setAdapter(adapter); // I get an error here if I wrap these two lines in /*...*/ the whole thing loads as expected but the spinner is empty
            userSpinner.setOnItemSelectedListener(new MyOnItemSelectedListener());

        }
        catch (Exception e) 
        {       
            e.printStackTrace();
            displayExceptionMessage(e.getMessage());
        }

Final Solution:

private class Task extends AsyncTask<Void, Void, Void> 
 { 
    JSONArray myUsers = null;
    JSONObject jsonResponse = null;  // this is also needed at class level

     protected void onPreExecute() {            
         showDialog(DIALOG_TASKING); 
     } 
     protected Void doInBackground(Void... JSONArray) { 

        try
        {
        HttpGet request = new HttpGet(SERVICE_URI + "/GetBusNames");
        request.setHeader("Accept", "application/json");
        request.setHeader("Content-type", "application/json");

        DefaultHttpClient httpClient = new DefaultHttpClient();
        HttpResponse response = httpClient.execute(request);
        HttpEntity responseEntity = response.getEntity();

        char[] buffer = new char[(int)responseEntity.getContentLength()];
        InputStream stream = responseEntity.getContent();       
        InputStreamReader reader = new InputStreamReader(stream);
        reader.read(buffer);
        stream.close();

        jsonResponse = new JSONObject(new String(buffer));
        }
        catch (Exception e) 
        {       
            e.printStackTrace();
            displayExceptionMessage(e.getMessage());
        }
        return null;
    }

    protected void onPostExecute(Void unused) {
        dismissDialog(DIALOG_TASKING);    

 myUsers = jsonResponse.getJSONArray("GetBusNamesResult");

        ArrayAdapter<String> adapter = new ArrayAdapter<String>(RealestateActivity.this, android.R.layout.simple_spinner_item);
        adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);

        adapter.add("Select a Buseness...");                
        for (int i = 0; i < myUsers.length(); ++i)
        {
            adapter.add(myUsers.getString(i));
            adapter.add(myUsers.getJSONObject(i).getString("BusName"));
        }

            userSpinner.setAdapter(adapter); // I get an error here if I wrap these two lines in /*...*/ the whole thing loads as expected but the spinner is empty
            userSpinner.setOnItemSelectedListener(new MyOnItemSelectedListener());          
    } 
Paresh Mayani
  • 127,700
  • 71
  • 241
  • 295
  • I’ve tried all that but I get an error if I don’t try to pass a parameter into onPostExecute, so Eclipse says I have to pass either JSONObject jsonResponse, JSONArray myUsers or String buffer as a parameter from doInBackground to onPostExecute. If I do I get no errors but it crashes when I run it, I’m guessing because doInBackground has not finished what it’s doing and trying to move to onPostExecute with no data? It wont let me use "Void unused". –  Nov 07 '11 at 12:38
  • @MikeClarke I am sure you dont understood AsyncTask exactly, FYI onPostExecute() executes only when doInBackground() completes their execution. – Paresh Mayani Nov 07 '11 at 12:47
  • @MikeClarke You are not using your own brain. Mistake is JSONObject jsonResponse = null; requires to be declared at class-level. check update in above code. – Paresh Mayani Nov 07 '11 at 12:50
  • Thanks Paresh, yes I was not using my brain, I needed to declare the variables at class level. This is the first time since Uni that I have had to deal with proper programming and not web development, I have to remember threading and all the other things that you can get away with in a real language. Proper compiled software at the end of the day is more forgiving than triyng to maintain state in wb pages! I’m having lots of fun with this. –  Nov 07 '11 at 21:35
  • And you were right, I was not quite sure about how AsyncTask works and my next question would have been, “does onPostExecute() automatically follow on when doInBackground has finnished” but I had sort of gathered that it must. Cheers, Mike. –  Nov 07 '11 at 21:35
3

Use below code inside your onPostExecute method.

       userSpinner.setAdapter(adapter);  
       userSpinner.setOnItemSelectedListener(new MyOnItemSelectedListener());

Try this it may help you..

deepa
  • 2,496
  • 1
  • 26
  • 43
2

you need to move all the UI manipulation into postExecute method which is executed in the main app thread. Android UI is not thread safe.

slkorolev
  • 5,883
  • 1
  • 29
  • 32
2

Don't do UI related tasks in doInBackground(). Collect your data in doInBackground() and return i from there. Get your data as a parameter to onPostExecute() and issue your userSpinner.* calls there.

Harald Wilhelm
  • 6,656
  • 11
  • 67
  • 85