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

Jak*_*son 16 android android-asynctask

我没有花太多时间AsyncTasks在Android上工作.我试图了解如何将变量传入和传递给类.语法:

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

     // Your Async code will be here

}
Run Code Online (Sandbox Code Playgroud)

它与< >类定义末尾的语法有点混淆.以前从未见过这种语法.似乎我只限于将一个值传递给AsyncTask.假设这个我不正确吗?如果我有更多要通过,我该怎么做?

另外,如何从AsyncTask返回值?

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

Pet*_*tai 46

注意:以下所有信息均可在Android Developers AsyncTask参考页面上找到.的用法报头具有一个例子.另请参阅无痛线程Android开发人员博客条目.

看一下AsynTask的源代码.


有趣的< >表示法允许您自定义您的异步任务.括号用于帮助在Java中实现泛型.

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

  1. 传入的参数类型 - 您想要的任何数字
  2. 用于更新进度条/指示器的类型
  3. 使用后台任务完成后返回的类型

请记住,上述任何一个都可能是接口.这是你在同一个电话上传递多种类型的方法!

您将这三种类型的东西放在尖括号中:

<Params, Progress, Result>
Run Code Online (Sandbox Code Playgroud)

因此,如果您要传入URLs并使用Integers更新进度并返回指示成功的布尔值,您将编写:

public MyClass extends AsyncTask<URL, Integer, Boolean> {
Run Code Online (Sandbox Code Playgroud)

在这种情况下,如果您正在下载位图,例如,您将在后台处理您对位图所做的操作.如果需要,您也可以返回位图的HashMap.还要记住你使用的成员变量不受限制,因此不要被params,进度和结果所束缚.

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

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

使用上面的示例.

...
myBgTask = new MyClass();
myBgTask.execute(url1, url2, url3, url4);
...
Run Code Online (Sandbox Code Playgroud)

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

myBgTask1 = new MyClass().execute(url1, url2);
myBgTask2 = new MyClass().execute(urlThis, urlThat);
Run Code Online (Sandbox Code Playgroud)

请注意如何传递多个参数execute()传递给多个参数doInBackground().这是通过使用varargs(你知道的String.format(...).许多例子只显示使用的第一个参数的提取params[0],但你应该确保你得到所有的参数.如果你传入的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;
 }
Run Code Online (Sandbox Code Playgroud)

如果您要执行多个bg任务,那么您需要考虑上述myBgTask1myBgTask2调用将按顺序进行.如果一个呼叫依赖于另一个呼叫,这是很好的,但是如果呼叫是独立的 - 例如你正在下载多个图像,而你不关心哪些呼叫首先到达 - 那么你可以使用以下内容并行调用myBgTask1myBgTask2调用THREAD_POOL_EXECUTOR:

myBgTask1 = new MyClass().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, url1, url2);
myBgTask2 = new MyClass().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, urlThis, urlThat);
Run Code Online (Sandbox Code Playgroud)

注意:

下面是一个示例AsyncTask,它可以在同一个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;
    }
}
Run Code Online (Sandbox Code Playgroud)

现在你可以这样做:

new BackgroundTask().execute(this1, that1, other1); 
Run Code Online (Sandbox Code Playgroud)

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


Luk*_*ner 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;
    }
}
Run Code Online (Sandbox Code Playgroud)

然后像这样访问它:

AsyncTask asyncTask = new MyAsyncTask().execute(new MyClass());
Run Code Online (Sandbox Code Playgroud)

或者我可以在我的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;
    }
}
Run Code Online (Sandbox Code Playgroud)

然后像这样访问它:

AsyncTask asyncTask = new MyAsyncTask("String1", "String2").execute();
Run Code Online (Sandbox Code Playgroud)

希望这可以帮助!