Метад AsyncTask Апранаць (): Ці ёсць сцэнар, дзе ён на самай справе лепшы варыянт?

Пасля адказу гэтае пытанне , у мяне сумнеў пра сэнс/карыснасці выкарыстання метады Get() класа AsyncTask Android.

public final Result get ()

Waits if necessary for the computation to complete, and then retrieves its result. 

У прынцыпе, сінхроннае рашэнне класа AsyncTask, што блокі (застывае) карыстацкі інтэрфейс, пакуль фонавыя аперацыі не будуць скончаны.

Акрамя тэставых мэтаў, і нават у тых выпадках, я не магу думаць у любым выпадку, калі ён на самай справе з'яўляецца добрым рашэннем, але я магу памыляцца, таму я адчуваю сябе цікаўным.

Калі вам трэба, каб карыстальнік на самай справе чакаць, пакуль AsyncTask не скончыцца, вы можаце паказаць дыялог ці ProgressDialog, маючы кантроль над UI ў любы момант. Я ведаю, што гэта не зусім тое ж самае, але ІМХО гэта нашмат лепш, чым падыход, выкарыстоўваючы атрымаць() <�код /> метад.

20
Хоць сам пытанне цікавае, варыянт «лепш», часта вельмі суб'ектыўна. Вы можаце вызначыць «лепшы варыянт»?
дададзена аўтар Simon Forsberg, крыніца
Гэта мой пункт гледжання: гэта здаецца бескарысным.
дададзена аўтар Alejandro Colorado, крыніца
Хоць гэта праўда, што варыянт «лепш» можа быць вельмі суб'ектыўным, магчымы аб'ектыўны адказ можа быць заснаваны на прадукцыйнасці, напрыклад. Рэальны «дух» можа быць і гаворкі, калі нават ёсць «добры» сцэнар варыянт, таму што мне здаецца, што няма, што заўсёды ёсць лепшае рашэнне праблемы, чым з дапамогай функцыі атрымаць() метад.
дададзена аўтар Alejandro Colorado, крыніца
@SimonMeyer, гэта добры адказ (я б upvote яго, калі ён быў адпраўлены ў якасці адказу).
дададзена аўтар Alejandro Colorado, крыніца
Для мяне, толькі выкарыстанне атрымаць() , каб пазбегнуць NetworkOnMainThread выключэнне, у іншым слове бескарысна. Я не бачу ніякіх прычын, чаму б проста не напісаць поўную нармальную функцыю з зваротным аб'ектам, калі вам трэба значэнне з атрымаць() .
дададзена аўтар Chor Wai Chun, крыніца
гэта можа быць карысна, калі вы хочаце пераўтварыць Java-код для андроіда, які выкарыстоўвае клас будучыні: docs.oracle.com/javase/6/docs/api/java/util/concurrent/… . Такім чынам, рэчы, якія выкарыстоўваюцца ў будучых рэчах цяпер таксама выконваецца ў AsyncTask ThreadPool. Але вы маеце рацыю - я не бачу асаблівага сэнсу ў ім таксама
дададзена аўтар Simon Meyer, крыніца

9 адказы

AsyncTask isn't the only way of doing background operations. Indeed, the documentation says that AsyncTask should only be used for operations take at most a few seconds. So if you've got tasks that take longer, they should be coded via classes that implement the runnable interface. Such tasks in other (non AsyncTask) threads may well want to wait for an AsyncTask to finish, so it seems to me that the idea that there are no situations where one would want to use AsyncTask.get() is false.

Update: In response to a comment, to emphasize that this could be a valid use of AsyncTask.get(), the following is possible:

  • There could be AsyncTasks that get initiated from the UI thread, which might involve communicating over the internet, e.g. loading a web page, or communicating with a server. Whatever the results of the AsyncTask are, some (or all) of the results are needed to update the screen. Hence an AsyncTask with its doInBackground followed by onPostExecute on the UI thread makes sense.
  • Whenever the UI thread initiates an AsyncTask, it places the AsyncTask object in a queue, for additional processing by a separate background thread once the results are available.
  • For each AsyncTask in the queue in turn, the background thread uses AsyncTask.get() to wait for the task to finish, before doing the additional processing. One obvious example of additional processing could simply be logging all such AsyncTask activities to a server on the internet, so it makes sense to do this in the background.
