异步任务使用泛型来处理doInBackground中的不同返回类型

时间:2014-11-27 02:09:02

标签: java android generics asynchronous

我有一个扩展异步任务的实用程序类。我将使用此调用在后台发出HTTP请求,但我还将有更多专门的子类来准备参数,标题,url来调用,所以我可以从GUI中删除更多常见的工作。

问题是我想要使用泛型。基础API类doInBackground将返回一个字符串,有一个更专业的Json子类,它将调用parent并返回一个JSONObject并对json响应进行一些解析,有专门的类扩展Json子类并返回自定义对象的List,所以上。原因是如果我们需要交换XML和XML处理,那么专门的子类将同时具有JSON和XML实现。这是因为我们正在重新使用几个不同的api。

所以我尝试使用Generics,但我并不是100%确定我理解这种情况下的实现。很明显,当你想做List之类的事情并列出List但是如何在这里应用它?我认为我主要是在模拟代码与实现之间混淆,在基本和子类中,一切都只是T,而不是像我在GUI中指定我期望的返回类型那样实例化其他地方的实例吗?比我想象的还要理解。所以我所说的是在编写类时我只使用T,从不指定类型,在代码中我实例化实例,当我指定类型时,这是doInBackground的返回类型是什么?

我还希望能够一般地实现onPostExecute()因为我将使用回调设置,因此GUI可以在调用完成时轻松订阅并处理结果,但是interfact也将具有onPostExecute的泛型(T回应)。所以我可以创建新实例,传递'this',当异步任务完成时,它将使用结果调用回调,并且回调可以处理适当的类型。

public class Base<T> extends AsyncTask<String, Integer, T> 
{   
    protected Callback callback = null; //interface implemented for processing response

    public Base setCallback(Callback callback){ this.callback = callback; return this; }

    @Override
    protected T doInBackground(String... uri) 
    {       
        //do http call
        String response = "";
        return response;  //raw string of server response
    }

    @Override
    final protected void onPostExecute(T result) 
    {    
        //no overrides, same every time
        if( callback != null )
        {
            callback.finished(result);  //forward generic result, but there it will be typed
        }
    }

public class JsonBase<T> extends Base<T>
{
    @Override
    protected T doInBackground(String... uri) 
    {       
        //this will be a JSONObject returned
        String result = (String)super.dpInBackground(uri); //gives me back a string
        return new JSONObject(result);                     //return a json object
    }    
} 

public class SpecializedBase<T> extends JsonBase<T>
{
    @Override
    protected T doInBackground(String... uri) 
    {       
        //this will be a List<String> returned
        //iterate over all json array strings and pass back
        return new List<String>();
    }
}

class FragmentFoo extends Fragment implements Callback
{
    @Override
    protected void onViewCreate(...)
    {
        //Example usage
        new JsonBase< JSONObject >().setCallback(this).execute("<url">);
        new SpecializedBase< List<String> >().setCallback(this).execute("");  //hard coded internally for example

    } 


    //Can we do something like this?  
    @Override
    protected void finished(JSONObject object)
    {
        //handle json response
    }

    @Override 
    protected void finished(List<String> strings)
    {
        //handle list of strings response
    }
}

interface Callback
{
    public <T> void finish(T response);      
}

Async的专用子类将根据特定类型进行定制,并返回不同的类型,我们希望根据GUI中的位置和我们正在做的事情来处理这些特殊类型。否则我们所能做的只是GUI中的所有逻辑或者有另一个中间层的包装器......这只是一个原始的例子,说明了我的观点以及我们希望如何工作。

2 个答案:

答案 0 :(得分:0)

只要保持T,任何时候它抱怨施放(T)响应我刚刚添加了抑制警告。只要我知道在特定的回调中会发生什么,并转换为该类型,那就没关系。但如果我犯了错误并将其转换为其他内容,则很容易在运行时崩溃。

它编译,运行和工作。但似乎不是一个干净的合适解决方案。

答案 1 :(得分:0)

我知道这是一个古老的问题,但我只是遇到过它 - 使用了大部分解决方案并对其进行了一些改进以解决您遇到的问题。

我只是粘贴代码,但基本上只需键入列表,而不是将其用作返回值,我使用整数静态作为回调中的返回值,并将列表创建为asynctask的字段对象本身,然后在回调方法中访问。 (为清晰起见,我还使用DatabaseLoaderParams)

public class DatabaseLoader<T> extends AsyncTask<DatabaseLoaderParams, Void, Integer> {


ArrayList<T> returnList;

protected DbLoaderCallback callback = null; //interface implemented for processing response

public DatabaseLoader setCallback(DbLoaderCallback callback){ this.callback = callback; return this; }


@Override
protected Integer doInBackground(DatabaseLoaderParams... params) {


//you have to give the object class to the asynctask     
ArrayList<T> mReturnList = getList(params[0].objectClass);

    try {
        // DB loading code

    } catch (Exception e) {
        e.printStackTrace();
    } catch (SQLException e) {

        e.printStackTrace();

        return 0;
    }


    // Done!
    returnList=mReturnList;

    return params[0].startId;
}

@Override
final protected void onPostExecute(Integer startId)
{

    if( callback != null && startId>0)
    {
        callback.onLoadFinished(startId);  //forward generic result, but there it will be typed
    }
}


private <T> ArrayList<T> getList(Class<T> requiredType) {
    return new ArrayList<T>();
}

在活动中:

@Override
public void onLoadFinished(int startId)
    {
        switch(startId){

        case INTEGER_STATIC:
            //check the type if you want but I don't bother
            for(DBObject dbObject : DBLoader.returnList){

...