Заменить вложенные AsyncTasks - PullRequest
0 голосов
/ 27 апреля 2018

В моем приложении для Android у меня есть несколько операций, которые все подключены к одному сервису. Этот сервис устанавливает соединение с сервером и обрабатывает отправку и получение данных (в большинстве случаев это xml-файлы). Внутри своей деятельности я вызываю сервисные функции внутри AsyncTask, потому что мне нужно выполнить следующие действия, основанные на ответе сервера. Вот пример структуры:

String xmlString = "<myXmlString><myDataObject></myDataObject></myXmlString>";

final AsyncTask<Void, Void, Boolean> myTask = new AsyncTask<Void, Void, Boolean>() {
    @Override
    protected void onPreExecute() {
        super.onPreExecute();

        showProgressDialog("Send Data...");
    }

    @Override
    protected Boolean doInBackground(Void... params) {
        int rc = mService.callMethod("MYFUNCTION", xmlString);
        if (rc == 0) {
            return true;
        }
        else {
            return false;
        }
    }

    @Override
    protected void onPostExecute(Boolean success) {
        hideProgressDialog();

        if (success) {
            // handle received data
            // here it also might occur that another AsyncTask is called
            // e.g.: final AsyncTask<Void, Void, Boolean> nestedTask = new AsyncTask<Void, Void, Boolean>() { ... }
        } else {
            // handle error
        }
    }
};

myTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);

Handler handler = new Handler();
Runnable taskCanceler = new Runnable() {
    @Override
    public void run() {
        if (myTask.getStatus() == AsyncTask.Status.RUNNING) {
            myTask.cancel(true);

            hideProgressDialog();
        }
    }
};
handler.postDelayed(taskCanceler, 15000);

Поскольку я обновил Android Studio, он говорит, что «этот AsyncTask должен быть статическим, иначе могут возникнуть утечки». Кроме того, вложенные AsyncTasks иногда могут сбивать с толку, но они зависят друг от друга, поэтому я не знаю, как изменить эти задачи на статические классы. Должен ли я использовать другой подход для своих нужд или я могу преобразовать их в статические классы и по-прежнему поддерживать вложенную логику?

Я надеюсь, что смогу прояснить мои проблемы. Заранее спасибо!

Ответы [ 4 ]

0 голосов
/ 27 апреля 2018

Asyntasks были введены в качестве фонового метода синхронизации с возможностью публиковать результаты в основном потоке, когда они завершаются. Тем не менее, они имеют большие ограничения, когда логика сложна.

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

Наконец, у них есть жесткое ограничение на их количество, которое вы можете выполнять одновременно.

Здесь, вы найдете список библиотек, которые вы можете использовать вместо Asynctask

Если вы более опытный программист, я предлагаю вам сделать шаг вперед и использовать одну из следующих технологий:

RxJava : Это стало основной тенденцией в разработке Android за последние пару лет. Это поможет вам реагировать на бизнес-логику и вызовы API. Кривая обучения вначале довольно крутая, но позже она облегчит вашу жизнь. Вот вступительное руководство

Котлинские сопрограммы : Если вы любите котлинские сопрограммы, представьте простой способ справиться с параллелизмом. Здесь вы можете найти учебники

0 голосов
/ 27 апреля 2018
   private static class TASK_NAME extends AsyncTask<Void, Void, Boolean> {
        @Override
        protected void onPreExecute() {
            super.onPreExecute();

            showProgressDialog("Send Data...");
        }

        @Override
        protected Boolean doInBackground(Void... params) {
            int rc = mService.callMethod("MYFUNCTION", xmlString);
            if (rc == 0) {
                return true;
            }
            else {
                return false;
            }
        }

        @Override
        protected void onPostExecute(Boolean success) {
            hideProgressDialog();

            if (success) {
                // handle received data
                // here it also might occur that another AsyncTask is called
                // e.g.: final AsyncTask<Void, Void, Boolean> nestedTask = new AsyncTask<Void, Void, Boolean>() { ... }
            } else {
                // handle error
            }
        }
    };

Тогда OnCreateView вызывает его так:

new TASK_NAME().execute();
0 голосов
/ 27 апреля 2018

Не беспокойтесь о AsyncTasks, если вы понимаете основные потоки, которых достаточно для выполнения. AsyncTasks являются помощниками, и они не очень помогают. Добавьте что-то вроде следующего к вашему сервису. Как правило, вы передаете общий интерфейс (лямбда отлично подойдет, но, увы, Java7), который сработает при ответе. Тогда сервис делает потоки для вас. В конце концов, это то, что всегда будет происходить, если служба обращается к серверу. В любом случае это всегда нужно делать в потоке.

    HttpFetch.get(url, new UIResponse() {
        @Override
        public void response(String header, String content) {
        }
    },this);

Поскольку он использует статический класс для работы Http, утечки нет, и вы можете просто вызвать его и получить нужные данные ответа. И так как это тот же статический класс, вы, очевидно, можете просто вкладывать их в свое удовольствие. Таким образом, вы отправляете ему запрос и класс для ответа и реализуете класс ответа.

Например, вот остальная часть того времени, когда я сделал именно эту вещь:

public static void get(final URL urir, final Response response, final Activity activity) {
    Runnable run = new Runnable() {
        @Override
        public void run() {
            HttpURLConnection urlConnection = null;
            try {
                urlConnection = (HttpURLConnection) urir.openConnection();
                InputStream stream = new BufferedInputStream(urlConnection.getInputStream());
                final String content = convertStreamToString(stream);
                final String header = urlConnection.getResponseMessage();
                stream.close();

                activity.runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        response.response(header, content);
                    }
                });
            } catch (final IOException e) {
                activity.runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        response.error(e);
                    }
                });
            } finally {
                if (urlConnection != null) urlConnection.disconnect();
            }
        }
    };
    Thread thread = new Thread(run);
    thread.start();
}

static String convertStreamToString(java.io.InputStream is) {
    java.util.Scanner s = new java.util.Scanner(is).useDelimiter("\\A");
    return s.hasNext() ? s.next() : "";
}


public interface Response {
    void response(String header, String content);
    void error(IOException exception);
}

Другие классы, такие как RxJava, вероятно, будут делать то же самое. Просто передайте ему запрос с функцией ответа и выполните потоковую обработку в сервисе, и все будет прекрасно.

0 голосов
/ 27 апреля 2018

Похоже, вы готовы изменить логику доступа к веб-сервису.

Вы должны прочитать о Rxjava / RxKotlin и быстро выполнить рефакторинг с этими технологиями. Сначала это может показаться сложным, но, поверьте мне, однажды Rx, вы никогда не вернетесь.

Подробнее здесь

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...