The following code shows what I mean. The app calls KickOffAsynctask(...) whenever it wants to do an AsyncTask, and there's a background thread that will automatically pickup the task for post-processing once the task is complete.
public class MyActivity extends Activity {

    static class MyAsyncTaskParameters { }
    static class MyAsyncTaskResults { }

    Queue queue;  //task queue for post-processing of AsyncTasks in the background
    BackgroundThread b_thread; //class related to the background thread that does the post-processing of AsyncTasks

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);     
        queue = new  ConcurrentLinkedQueue();
        b_thread = new BackgroundThread(queue);
        b_thread.Start();       
    }

    void KickOffAsynctask(MyAsyncTaskParameters params) {
        MyAsyncTask newtask = new MyAsyncTask();
        newtask.execute(params);
        synchronized(queue) {
            queue.add(newtask);
        }
    }

    static class MyAsyncTask extends AsyncTask {

        @Override
        protected MyAsyncTaskResults doInBackground(MyAsyncTaskParameters... params) {
            MyAsyncTaskResults results = new MyAsyncTaskResults();
           //do AsyncTask in background
            return results;
        }

        @Override
        protected void onPostExecute(MyAsyncTaskResults res){
           //take required results from MyAsyncResults for use in the user interface
        }

    }

    static class BackgroundThread implements Runnable {
       //class that controls the post processing of AsyncTask results in background

        private Queue queue;
        private Thread thisthread;
        public boolean continue_running;

        public BackgroundThread(Queue queue) {
            this.queue=queue; thisthread = null; continue_running = true;
        }

        public void Start() {
            thisthread = new Thread(this);
            thisthread.start();
        }

        @Override
        public void run() {
            try {
                do {
                    MyAsyncTask task;
                    synchronized(queue) {
                        task = queue.poll();
                    }
                    if (task == null) {
                        Thread.sleep(100);
                    } else {
                        MyAsyncTaskResults results = task.get();
                       //post processing of AsyncTask results in background, e.g. log to a server somewhere
                    }
                } while (continue_running);     
            } catch(Throwable e) {
                e.printStackTrace();
            }           
        }

    }

}

Update2. Another possible valid use of AsyncTask.get() has occurred to me. The standard advice is not to use AsyncTask.get() from the UI thread, because it causes the user interface to freeze until the result is available. However, for an app where stealth is needed, that may be exactly what is required. So how about the following situation: James Bond breaks into the hotel room of Le Chiffre and only has a couple of minutes to extract all the data from the villian's phone and install the monitoring virus. He installs the app provided by Q and starts it running, but he hears someone coming so he has to hide. Le Chiffre enters the room and picks up his phone to make a call. For a few seconds the phone seems a bit unresponsive, but suddenly the phone wakes up and he makes his phone call without further thought. Of course, the reason for the unresponsiveness was the fact that Q's app was running. It had various tasks to do, and some of them needed to be done in a particular order. The app used two threads to do the work, namely the UI thread itself and the single background thread that processes AsyncTasks. The UI thread was in overall control of all the tasks, but because some tasks needed to be done before other tasks, there were points in the app where the UI thread used AsyncTask.get() while waiting for the background task to finish :-).

