【问题标题】:Async task using generics for different return types from doInBackground异步任务使用来自 doInBackground 的不同返回类型的泛型
【发布时间】:2014-11-27 02:09:02
【问题描述】:

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

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

所以我尝试使用泛型,但我不能 100% 确定我理解这种情况下的实现。很明显,当您想做 List 之类的事情并制作 List 列表时,我该如何应用它呢?我想我主要对模拟代码与实现感到困惑,在基类和子类中的所有内容都只是 T,而不是当我在 GUI 等其他地方实例化实例时,我指定了我期望的返回类型?比我想我明白。所以我要说的是,在编写我只使用 T 的类时,从不指定类型,并且在我实例化实例的代码中,当我指定类型时,这就是 doInBackground 的返回类型?

我还希望能够通用地实现 onPostExecute(),因为我将使用回调设置,以便 GUI 可以在调用完成时轻松订阅并处理结果,但接口也将具有通用的 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 中的所有逻辑,或者有另一个中间层的包装器......这只是一个简单的例子,说明了我的观点以及我们希望它如何工作。

【问题讨论】:

  • 我在 Json 子类中收到此警告,类型安全:当我返回 JSONObject 时,未检查从 JSONObject 转换为 T
  • 我也得到这个错误 SpecializedBase sbase = new SpecializedBase >().execute(); - 类型不匹配:无法从 AsyncTask> 转换为 SpecializedBase
  • 任何人都可以帮助...?

标签: java android generics asynchronous


【解决方案1】:

只保留 T 并且每当它抱怨投射 (T) 响应时,我只是添加了一个抑制警告。只要我知道在特定回调中会发生什么并转换为该类型,就可以了。但是如果我犯了错误并将其转换为其他内容,则很容易在运行时崩溃。

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

【讨论】:

    【解决方案2】:

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

    我只是粘贴代码,但基本上只是键入列表,而不是将其用作返回值,我在回调中使用整数静态作为返回值,并将列表创建为 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){
    

    ....

    【讨论】:

    • 什么是DatabaseLoaderParams,您能详细说明一下吗?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-12-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-09-26
    • 1970-01-01
    相关资源
    最近更新 更多