How to pass variables in and out of AsyncTasks?

前端 未结 5 1122
深忆病人
深忆病人 2020-12-01 09:39

I haven\'t spent much time working with AsyncTasks in Android. I\'m trying to understand how to pass variables to and from the class. The syntax:



        
相关标签:
5条回答
  • 2020-12-01 10:02

    Passing a simple String:

     public static void someMethod{ 
         String [] variableString= {"hello"};
         new MyTask().execute(variableString);
    }
    
    static class MyTask extends AsyncTask<String, Integer, String> {
    
            // This is run in a background thread
            @Override
            protected String doInBackground(String... params) {
                // get the string from params, which is an array
                final String variableString = params[0];
    
                Log.e("BACKGROUND", "authtoken: " + variableString);
    
                return null;
            }
        }
    
    0 讨论(0)
  • 2020-12-01 10:20

    Note: all of the information below is available on the Android Developers AsyncTask reference page. The Usage header has an example. Also take a look at the Painless Threading Android Developers Blog Entry.

    Take a look at the source code for AsynTask.


    The funny < > notation lets you customize your Async task. The brackets are used to help implement generics in Java.

    There are 3 important parts of a task you can customize:

    1. The type of the parameters passed in - any number you want
    2. The type for what you use to update the progress bar / indicator
    3. The type for what you return once done with the background task

    And remember, that any of the above may be interfaces. This is how you can pass in multiple types on the same call!

    You place the types of these 3 things in the angle brackets:

    <Params, Progress, Result>
    

    So if you are going to pass in URLs and use Integers to update progress and return a Boolean indicating success you would write:

    public MyClass extends AsyncTask<URL, Integer, Boolean> {
    

    In this case, if you are downloading Bitmaps for example, you would be handling what you do with the Bitmaps in the background. You could also just return a HashMap of Bitmaps if you wanted. Also remember the member variables you use are not restricted, so don't feel too tied down by params, progress, and result.

    To launch an AsyncTask instantiate it, and then execute it either sequentially or in parallel. In the execution is where you pass in your variables. You can pass in more than one.

    Note that you do not call doInBackground() directly. This is because doing so would break the magic of the AsyncTask, which is that doInBackground() is done in a background thread. Calling it directly as is, would make it run in the UI thread. So, instead you should use a form of execute(). The job of execute() is to kick off the doInBackground() in a background thread and not the UI thread.

    Working with our example from above.

    ...
    myBgTask = new MyClass();
    myBgTask.execute(url1, url2, url3, url4);
    ...
    

    onPostExecute will fire when all the tasks from execute are done.

    myBgTask1 = new MyClass().execute(url1, url2);
    myBgTask2 = new MyClass().execute(urlThis, urlThat);
    

    Notice how you can pass multiple parameters to execute() which passes the multiple parameter on to doInBackground(). This is through the use of varargs (you know like String.format(...). Many examples only show the extraction of the first params by using params[0], but you should make sure you get all the params. If you are passing in URLs this would be (taken from the AsynTask example, there are multiple ways to do this):

     // This method is not called directly. 
     // It is fired through the use of execute()
     // It returns the third type in the brackets <...>
     // and it is passed the first type in the brackets <...>
     // and it can use the second type in the brackets <...> to track progress
     protected Long doInBackground(URL... urls) 
     {
             int count = urls.length;
             long totalSize = 0;
    
             // This will download stuff from each URL passed in
             for (int i = 0; i < count; i++) 
             {
                 totalSize += Downloader.downloadFile(urls[i]);
                 publishProgress((int) ((i / (float) count) * 100));
             }
    
             // This will return once when all the URLs for this AsyncTask instance
             // have been downloaded
             return totalSize;
     }
    

    If you are going to be doing multiple bg tasks, then you want to consider that the above myBgTask1 and myBgTask2 calls will be made in sequence. This is great if one call depends on the other, but if the calls are independent - for example you are downloading multiple images, and you don't care which ones arrive first - then you can make the myBgTask1 and myBgTask2 calls in parallel with the THREAD_POOL_EXECUTOR:

    myBgTask1 = new MyClass().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, url1, url2);
    myBgTask2 = new MyClass().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, urlThis, urlThat);
    

    Note:

    Example

    Here is an example AsyncTask that can take as many types as you want on the same execute() command. The restriction is that each type must implement the same interface:

    public class BackgroundTask extends AsyncTask<BackgroundTodo, Void, Void>
    {
        public static interface BackgroundTodo
        {
            public void run();
        }
    
        @Override
        protected Void doInBackground(BackgroundTodo... todos)
        {
            for (BackgroundTodo backgroundTodo : todos)
            {
                backgroundTodo.run();
    
                // This logging is just for fun, to see that they really are different types
                Log.d("BG_TASKS", "Bg task done on type: " + backgroundTodo.getClass().toString());
            }
            return null;
        }
    }
    

    Now you can do:

    new BackgroundTask().execute(this1, that1, other1); 
    

    Where each of those objects is a different type! (which implements the same interface)

    0 讨论(0)
  • 2020-12-01 10:22

    Alternatively, you could just use a regular thread and usea handler to send data back to the ui thread by overriding the handlemessage function.

    0 讨论(0)
  • 2020-12-01 10:25

    I recognize that this is a late answer, but here's what I've been doing for the last while.

    When I'm needing to pass in a bunch of data to an AsyncTask, I can either create my own class, pass that in and then access it's properties, like this:

    public class MyAsyncTask extends AsyncTask<MyClass, Void, Boolean> {
    
        @Override
        protected Boolean doInBackground(MyClass... params) {
    
            // Do blah blah with param1 and param2
            MyClass myClass = params[0];
    
            String param1 = myClass.getParam1();
            String param2 = myClass.getParam2();
    
            return null;
        }
    }
    

    and then access it like this:

    AsyncTask asyncTask = new MyAsyncTask().execute(new MyClass());
    

    or I can add a constructor to my AsyncTask class, like this:

    public class MyAsyncTask extends AsyncTask<Void, Void, Boolean> {
    
        private String param1;
        private String param2;
    
        public MyAsyncTask(String param1, String param2) {
            this.param1 = param1;
            this.param2 = param2;
        }
    
        @Override
        protected Boolean doInBackground(Void... params) {
    
            // Do blah blah with param1 and param2
    
            return null;
        }
    }
    

    and then access it like this:

    AsyncTask asyncTask = new MyAsyncTask("String1", "String2").execute();
    

    Hope this helps!

    0 讨论(0)
  • 2020-12-01 10:25

    Since you can pass array of objects in the square bracket, that is the best way to pass data based on which you want to do processing in the background.

    You could pass the reference of your activity or the view in the Constructor and use that to pass data back into your activity

    class DownloadFilesTask extends AsyncTask<URL, Integer, List> {
        private static final String TAG = null;
        private MainActivity mActivity;
        public DownloadFilesTask(MainActivity activity) {
            mActivity = activity;
            mActivity.setProgressBarIndeterminateVisibility(true);
        }
    
        protected List doInBackground(URL... url) {
            List output = Downloader.downloadFile(url[0]);
            return output;
        }
    
        protected void onProgressUpdate(Integer... progress) {
            setProgressPercent(progress[0]);
        }
    
        private void setProgressPercent(final Integer integer) {
            mActivity.setProgress(100*integer);
        }
    
        protected void onPostExecute(List output) {
    
            mActivity.mDetailsFragment.setDataList((ArrayList<Item>) output);
    
            //you could do other processing here
        }
    }
    
    0 讨论(0)
提交回复
热议问题