Android异步任务的重复利用

6
我正在开发一个应用程序,在其中许多活动中,我需要通过Http检索数据。 一旦我获得数据,我就在onPostExecute()回调方法中处理它。
如果我将async task定义为内联类,则这样做很好,但是由于我想在许多活动中进行相同的处理,因此我已将其定义为外部类。
那么问题来了,使用外部类,我如何向调用类发出“事件”作为传递数据的手段。我知道如何在C#中做到这一点,但我是Java的新手,不知道如何��现。
5个回答

4

虽然Listener从技术上讲是正确的,但我认为它要么过于复杂,要么不够简单。

以下是更简单的解决方案:

class Foo {
   class Bar extends AsyncTask<Void, Void, Result> {

      public void onPostExecute(Result res) {
         doSomething(res);
      }
   }

   public void doSomething(Result res) {
      /// process result
   }

   public void startTask() {
       new Bar().execute();
   }
}

等同于:

class Bar extends AsyncTask<Void, Void, Result> {
     private final Foo foo;
     public Bar(Foo foo) { this.foo = foo; }

     public void onPostExecute(Result res) {
       foo.doSomething(res);
     }
}


class Foo {
   public void doSomething(Result res) {
      /// process result
   }

   public void startTask() {
       new Bar(this).execute();
   }
}

...这就是你所问的:当你将内部类拉出来时,你失去了隐式指针。只需使其明确并传递它。

坏消息是,这种解决方案会引起各种内存泄漏和生命周期问题。我非常建议在你的程序变得更加庞大之前,不妨考虑使用IntentService代替AsyncTask,并使用Handler或Activity.runOnUiThread将结果返回到UI线程。


可能会出现哪些内存泄漏问题?您能否提供一些关于如何使用IntentService而不是AysncTask的参考资料?我阅读了这篇文章https://dev59.com/-mw15IYBdhLWcg3w3vpe,强烈建议在http请求中使用`AsyncTask()`。 - Alston
我强烈不同意6343166。描述AsyncTask问题需要超过600个字符。只需在Google中搜索“AsyncTask内存泄漏”即可找到数十篇文章。要了解如何使用IntentService的示例,请从eclipse/ADT中选择New > Other,然后在对话框中选择Android > Android Object > Next并选择Service(Intent Service)。您将获得一个优秀的原型。 - G. Blake Meike
http://stackoverflow.com/questions/25345087/intentservice-connected-to-server-listening 建议不要使用 Intent Service - Alston
实际上,它建议重新实现 IntentService。在现有 IntentService 的“一次性”特性成为问题的情况下,这对我来说似乎相当合理。请注意,如建议的那样,它有一个错误:它不会启动服务(因此不会降低 oom_adj)。就个人而言,我通常认为 IntentService 提供的隔离是一个优点。 - G. Blake Meike
@G. Blake Meike 这仅适用于 For 类,如果另一个类需要使用 Bar 任务怎么办?那就不是可重用的。 - Diego

3

一种方法:

定义一个名为ParentActivity的父抽象类(当然要扩展Activity)。其中包含一个名为onAsyncCallback();的抽象方法。

让每个使用该任务的类都扩展该类并实现该方法。

在您的AsyncTask构造函数中,接受一个ParentActivity

例如:

ParentActivity activity;
public MyTask (ParentActivity myActivity)
{
 this.activity = myActivity;
}

onPostExecute() 中完成后,只需执行以下操作

activity.onAsyncCallback(data);

这也可以使用接口来实现,原理相同,只不过您需要在构造函数中传入监听器实例。


2
如果您想以清晰的方式完成此操作,请尝试以下方法:
首先创建一个包含所有异步调用名称的枚举。
public enum TaskType {
    USER_LOGIN(1), GET_PRODUCTS(2), GET_EMPLOYEE(3);

    int value;

    private TaskType(int value) {
        this.value = value;
    }
}

