DRY:AsyncTasks的一个案例

时间:2014-02-05 22:43:01

标签: java android android-asynctask dry

我正在开发一个Android应用程序,它对Web服务有很多不同的请求。 每个请求都以AsyncTask的子类以这种方式完成:

(new AsyncTask<String, Void, Object1>() {
    @Override
    protected Object1 doInBackground(String... params) {
        // network request and parsing to Object1
        Object1 obj = new Object1();
        obj1 = Parser.parseObject1(httpClient.execute(...));
        return obj1;
    }

    @Override
    protected Object1 onPostExecute(Object1... ret) {
        return ret[0];
    }
}).execute();

Object1是不同对象的占位符(CarBicycleTruck ...),每个对象位于不同的AsyncTask

除了在String中返回httpClient的输出并在主线程(UI线程)中解析之外,还有什么其他选择?避免在UI中解析如果要解析大量数据,那么Thread听起来是合理的,对吗?

- = UPDATE = -

让我重新解释一下这个问题:我要求一种更智能的方法来开发我的应用程序,避免重复(AsyncTask有很多样板代码)。我的方法是创建20多个AsyncTask的子类,这显然不是DRY(不要重复自己)。

在iOS中我们有lambda表达式,因此在Web请求中完成的回调非常简单和简洁。

2 个答案:

答案 0 :(得分:4)

您可以创建包含大部分样板代码的类。 E.g。

public class SpecialAsyncTask<T> extends AsyncTask<String, Void, T> {

    public interface ResultProvider<T> {
        T generateResultInBackground(String... params);
    }

    public interface ResultConsumer<T> {
        void handleResultInForeground(T result);
    }

    private final ResultProvider<T> mProvider;
    private final ResultConsumer<T> mConsumer;
    private SpecialAsyncTask(ResultProvider<T> provider, ResultConsumer<T> consumer) {
        mProvider = provider;
        mConsumer = consumer;
    }

    @Override
    protected T doInBackground(String... params) {
        return mProvider.generateResultInBackground(params);
    }

    @Override
    protected void onPostExecute(T result) {
        mConsumer.handleResultInForeground(result);
    }

    public static <T> void execute(ResultProvider<T> provider, ResultConsumer<T> consumer, String... params) {
        new SpecialAsyncTask<T>(provider, consumer).execute(params);
    }
}

是一个示例,说明如何将Object1作为通用参数保留,同时能够指定一个只需要实现接口来处理代码的对象,否则这些代码必须位于新的AsyncTask内实例

使用类似的模式,您可以将一些常用代码定义为静态内容:

class Providers {
    public static final ResultProvider<String> HTTP_GETTER = new ResultProvider<String>() {

        @Override
        public String generateResultInBackground(String... params) {
            return MagicHttpLibrary.getContentAsString(params[0]);
        }

    };
}

您可以使用Providers.HTTP_GETTER作为参数,而不是实施doInBackground。或者创建一个新的类层次结构,实现其中一个接口,使用不同的方法来访问它们(例如工厂)

使用上面的例子可以看例如下面的

class User extends Activity implements ResultConsumer<String> {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        SpecialAsyncTask.execute(Providers.HTTP_GETTER, this , "http://google.com");
        SpecialAsyncTask.execute(Providers.HTTP_GETTER, this , "http://yahoo.com");
    }

    @Override
    public void handleResultInForeground(String result) {
        Toast.makeText(this, result, Toast.LENGTH_LONG).show();
    }
}

除了不同的方法调用之外,或多或少没有重复的代码。这取决于您希望如何使用类以及代码中实际发生的变化以了解如何设计类似的东西。确定需要参数化的部分,并将重复的代码移动到重用位置(继承/组合)。

答案 1 :(得分:0)

Google的Volley HTTP请求库执行请求并在同一个工作线程中解析它们。所以,这是编码的一个很好的例子。