18
дададзена
На самай справе, я адправіў свае каментары да вашага абнаўлення 2! Я буду глядзець на яго.
дададзена аўтар Alejandro Colorado, крыніца
Я згодны з тым, што вы кажаце пра выкарыстанне толькі AsyncTask для аперацый, якія прымаюць у большасці некалькі секунд. Сапраўды, тыдзень назад я напісаў каментар да @ адказу CFlex ў дакладнасці з указаннем таго, што афіцыйнае docummentation дзяржавы аб тым, што.
дададзена аўтар Alejandro Colorado, крыніца
Дарэчы, як AsyncTask docummentation стан, ёсць некалькі правілаў, пранізлівых якія павінны выконвацца для гэтага класа, каб працаваць належным чынам: - клас AsyncTask павінен быць загружаны ў патоку карыстацкага інтэрфейсу. - Экземпляр задачы павінен быць створаны ў патоку карыстацкага інтэрфейсу. - выкананне (Params ...) павінен быць выкліканы ў патоку карыстацкага інтэрфейсу. Такім чынам, калі, як вы кажаце, адзін выкарыстоўвае іншыя (не AsyncTask) фонавыя патокі для выканання цяжкіх задач, то AsyncTask не можа быць выкарыстаны ў тым ўжо фоне threads.So AsyncTask.get() не з'яўляецца добра, ні магчымая ідэя ў гэтым выпадку.
дададзена аўтар Alejandro Colorado, крыніца
Прывітанне Павел (праверыў свой профіль, каб ведаць ваша імя;). Дзякуй за Ваш адказ! Я downvote свайго адказу, але не прымайце гэта неяк асабістае. Гэта значна прасцей: я лічу, што гэта не толькі няправільна, але дрэнны адказ, так як ён нават не можа быць рэалізаваны. Вы абнавілі свой адказ і вашыя намаганні заслугоўваюць downvote быць адменена. Я дам узнагароду на лепшы дадзены адказ (ИМО, відавочна). Я не пакіну яго ungiven, хоць ІМХО не быў сапраўды добры адказ.
дададзена аўтар Alejandro Colorado, крыніца
ІМХО, ваш адказ мае дзве вялікія праблемы: 1.- Вы кажаце аб запуску ў фонавым рэжыме забэрзаць чаргу AsyncTasks. Як я ўжо сказаў, афіцыйны docummentation кажа, што гэта немагчыма. 2.- Нават калі б гэта было магчыма (напрыклад, з дапамогай runOnUIThread, каб вярнуцца на першы план і выканаць кожны AsyncTask), выкарыстоўваючы атрымаць() метад будзе блакаваць (замарожванне) карыстацкі інтэрфейс падчас выканання чарга з AsyncTasks. Блякаваньне карыстацкага інтэрфейсу прыводзіць да «Прыкладанне не рэагуе дыялог», які раздражняе карыстальнікаў.
дададзена аўтар Alejandro Colorado, крыніца
Гэта мае вельмі простую альтэрнатыву: забыць атрымаць() <�код /> метад і выкарыстоўваць AsyncTask асінхронна з зваротных выклікаў. UI не будзе заблякаваны, і вы атрымаеце сапраўды такі ж вынік.
дададзена аўтар Alejandro Colorado, крыніца
Так што мой пункт гледжання: заўсёды здаецца, лепшым рашэннем, чым выкарыстанне атрымаць() метад.
дададзена аўтар Alejandro Colorado, крыніца
Вызначана, ваша абнаўленне 2 заслугоўвае майго upvote; о) З іншага боку, той факт, што прыкладанне Q у меў розныя задачы зрабіць, і некаторыя з іх трэба рабіць у пэўным парадку , ня робіць азначае, што ён павінен выкарыстоўваць атрымаць() <�код /> метад. На самай справе, Q можна лёгка рэалізаваць AsyncTask з зваротнымі выклікамі і пазбегнуць UI замарожаны, таму Le Chiffre нават не заўважыць ні адной праблемы з яго тэлефонам.
дададзена аўтар Alejandro Colorado, крыніца
Падлогу, у вашым Update1, ваш KickOffAsynctask ня выклікаецца ў любым месцы, так што чарга пустая, і я ўявіць сабе не AsyncTasks не выконваецца.
дададзена аўтар Alejandro Colorado, крыніца
Проста плямісты вашыя каментары, але да гэтага часу не было магчымасці разгледзець, таму што я працаваў над UPDATE2. Трэба ісці зараз, я адкажу пазней. Хуткі адказ: мая першая думка, што вы няправільна Update1. Калі гэта так, я буду спрабаваць змяніць пазней, каб зрабіць яго больш выразным, ці прызнаць сваю паразу!
дададзена аўтар Stochastically, крыніца
ОК дзякуй Alejandro :-). Калі я магу думаць аб любой іншай разумны (і ажыццяўляльнымі) выкарыстоўвае функцыі AsyncTask.get() да Баунті тэрмін мінае, то я буду абнаўляць мой адказ адпаведна.
дададзена аўтар Stochastically, крыніца
Я дадаў код, каб праілюстраваць мой Update1 выпадак. Наколькі я разумею, гэта сапраўднае выкарыстанне AsyncTask.get() , што не будзе блакаваць карыстацкі інтэрфейс.
дададзена аўтар Stochastically, крыніца
Прывітанне Алехандра, Я абнавіў свой адказ у адказ на ваш каментар. Ад таго, як вы што сфармуляванага пытання, верагодна, неабходна толькі, каб знайсці адзін разумна выкарыстоўваць AsyncTask.get (), каб стаяць шанец зарабіць ўзнагароду. Ці згодныя вы? (PS. Гэта ты, хто downvoted мой адказ тут?)
дададзена аўтар Stochastically, крыніца
Прывітанне Алехандра, код вельмі няпоўна, і проста меў на ўвазе, каб праілюстраваць гэтую ідэю ў тэрмінах AsyncTask, прыкладанне ўласнай фонавага патоку, разам з сінхранізаванай аб'екта чарзе. Як вы кажаце, KickOffAsynctask ніколі не выклікаецца, а гэта значыць, як ён не вытрымлівае AsyncTask будзе калі-небудзь выканаць. Адзін са спосабаў зрабіць гэта функцыянальным б стварыць карыстацкі інтэрфейс з дапамогай адной кнопкі, так што пры націску кнопкі KickOffAsynctask называецца. Калі вы зробіце гэта, то я ўпэўнены, што вы будзеце бачыць усе розныя біты выклікаецца пры націску кнопкі.
дададзена аўтар Stochastically, крыніца