然后创建一个接口。
public interface AsyncTaskListener {
    public void onTaskCompleted(String result, TaskType taskType);
}

现在在你要调用GetAsyncTask的活动中实现这个接口,例如:

 public class LoginActivity extends Activity implements AsyncTaskListener {

 protected void onCreate(Bundle savedInstanceState) {
     String url = ".....";
     new GetAsyncTask(LoginActivity.this, LoginActivity.this, TaskType.USER_LOGIN).execute(url);
 }
    ...
    public void onTaskCompleted(String result, TaskType taskType) {
       if(taskType == TaskType.USER_LOGIN){
       //your login result handling here
       }
}

最后,这是您的AsyncTask。
public class GetAsyncTask extends AsyncTask<String, Void, String> {
    String outputStr;
    ProgressDialog dialog;
    Context context;
    AsyncTaskListener taskListener;
    TaskType taskType;

    public GetAsyncTask(Context context, AsyncTaskListener taskListener, TaskType taskType){
        this.context = context;
        this.taskListener = taskListener;
        this.taskType = taskType;
    }

    @Override
    protected void onPreExecute() {
        super.onPreExecute();
        dialog = ProgressDialog.show(context, "Loading", "Please wait...", true);
    }
    @Override
    protected String doInBackground(String... params) {
        String urlString = params[0];

        try {

            URL url = new URL(urlString);
            HttpURLConnection conn
                    = (HttpURLConnection) url.openConnection();
            conn.setConnectTimeout(5000);
            if (conn.getResponseCode() != 200) {
                throw new IOException(conn.getResponseMessage());
            }

            // Buffer the result into a string
            BufferedReader rd = new BufferedReader(
                    new InputStreamReader(conn.getInputStream()));
            StringBuilder sb = new StringBuilder();
            String line;
            while ((line = rd.readLine()) != null) {
                sb.append(line);
            }
            rd.close();
            conn.disconnect();
            String jsonStr = sb.toString();
            outputStr = jsonStr;
        } catch (SocketTimeoutException e) {
            outputStr = "timeout";
        }catch(Exception e){
            e.printStackTrace();
            outputStr = "error";
        }

        return outputStr;
    }

    @Override
    protected void onPostExecute(String result) {
        super.onPostExecute(result);
        taskListener.onTaskCompleted(result, taskType);
        dialog.dismiss();
    }

}

1
尝试创建自己的http请求类,继承AsyncTask,并将代码放在“doInBackground”调用中。这样你只需要用URL和参数实例化你的类,并读取响应即可。对我很有效。
以下是示例:
public class HttpRequest extends AsyncTask<String, Void, String> {
    public String url;
    public List<NameValuePair> nameValuePairs;
    public String httpResponse =null;

    public HttpRequest(String _url, List<NameValuePair> _nameValuePairs) {
        url = _url;
        nameValuePairs=_nameValuePairs;
    }

    @Override
    protected String doInBackground(String... params) {
        httpResponse = getWebPageWithFormData(url, nameValuePairs);
        return "";
    }

    public static String getWebPageWithFormData( String url, List<NameValuePair> nameValuePairs ){
        String html = "";
        HttpClient httpclient = new DefaultHttpClient();
        HttpPost httppost = new HttpPost(url);
        if (nameValuePairs!=null){
            try {httppost.setEntity(new UrlEncodedFormEntity(nameValuePairs));}
            catch (Exception e){}
        }
        HttpResponse response = null;
        try {
            response = httpclient.execute(httppost);
        }
        catch (ClientProtocolException e) { return ""; }
        catch (IOException e) { return ""; }
        int responseCode = response.getStatusLine().getStatusCode();
        switch(responseCode) {
            case 200:
                HttpEntity entity = response.getEntity();
                if(entity != null) {
                    try{ html = EntityUtils.toString(entity);}
                    catch (Exception e) {}
                }
                break;
        }
        return html;
    }
}

1

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接