Return data from AsyncTask Android

前端 未结 3 683
佛祖请我去吃肉
佛祖请我去吃肉 2021-01-05 04:09

I tried to refer similar question on SO, but didn\'t got any help.

In my android app, I\'m planning to implement Recent Quote the user has visited i.e. similar to r

相关标签:
3条回答
  • 2021-01-05 04:49

    Essentially, AsyncTask.onPostExecute() is where you do whatever you want to do after AsyncTask's doInBackground() is executed and the execution result gets returned. This should be considered the best practice.

    When AsyncTask().execute() is called from the UI thread (note that this method must be called from the UI thread), the Android framework creates a worker thread and starts running whatever you wrote in AsyncTask.doInBackground() on this worker thread. At this point (after calling new AsyncTask().execute()), the UI thread continues to execute code after new AsyncTask().execute(). So now during run time, you have two threads (UI and worker thread) both running simultaneously.

    But where and when does the AsyncTask execution result get returned from the worker thread back to the UI thread?

    The point where your worker thread (doInBackground()) finishes and returns to the UI thread is AysncTask.onPostExecute(). This method is guaranteed to be called by the framework on the UI thread as soon as AsyncTask finishes. In other words, we don't care where and when AsyncTask.onPostExecute() gets called at run time, we just need to guarantee it will be called ultimately at some stage in the future. This is the reason why this method does not return an execution result - instead, it requires that the execution result gets passed in as the only method parameter from doInBackground().

    In addition, the Android API provides a way to return an AsyncTask execution result at coding time, AsyncTask.get():

    MyAsyncTask myAsyncTask = new MyAsyncTask();
    
    // This must be called from the UI thread:
    myAsyncTask.execute();
    
    // Calling this will block UI thread execution:
    ExecutionResult result = myAsyncTask.get();
    

    Bear in mind that AsyncTask.get() will block the calling thread's execution, and you will probably get an ANR exception if you call it on the UI thread. This is the payload of using AsyncTask.get(), by calling it on the UI thread, you are actually making your AsyncTask (worker thread) run synchronously with UI thread (by making UI thread wait). To sum up, this is doable but not recommended.

    0 讨论(0)
  • 2021-01-05 04:57

    Just for future reference, because this post is a little old:

    I have created an Activity class which has an onStart() method and a separate class for the AsyncTask. Based on my test, after the doInbackground() method the result will be sent to the activity first and after that onPostExecute() will run. This is because based off of logcat, I have my first response data (sent by server) first, then this response will show again from the activity and the last the message in onPostExecute() will show.

    Code for the activity:

    @Override
        protected void onStart() {
            super.onStart();
            String str = "***";
            if(isConnectedToInternet()){
                myAsyncTask.execute();
    
                try {
                    if(myAsyncTask.get())
                        str = myAsyncTask.getResponseMsg();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } catch (ExecutionException e) {
                    e.printStackTrace();
                } catch (CancellationException e) {
                    e.printStackTrace();
                }
            }
            Log.i("Data returned by server2:", str);
        }
    

    AsyncTask code:

    public class MyAsyncTask extends AsyncTask<Void, Void, Boolean> {
    
        private URL url;
        private HttpURLConnection conn;
        private String strResponseMsg;
    
        public MyAsyncTask(String url) throws MalformedURLException{
            this.url = new URL(url);
        }
    
    
        @Override
        protected void onPreExecute() {
            Log.i("Inside AsyncTask", "myAsyncTask is abut to start...");
        }
    
        @Override
        protected Boolean doInBackground(Void... params) {
            boolean status = false;
    
            try {
                conn = (HttpURLConnection) url.openConnection();
                conn.setConnectTimeout(Manager.ConnTimeout);
                conn.setReadTimeout(Manager.ReadTimeout);
    
                int responseCode = conn.getResponseCode();
                Log.i("Connection oppened", "Response code is:" + responseCode);
                if (responseCode == HttpURLConnection.HTTP_OK) {
                    BufferedReader in = new BufferedReader(new InputStreamReader(conn.getInputStream()));
                    if (in != null) {
                        StringBuilder strBuilder = new StringBuilder();
                        // Read character by character              
                        int ch = 0;
                        while ((ch = in.read()) != -1)
                            strBuilder.append((char) ch);
    
                        // Showing returned message
                        strResponseMsg = strBuilder.toString(); 
                        Log.i("Data returned by server:", strResponseMsg);
    
                        status = true;
                    }
                    in.close();
                }
    
            } catch (IOException e) {
                e.printStackTrace();
            }       
    
            return status;
        }
    
        @Override
        protected void onPostExecute(Boolean result) {
            Log.i("Inside AsyncTask", "myAsyncTask finished its task. Returning data to caller...");
        }
    
        public String getResponseMsg(){
            return strResponseMsg;
        }
    }
    
    0 讨论(0)
  • 2021-01-05 05:01

    postExecute() can't return a value because who or what would it return to? Your original method that invoked the AsyncTask is gone because your AsyncTask is running in the background. It's asynchronous meaning when AsyncTask.execute() returns it's still running in the background, and hence postExecute() can't return a value because there's nothing to return it to.

    Instead your AsyncTask needs a reference back to your Activity or some other object so it can post your values back to it. In your code the lines after you call execute() can't be there because your task hasn't finished. Instead you should create a method called updateSymbol( currentPrice, percentChange), move all that code below execute() in there, and in your AsyncTask you should pass a reference to the Activity. Then call updateSymbol( currentPrice, percentChange ) from the onPostExecute() method.

    But, be careful if you have a reference back to an Activity it can be destroyed while your doInBackground() is running, and when postExecute() runs it should just drop the results or not attempt to update the UI. For example, the user rotates their phone causing the Activity to be destroyed. I find it best to hold a reference to the AsyncTask in the activity so it can cancel() it if the Activity is destroyed. You can call AsyncTask.cancel() then check if your task was canceled like:

    public void postExecute( String result ) {
        if( !isCanceled() ) {
           // do your updating here
           activity.setSymbol( result );
        }
    }
    

    It's really easy to create a base class for all Activities so you can easily keep track of AsyncTasks running:

    public class BaseActivity extends Activity {
    
       List<AsyncTask> runningTasks;
    
       public void onStop() {
           for( AsyncTask task : runningTasks ) {
              task.cancel(true);
           }
       }
    
       public AsyncTask start( AsyncTask task ) {
          runningTasks.add( task );
          return task;
       }
    
       public void done( AsyncTask task ) {
          runningTasks.remove( task );
       }
    }
    

    Some quick pointers. You don't need execute( new String[] { "blah" + blah } ). Varargs in Java allow you to do this. execute( "blah" + blah ). You also are catching exceptions and continuing without really handling them. It will be hard when something really happens because your app catches them, and just continues as if nothing happened. If you get an error you might want to provide some feedback to the user and stop trying to execute that process. Stop, show an error to the user, and let them do the next thing. Move the catch blocks to the bottom of the methods.

    0 讨论(0)
提交回复
热议问题