如何将变量传入和传出AsyncTasks?

时间:2012-03-28 03:41:25

标签: android android-asynctask

我没有花太多时间在Android中使用AsyncTasks。我试图了解如何将变量传入和传递给类。语法:

class MyTask extends AsyncTask<String, Void, Bitmap>{

     // Your Async code will be here

}

在类定义的末尾使用< >语法有点令人困惑。以前从未见过这种语法。似乎我只限于将一个值传递给AsyncTask。假设这个我不正确吗?如果我还有更多要通过,我该怎么做?

另外,如何从AsyncTask返回值?

这是一个类,当你想使用它时,你调用new MyTask().execute(),但你在课堂上使用的实际方法是doInBackground()。那你在哪里实际归还什么?

5 个答案:

答案 0 :(得分:45)

注意:以下所有信息均可在Android开发者 AsyncTask reference page 上找到。 使用标头有一个示例。另请查看 Painless Threading Android Developers Blog Entry

看看the source code for AsynTask


有趣的< >表示法可让您自定义Async任务。括号用于帮助实现generics in Java

您可以自定义任务的3个重要部分:

  1. 传入的参数类型 - 您想要的任何数字
  2. 用于更新进度条/指示符的类型
  3. 使用后台任务完成后返回的类型
  4. 请记住,上述任何一种都可能是接口。这就是你可以在同一个电话中传递多种类型的方法!

    您可以将这3种内容的类型放在尖括号中:

    <Params, Progress, Result>
    

    因此,如果你打算传递URL并使用Integers更新进度并返回一个表示成功的布尔值,你会写:

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

    在这种情况下,如果您正在下载位图,那么您将在后台处理使用位图所做的事情。如果需要,您也可以返回位图的HashMap。还要记住你使用的成员变量不受限制,所以不要因为参数,进度和结果而过于紧张。

    启动AsyncTask实例化它,然后execute顺序或并行实例化它。在执行中,您传入变量。你可以传递不止一个。

    请注意,您不要直接致电doInBackground() 。这是因为这样做会破坏AsyncTask的魔力,即doInBackground()在后​​台线程中完成。直接调用它会使它在UI线程中运行。所以,你应该使用execute()的形式。 execute()的工作是在后台线程而不是UI线程中启动doInBackground()

    使用上面的示例。

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

    onPostExecute将在执行完所有任务时触发。

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

    注意如何将多个参数传递给execute(),将多个参数传递给doInBackground()。这是通过使用varargs(您知道String.format(...)。许多示例仅显示使用params[0]提取第一个参数,但您应该 make sure you get all the params 。如果您传入的URL是(从AsynTask示例中获取,有多种方法可以执行此操作):

     // 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;
     }
    

    如果您要执行多项bg任务,则需要考虑上述myBgTask1myBgTask2调用将按顺序进行。如果一个呼叫依赖于另一个呼叫,这是很好的,但如果呼叫是独立的 - 例如,您正在下载多个图像,而您不关心哪些呼叫首先到达 - 那么您可以创建myBgTask1和{{ 1}}与myBgTask2

    并行调用
    THREAD_POOL_EXECUTOR

    注意:

    示例

    这是一个示例AsyncTask,它可以在同一myBgTask1 = new MyClass().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, url1, url2); myBgTask2 = new MyClass().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, urlThis, urlThat); 命令中使用任意数量的类型。限制是每种类型必须实现相同的接口:

    execute()

    现在你可以做到:

    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;
        }
    }
    

    其中每个对象都是不同的类型! (实现相同的接口)

答案 1 :(得分:9)

我认识到这是一个迟到的答案,但这是我最后一直在做的事情。

当我需要将一堆数据传递给AsyncTask时,我可以创建自己的类,传入它然后访问它的属性,如下所示:

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;
    }
}

然后像这样访问它:

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

或者我可以在我的AsyncTask类中添加一个构造函数,如下所示:

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;
    }
}

然后像这样访问它:

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

希望这有帮助!

答案 2 :(得分:2)

由于您可以在方括号中传递对象数组,因此这是根据您要在后台进行处理的数据传递的最佳方式。

您可以在构造函数中传递活动或视图的引用,并使用该引用将数据传递回您的活动

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
    }
}

答案 3 :(得分:0)

或者,你可以使用常规线程和usea处理程序通过覆盖handlemessage函数将数据发送回ui线程。

答案 4 :(得分:0)

传递一个简单的字符串:

 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;
        }
    }