【问题标题】:How to use Asynctask effectively如何有效地使用 Asynctask
【发布时间】:2012-03-16 17:12:21
【问题描述】:

我是 Android 新手。我想问你们关于 Asynctask 的问题。我有一个活动显示项目的(应用程序、歌曲、故事..)详细信息。它需要许多相关数据,例如屏幕截图、相关应用程序(歌曲、故事)……那么 Asynctask 最好的实现是什么?我是为每个任务创建一个异步任务(例如:2 个异步任务:1 个用于获取屏幕截图,1 个用于获取相关项目...)还是将所有内容都放入 doInBackGround 并发布进度?

提前致谢。

【问题讨论】:

标签: android thread-safety android-asynctask


【解决方案1】:

从 OO 的角度来看,业务逻辑的东西应该始终与 UI 的东西隔离开来。我会将我所有的业务调用(如 getSong()、getStore() 等)隔离并集中到一个 POJO 中,并让我的活动类只专注于 UI 操作/渲染,这就是我的做法:

  1. 定义一个接口 IBusinessDAO
  2. 定义 RealBusinessDAO 实现 IBusinessDAO
  3. 定义 MockBusinessDAO 实现 IBusinessDAO
  4. 调用 IBusinessDAO.getSong();在 AsyncTask.doInBackground() 中

    public class MyActivity extends Activity {
      IBusinessDAO businessDAO;
    
      ... ...
    
      private class MyAsyncTask extends AsyncTask<Void, Void, Void> {
        ... ...        
    
        protected void doInBackground(Void... params) {
          businessDAO.getSong();
        }
      }
    
      ... ...
    
      public void onCreate(Bundle savedInstanceState) {
        if (runInTest)
          businessDAO = new MockBusinessDAO();
        else
          businessDAO = new RealBusinessDAO();
    
        new myAsyncTask().execute();
      }
    
    }
    

因此,在不同活动之间的每个 AsyncTask 实现中,您的 AsyncTask.doInBackgroud() 将简单明了,从而使您的代码更加高效和可维护。

它还有助于提高代码的可测试性,对您的业务逻辑进行单元测试,因为它是一个 POJO,您可以使用纯 JUnit 编写您的测试用例。有时我们想测试 UI 组件,并不关心底层业务逻辑是如何实现的,比如我的业务逻辑连接到远程 http 服务器下载一些 json 数据,我不想每次都这样做想要测试 UI 布局,对于这种情况,我可以很容易地改变我所有的活动使用 MockBusinessDAO(一种 Spring 的 DI 概念),来测试 UI 组件,而不用关心实际的业务逻辑是如何实现的。

最后,它还提高了代码的可重用性,因为除了经典 POJO 之外,您的 businessDAO 与 Andriod 没有任何关系,此外,您不需要关注 BusinessDAO 实现中的任何并发性,因为它的所有方法都将在 AsyncTask 中调用.doInBackground() 方法。

希望有所帮助。

【讨论】:

  • 可能我没有解释清楚。我的应用在某种程度上喜欢 Android Market。例如:详细应用活动,显示应用截图、同类别应用、同供应商应用、推荐应用。 所以我创建了 4 个异步任务来获取数据或将 4 个函数放在一个异步任务中并通过调用 publishProgress 更新 UI。哪种方式更有效。我已经对歌曲、应用程序、故事......和假数据有不同的模型:D
  • 我个人更喜欢单个AsyncTask和publishProgress,只要你所有耗时的任务都在后台线程中处理,使用一个就足够了,使用几个更有效。
【解决方案2】:

我已经在一个 AsyncTask 中实现了这样的任务

private void _initCommonAsyncTask(AsyncTaskName currentTaskName,
        String searchQuery) {
    CommonAsyncTask task = new CommonAsyncTask(currentTaskName, searchQuery);
    task.execute();
    taskReference = new WeakReference<CommonAsyncTask>(task);
}

/**
 * Asynchronous Task for different functionalities.
 * 
 */
private class CommonAsyncTask extends AsyncTask<Void, Void, Void> {
    private final String searchQuery;
    private AsyncTaskName currentTaskName;

    /**
     * Default constructor
     */
    public CommonAsyncTask(AsyncTaskName currentTaskName, String searchQuery) {
        super();
        this.searchQuery = searchQuery;
        this.currentTaskName = currentTaskName;
    }

    @Override
    protected void onPostExecute(Void result) {
        switch (currentTaskName) {
        case SEARCH:
            // Reinitialized the list view
            break; 
        case REFRESH:
            // Reinitialized the list view
            break;
        case LOAD_NEXT:
            // Reinitialized the list view
            break;
        default:
            break;
        }
        super.onPostExecute(result);
    }

    @Override
    protected void onPreExecute() {
        super.onPreExecute();
    }

    @Override
    protected Void doInBackground(Void... params) {
        switch (currentTaskName) {
        case SEARCH:
            // My searching stuff here
            break;
        case REFRESH:
            // my refreshing stuff here
            break;  
        case LOAD_NEXT:
            //my load next 50 orders here
            break;  
        default:
            break;
        }
        return null;
    }
}

你可以调用 Asynctask 使用

_initCommonAsyncTask(AsyncTaskName.SEARCH, searchQuery);

像这样在枚举中定义你的任务列表

public enum AsyncTaskName {
    SEARCH, REFRESH, LOAD_NEXT;
}

【讨论】:

    最近更新 更多