Повторное использование задач Async для Android

Я разрабатываю приложение, где в ряде видов деятельности мне нужно получить данные через Http. Как только у меня есть данные, я обрабатываю его в методе обратного вызова onPostExecute ().

Это отлично работает, если я определяю задачу async как встроенный класс, но поскольку я хочу выполнить ту же обработку в ряде операций, я определил ее как внешний класс.

Итак, вопрос заключается в том, что с помощью внешнего класса я могу передать «событие» обратно вызывающему классу в качестве средства передачи данных обратно. Я знаю, как это сделать на C #, но я новичок в Java и не вижу, как это сделать.

Хотя верно, что слушатель технически корректен, я бы сказал, что он слишком сложный или недостаточно сложный.

Вот более простое решение:

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 и используете обработчик или Activity.runOnUiThread, чтобы вернуть результаты в поток пользовательского интерфейса.

Один подход:

Определите родительский абстрактный класс под названием ParentActivity (продлить действие, конечно). У них есть абстрактный метод, называемый onAsyncCallback();

Попросите каждый класс, который использует задачу, расширить этот класс и реализовать этот метод.

В конструкторе AsyncTask его можно принять в ParentActivity .

Например

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

Когда это делается в onPostExecute() , просто выполните

 activity.onAsyncCallback(data); 

Это также будет работать с интерфейсом, он делает то же самое, за исключением того, что вы принимаете конструктор в экземпляре Listener.

Используйте шаблон прослушивателя. Посмотрите здесь TaskListener , Задача, которая использует этот прослушиватель и фрагмент, который вызывает задачу

Попробуйте создать свой собственный HTTP-запрос класса, который расширяет AsyncTask, а затем помещает ваш код в вызов doInBackground. Thyt вы должны только создать экземпляр своего класса с 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; } } 

Если вы хотите сделать это чистым способом, попробуйте следовать подходу

Сначала создайте перечисление, которое содержит все ваши имена асинхронных вызовов

 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(); } }