калі запусціць некалькі asyncTasks паралельна, вы можаце захацець, што некаторыя задачы будуць чакаць выніку іншых.

Аднак, я думаю, што вы павінны пазбягаць працы занадта шмат asyncTasks паралельна, таму што гэта будзе запавольваць прылада.

5
дададзена
Праўда. Іншы сцэнар будзе тое, што іншыя патокі хацелі б дачакацца яго завяршэння.
дададзена аўтар android developer, крыніца
У афіцыйнай дакументацыі абвяшчае: Калі ўпершыню, AsyncTasks былі выконвацца паслядоўна на адным фонавым струмені. Пачынаючы з DONUT, гэта было зменена ў пул патокаў, што дазваляе некалькі задач, працаваць паралельна. Пачынаючы з Honeycomb, задачы выконваюцца ў адным патоку, каб пазбегнуць распаўсюджаных памылак, выкліканых паралельным выкананнем. Калі вы сапраўды хочаце паралельнага выканання, вы можаце выклікаць executeOnExecutor (java.util.concurrent.Executor, Object []) з THREAD_POOL_EXECUTOR.
дададзена аўтар Alejandro Colorado, крыніца
Справа ў тым, дзе я хачу, каб атрымаць тое, што я не магу ўявіць сабе адзін адзіны сцэнар, пры якім з дапамогай функцыі атрымаць() метад з'яўляецца лепшым варыянтам.
дададзена аўтар Alejandro Colorado, крыніца

<�Код> ня атрымаць метад павінен ніколі быць выкарыстаны ў патоку карыстацкага інтэрфейсу, так як ён будзе (як вы заўважылі) замарозіць UI. Ён павінен быць выкарыстаны ў фонавым патоку, каб чакаць канца вашай задачы, але, наогул кажучы, імкнуцца пазбягаць AsyncTask як мага больш (WHY? ).

Я хацеў бы прапанаваць зваротны выклік ці eventbus ў якасці замены.

