6

我正在开发一个应用程序,在许多活动中我需要通过 Http 检索数据。一旦我有了数据,我就会在 onPostExecute() 回调方法中处理它。

如果我将异步任务定义为内联类,这可以正常工作,但由于我想在许多活动中进行相同的处理,我将其定义为外部类。

所以问题是,使用外部类如何将“事件”发回给调用类,作为将数据传回的一种方式。我知道如何在 C# 中做到这一点,但我是 Java 新手,看不到如何实现这一点。

4

5 回答 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 线程。

于 2013-01-21T22:52:07.443 回答
3

一种方法:

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

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

在您的 AsyncTask 构造函数中,让它接受ParentActivity.

例如

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

完成后onPostExecute(),只需执行

activity.onAsyncCallback(data);

这也适用于接口,它做同样的事情,除了你让构造函数在侦听器实例中接受。

于 2013-01-21T21:54:52.920 回答
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();
    }

}
于 2014-12-18T01:39:58.387 回答
1

使用侦听器模式。看看这里TaskListener使用这个监听器的任务和调用任务的片段

于 2013-01-21T21:58:28.950 回答
1

尝试制作您自己的扩展 AsyncTask 的 http 请求类,然后​​将您的代码放在“doInBackground”调用中。你只需要用 url 和 params 实例化你的类并读取响应。这对我有用。

这是示例:

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;
    }
}
于 2013-06-30T11:03:17.020 回答