Google Directions API с использованием ExecutorService вместо AsyncTask

#java #android

#java #Android

Вопрос:

Кажется, что в каждом учебном пособии, которое я нахожу, вместо ExecutorService используется AsyncTask (устаревший). Я прошел курс Java на Udemy, и они также использовали AsyncTask для всего. Вот один класс, с которым я работаю:

 public class FetchURL extends AsyncTask<String, Void, String> {
Context mContext;
String directionMode = "driving";

public FetchURL(Context mContext) {
    this.mContext = mContext;
}

@Override
protected String doInBackground(String... strings) {
    // For storing data from web service
    String data = "";
    directionMode = strings[1];
    try {
        // Fetching the data from web service
        data = downloadUrl(strings[0]);
        Log.d("mylog", "Background task data "   data.toString());
    } catch (Exception e) {
        Log.d("Background Task", e.toString());
    }
    return data;
}

@Override
protected void onPostExecute(String s) {
    super.onPostExecute(s);
    PointsParser parserTask = new PointsParser(mContext, directionMode);
    // Invokes the thread for parsing the JSON data
    parserTask.execute(s);
}

private String downloadUrl(String strUrl) throws IOException {
    String data = "";
    InputStream iStream = null;
    HttpURLConnection urlConnection = null;
    try {
        URL url = new URL(strUrl);
        // Creating an http connection to communicate with url
        urlConnection = (HttpURLConnection) url.openConnection();
        // Connecting to url
        urlConnection.connect();
        // Reading data from url
        iStream = urlConnection.getInputStream();
        BufferedReader br = new BufferedReader(new InputStreamReader(iStream));
        StringBuffer sb = new StringBuffer();
        String line = "";
        while ((line = br.readLine()) != null) {
            sb.append(line);
        }
        data = sb.toString();
        Log.d("mylog", "Downloaded URL: "   data.toString());
        br.close();
    } catch (Exception e) {
        Log.d("mylog", "Exception downloading URL: "   e.toString());
    } finally {
        iStream.close();
        urlConnection.disconnect();
    }
    return data;
}
}
  

и я бы действительно хотел использовать ExecutorService, как здесь, вместо AsyncTask. Я бьюсь головой о стену и, похоже, не могу привести правильные аргументы, и эта штука работает.

Ответ №1:

Замените свой AsyncTask на Runnable :

 public class FetchUrl implements Runnable {

    public interface Callback {
        void onSuccess(String data);
        void onFailure(Exception e);
    }

    private String url;
    private WeakReference<Callback> callbackWeakReference;

    public FetchUrl(String url, Callback callback) {
        this.url = url;
        this.callbackWeakReference = new WeakReference<>(callback);
    }

    @Override
    public void run() {
        try {
            String data = downloadUrl(url);
            Callback callback = callbackWeakReference.get();
            if (callback != null) {
                callback.onSuccess(data);
            }
        } catch (Exception e) {
            Callback callback = callbackWeakReference.get();
            if (callback != null) {
                callback.onFailure(e);
            }
        }
    }
    
    ... // include your downloadUrl function
}
  

Затем создайте и отправьте его в ExecutorService :

 FetchUrl.Callback callback = new FetchUrl.Callback() {
    @Override
    public void onSuccess(String data) {
        // handle your data
    }

    @Override
    public void onFailure(Exception e) {
        // handle the exception
    }
};
Runnable job = new FetchUrl(url, callback);

ExecutorService executorService = Executors.newFixedThreadPool(4);
executorService.submit(job);
  

Обратите внимание, что я использовал WeakReference<Callback> , потому что код в вашем обратном вызове содержит ссылку на Context и может вызвать Context утечки.

submit() Функция возвращает Future для управления отправленным заданием. Это удобно, если вы хотите отменить задание или дождаться его завершения (блокируя текущий поток). Последний вариант использования, возможно, предпочел бы использовать Callable<Result> вместо Runnable , потому что вызывающий поток может обработать исключение, и обратный вызов не будет использоваться, что сделает ваш код более кратким.

Также не забудьте вызвать shutdown() свой ExecutorService , когда вам это больше не нужно.

Комментарии:

1. Спасибо за это, но, похоже, это не работает. Я не получаю свою ломаную линию для указаний. Я предполагаю, что это потому, что я не включаю свою функцию onpostexecute, но как бы я это реализовал?

2. Вы обрабатываете это в обратном вызове onSuccess (), где вы получаете свои данные обратно. Если возможно, выполняйте как можно больше тяжелой работы в фоновом режиме, поэтому, возможно, выполните синтаксический анализ также в Runnable и верните вашу полилинию в качестве конечного результата.