5
дададзена
я думаю, што для маленькіх задач, гэта нармальна выкарыстоўваць AsyncTask. Прыклады: ListView пункты наліву, мадыфікацыі базы дадзеных, выявы загружаюцца (але вы таксама павінны выкарыстоўваць кэш-памяць). Цяпер у вас таксама ёсць бібліятэка залпу, каб дапамагчы вам з большасцю asynctasks выкарыстоўвае.
дададзена аўтар android developer, крыніца
Не маглі б вы прывесці прыклад шыну падзей выкарыстоўваецца з AsyncTask/FutureTask?
дададзена аўтар TechSpellBound, крыніца
Як у афіцыйнай дакументацыі станаў: AsyncTasks у ідэале павінен быць выкарыстаны для кароткіх аперацый (некалькі секунд самага вялікія.) Калі вам трэба захаваць тэмы, якія працуюць на працягу працяглых перыядаў часу, настойліва рэкамендуюцца выкарыстоўваць розныя інтэрфейсы, якія прадстаўляюцца java.util.concurrent PACAKGE, такія як кат, ThreadPoolExecutor і FutureTask .
дададзена аўтар Alejandro Colorado, крыніца

Я звычайна выкарыстоўваю клас апрацоўшчыка зрабіць трук (Загрузка носьбіта асинхр). як:

public void setRightSongAdele(Song current)
{
    RetriveCorrelateGenreSong rcgs = new RetriveCorrelateGenreSong(current);
    new Thread(rcgs).start();
}

@SuppressLint("HandlerLeak")
Handler updateRightAdeleHandler = new Handler()
{
    @Override
     public void handleMessage(Message msg) {
        songNextText.setText(utils.reduceStringLength(rightSong.getTitle(), 15));
        adeleNext.setImageBitmap(utils.getAlbumArtFromSong(rightSong.getPath(), getApplicationContext()));
    }
};
4
дададзена
Дзякуй за ваш адказ, але тое, што я сапраўды пытаюся, ці ёсць які-небудзь сцэнар, дзе гэта на самай справе лепшы варыянт ... Я не прашу альтэрнатывы; о)
дададзена аўтар Alejandro Colorado, крыніца

Я адпраўляю свой адказ, так як гэта тое, што я думаю, што ў гэты момант і ніхто не даў яго.

Маё цікаўнасць ўсё яшчэ жывы, так што я не буду адзначаць гэтае, як правільна. Калі хто-то адказвае на гэтае пытанне бліскуча, я адзначу яго/яе адказ як правільныя.

Мой адказ на тое, што ёсць на самой справе не сцэнар, пры якім з дапамогай AsyncTask ў атрымаць() метад з'яўляецца лепшым рашэннем.

ІМХО, выкарыстоўваючы гэты метад не мае сэнсу. Тое, што я маю на ўвазе, што заўсёды здаецца лепшым рашэннем.

Акрамя таго, я б сказаў, што гэта семантычна шакіруе, як выклік яго мяняе свой AsyncTask ў эфектыўны «SyncTask».

3
дададзена

Падобна на тое, што AsyncTask.get блокаў() нітка выклікае абанента, дзе AsyncTask.execute() не робіць.

Вы можаце выкарыстоўваць AsyncTask.get() для тэставых выпадкаў, калі вы хочаце, каб праверыць канкрэтны выклік вэб-службы, але не трэба быць асінхроннымі, і вы хацелі б кантраляваць, колькі часу спатрэбіцца, каб скончыць. Або ў любы час вы хацелі б праверыць на вашым вэб-службы ў наборы тэстаў.

Сінтаксіс такі ж, як выканаць:

    private class DownloadFilesTask extends AsyncTask {
     protected Long doInBackground(URL... urls) {
         int count = urls.length;
         long totalSize = 0;
         for (int i = 0; i < count; i++) {
             totalSize += Downloader.downloadFile(urls[i]);
             publishProgress((int) ((i/(float) count) * 100));
         }
         return totalSize;
     }

     protected void onProgressUpdate(Integer... progress) {
         setProgressPercent(progress[0]);
     }

     protected void onPostExecute(Long result) {
         showDialog("Downloaded " + result + " bytes");
     }
    }

new DownloadFilesTask().get(5000, TimeUnit.MILLISECONDS);
2
дададзена
Дзякуй за Ваш адказ! Згодна гэта , гэта і гэтага, ваш ProgressDialog не будзе правільна адлюстроўвацца.
дададзена аўтар Alejandro Colorado, крыніца

