AsyncTask, должен ли он принять такой удар по производительности …?

Я разрабатываю небольшое приложение, которое читает на определенных html-страницах, переформатирует их, а затем показывает их в WebView. Если я запустил свой код в потоке графического интерфейса, то поражение производительности приблизилось к незначительному по сравнению с простое, чтобы WebView отображал исходную html-страницу. Но если я хороший мальчик и мне нравится, мне говорят, я должен использовать AsyncTask для запуска кода в фоновом режиме, чтобы не замерзать графический интерфейс в течение этих 3-5 секунд, мой код выполняет свою работу , Проблема в том, что … если я это сделаю, код займет более 10 раз. Для отображения страницы требуется 60 секунд, что неприемлемо.

Отслеживая проблему, TraceView показывает мне, что мой AsyncTask (по умолчанию приоритет) работает примерно в 10 мс кусков, около 4 раз в секунду. Мне нужно установить приоритет потока в MAX_PRIORITY, чтобы приблизиться к допустимому времени загрузки, но даже тогда он занимает 3-4 раза дольше, чем при запуске в потоке графического интерфейса.

Я что-то делаю неправильно, или так оно и работает? И должен ли он работать таким образом …?

Вот компилируемый код по запросу:

package my.ownpackage.athome; import android.app.Activity; import android.os.AsyncTask; import android.os.Bundle; import android.os.StrictMode; import android.webkit.WebView; import android.webkit.WebViewClient; public class AndroidTestActivity extends Activity { WebView webview; //... private class HelloWebViewClient extends WebViewClient { @Override public boolean shouldOverrideUrlLoading(WebView view, String url) { AndroidTestActivity.this.fetch(view, url); return true; } } public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); // To allow to connect to the web and pull down html-files, reset strict mode // see http://stackoverflow.com/questions/8706464/defaulthttpclient-to-androidhttpclient if (android.os.Build.VERSION.SDK_INT > 9) { StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build(); StrictMode.setThreadPolicy(policy); } // webview init etc... fetch(webview, "http://www.example.com"); } // This one calls either the AsyncTask or does it all manually in the GUI thread public void fetch(WebView view, String url) { //** Use these when run as AsyncTask in background - SLOW! //** Takes 30+ seconds at default thread priority, with MAX_PRIORITY 15+ seconds // AsyncTask<Void, String, String> fx = new FilterX(url, view, this); // fx.execute(); // running as AsyncTask takes roughly ten times longer than just plain load! //** Use these when not running as AsyncTask - FAST! takes ~5 seconds FilterX fx = new FilterX(url, view, this); fx.onPreExecute(); final String str = fx.doInBackground(); fx.onPostExecute(str); } } class FilterX extends AsyncTask<Void, String, String> { WebView the_view = null; // other stuff... FilterX(final String url, final WebView view, final Activity activity) { the_view = view; // other initialization // same code in both cases } protected void onPreExecute() { // same code in both cases } protected String doInBackground(Void... v) { // same in both cases... return new String(); // just to make it compile } protected void onPostExecute(final String string) { the_view.loadUrl(string); // same in both cases... } } 

Чтобы запустить точно такой же код в моем классе FilterX при запуске как AsyncTask, как при запуске в потоке GUI, я лишил все материалы ProgressBar, а затем получаю следующие тайминги:

  • 30+ секунд для загрузки страницы по умолчанию.
  • 15+ секунд для загрузки страницы в MAX_PRIORITY
  • 5+ секунд для загрузки страницы при запуске в потоке графического интерфейса пользователя

Вы не единственный, кто наблюдает за этим поведением. Замедление в 10 раз, вероятно, является результатом Android, использующего группу Linux (класс планирования) для потоков приоритета BACKGROUND или ниже. Все эти потоки должны жить с 10% процессорного времени в целом.

Хорошей новостью является то, что вам не нужно жить с настройками приоритета потока из java.lang.Thread. Вы можете назначить свой поток приоритетом pthread (Linux thread) из определений в android.os.Process. Там у вас есть не только Process.THREAD_PRIORITY_BACKGROUND, но и константы, чтобы немного настроить приоритет.

В настоящее время Android использует общую цепочку потоков для всех потоков с приоритетом THREAD_PRIORITY_BACKGROUND или хуже, а THREAD_PRIORITY_BACKGROUND составляет 10, а THREAD_PRIORITY_DEFAULT – 0, а THREAD_PRIORITY_FOREGROUND – -2.

Если вы перейдете на THREAD_PRIORITY_BACKGROUND + THREAD_PRIORITY_MORE_FAVORABLE (aka 9), ваш поток будет снят из фоновой группы с ограничением 10%, но не будет достаточно важным, чтобы слишком часто прерывать потоки пользовательского интерфейса.

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

Если вы можете использовать HandlerThread, это легко достичь:

 ht = new HandlerThread("thread name", THREAD_PRIORITY_BACKGROUND + THREAD_PRIORITY_MORE_FAVORABLE); ht.start(); h = new Handler(ht.getLooper()); 

Если вы хотите пойти с AsyncTask, вы все равно можете

 protected final YourResult doInBackground(YourInputs... yis) { Process.setThreadPriority(THREAD_PRIORITY_BACKGROUND + THREAD_PRIORITY_MORE_FAVORABLE); ... } 

Но имейте в виду, что базовая реализация может повторно использовать один и тот же объект Thread для разных задач, для следующей AsyncTask или что-то еще. Похоже, что Android просто сбрасывает приоритет после возвращения doInBackground ().

Конечно, если ваш пользовательский интерфейс действительно потребляет процессор и вам нужно больше энергии для своей задачи одновременно, убрав его из пользовательского интерфейса, вы можете установить еще один приоритет, возможно, до Process.THREAD_PRIORITY_FOREGROUND.

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

Несмотря на хит производительности, вы хотите сделать это в фоновом режиме. Играйте хорошо, а другие будут хорошо играть с вами.

Поскольку я не знаю, для чего это, я не могу предложить альтернативу. Моя первая реакция заключалась в том, что странно, что вы пытаетесь переформатировать HTML на телефонном устройстве. Это телефон , а не четырехъядерный процессор с кучей ОЗУ. Можно ли выполнить переформатирование в веб-службе и отобразить результат на телефоне?

U нужно вызвать final String str = fx.execute. Вы не должны вызывать doinbackground непосредственно из нити ui.

Intereting Posts
Java преобразовать массив объектов в массив int Какой тип объекта возвращает Spinner.getItemAtPosition (…)? Android-тема установлена ​​в черный цвет, но она белая в Android 4.1 Groovy, Scala, Clojure и т. Д. В Android Передача аргументов AsyncTask и возвращение результатов Android: почему моментальные снимки и gpu являются взаимоисключающими? Чтобы проверить, действительно ли приложение использует разрешения, указанные в файле манифеста Html input type 'file' не работает в webview в android.there есть какой-либо способ загрузить файл с помощью webview android Как адаптировать покрытие / галерею для соответствия различным размерам экрана Обновление Android ListActivity от BaseAdapter Джойстик API Android Что означает «@ + android: id / title»? Курсор финализирован без предварительного закрытия () Android Как разрешить ошибку «com.android.internal.R невозможно решить», когда я использую файл android MultiAutoCompleteTextView.java, Как указать темный режим действия с моей темой