Як documentaion варта:

<�Р> "Чакае калі гэта неабходна для вылічэнні, каб скончыць, а затым   атрымлівае свой вынік ".

Таму абавязкова, каб вы пазбягалі называць яго на UI тэму, у адваротным выпадку вы атрымаеце NetworkOnMainThreadException . Я хацеў бы выкарыстаць яго ў тэставай асяроддзі, якая ўключае ў сябе чыстыя аперацыі або чакаць яшчэ адну задачу, каб скончыць.

EDIT: Я быў няправы NetworkOnMainThreadException .

2
дададзена
@AlejandroColorado Ён выкіне гэта выключэнне. Праверце, калі ў вас ёсць трохі часу. Не маглі б вы даць мне зваротную сувязь аб?
дададзена аўтар Blackbelt, крыніца
Я абяцаю, я буду правяраць, калі я магу і даць вам зваротную сувязь.
дададзена аўтар Alejandro Colorado, крыніца
Я не магу праверыць гэта прама цяпер, але я б сказаў, што выклік яго на UI тэму не кінуць NetworkOnMainThreadException , таму што ён сапраўды працуе ў фонавым рэжыме. Дарэчы, я згодны з вамі аб выкарыстанні яго толькі ў тэставай асяроддзі, хоць яна па-ранейшаму не самы лепшы варыянт для тых выпадкаў.
дададзена аўтар Alejandro Colorado, крыніца
Ня добры дзень для тэставання, але я ўпэўнены, што ён не будзе кідаць гэта выключэнне. Ну, калі AsyncTask добра закадзіраваны (відавочна, калі некаторыя з сеткавых задач выконваюцца ў onPreExecute() або onPostExecute() , а не ў doInBackground , ён павінен выкінуць гэта выключэнне).
дададзена аўтар Alejandro Colorado, крыніца
Абяцанне ёсць абяцанне: як я чакаў, што ён не кідаў NetworkOnMainThreadException .
дададзена аўтар Alejandro Colorado, крыніца

У мяне ёсць дадатак для рэдагавання фатаграфій, карыстальнік можа адкрываць фатаграфіі з URL.

Я выкарыстаў AsyncTask, каб загрузіць фота з URL, на працягу гэтага часу, інтэрфейс павінен быць заблякаваны. тое, што я зрабіў, я паказаў ProgressBar пачынае яго метад AsyncTask Апранаць (), чым схаваць ProgressBar ..

Здавалася, самае лепшае і простае рашэнне для мяне.

1
дададзена
Дзякуй за Ваш адказ! Вы атрымаеце той жа вынік, які паказвае ProgressBar ў onPreExecute() і не прымаючы яго ў onPostExecute() і карыстацкі інтэрфейс не заблякаваныя. Блякаваньне карыстацкага інтэрфейсу можа прывесці да «Application ня спагадным дыялог», які раздражняе карыстальнікаў.
дададзена аўтар Alejandro Colorado, крыніца
Акрамя таго, у адпаведнасці з гэта , this і гэтага, ваш ProgressDialog не будзе правільна адлюстроўвацца.
дададзена аўтар Alejandro Colorado, крыніца
Дзякуючы @Alenjandro. прычына блакаваць карыстацкі інтэрфейс, што я не хачу, каб карыстальнік ўносіць змены да таго, як малюнак цалкам загружана.
дададзена аўтар Tarek K. Ajaj, крыніца

Вы можаце выкарыстоўваць яго ў фільтр адаптара вашага AutoCompleteTextView ў ст.

private class Adapter extends BaseAdapter implements Filterable{
    getFilter(){
        return new Filter() {
        @Override
        protected FilterResults performFiltering(CharSequence constraint) {
            List suggestions = MyApiSuggestionsApi(constraint).get();
            return packageAsFilterResults(suggestions);
        }
    }
}
0
дададзена
Можа быць, я нешта не хапае, але як гэта звязана з пытаннем? Што гэта MyApiSuggestionsApi?
дададзена аўтар helleye, крыніца