AndroidでのHandlers
、AsyncTask
、Threads
の違いについて少し混乱しました。私はstackoverflowでここにかなりの数のブログと質問を読んだ。
Handler
は、UIと通信するためのバックグラウンドスレッドです。例えばプログレスバーの更新はHandler
を介して行われるべきです。ハンドラを使用すると、メッセージをスケジュールしたり、複数のUI要素を更新したり、タスクを繰り返したりする場合に、MessagingQueues
の利点があります。
AsyncTask
は似ていますが、Handler
を使用するという事実には関係ありませんが、UIスレッドでは実行されないため、Webサービスの取得など、データの取得に適しています。後でUIと対話できます。
Thread
はUIと対話できず、より「基本的な」スレッドを提供します。そしてAsyncTask
の抽象化をすべて見逃すことになります。
ただし、サービス内でソケット接続を実行したいのですが。これはハンドラーまたはスレッド、あるいはAsyncTask
で実行する必要がありますか? UIの操作はまったく必要ありません。使用するパフォーマンスの面で違いはありますか?
その間 ドキュメンテーション は大いに改良されました。
ハンドラーを使ったAndroidバックグラウンド処理に関するチュートリアルとして、VogellaサイトのAsyncTask and Loaders はそれを述べています。
Handler
クラスはスレッドへの登録に使用でき、このスレッドにデータを送信するための簡単なチャネルを提供します。
AsyncTask
クラスは、バックグラウンドプロセスの作成とメインスレッドとの同期をカプセル化します。実行中のタスクの進行状況の報告もサポートします。
そしてThread
は基本的にマルチスレッドの中心的な要素であり、開発者はこれを次のようなデメリットとともに使用できます。
Javaスレッドを使用する場合は、独自のコードで次の要件を処理する必要があります。
- ユーザインタフェースに結果をポストバックした場合はメインスレッドとの同期
- スレッドをキャンセルするためのデフォルトなし
- デフォルトのスレッドプールなし
- Androidで設定変更を処理するためのデフォルトなし
そしてAsyncTask
に関しては、 Android Developer's Reference によれば、
AsyncTask
は、UIスレッドの適切で簡単な使用を可能にします。このクラスを使用すると、スレッドやハンドラを操作しなくても、バックグラウンド操作を実行して結果をUIスレッドに公開できます。
AsyncTask
は、Thread
およびHandler
を囲むヘルパークラスになるように設計されており、汎用スレッドフレームワークを構成するものではありません。 AsyncTasksは理想的には短い操作(せいぜい数秒)のために使用されるべきです。スレッドを長期間実行し続ける必要があるならば、Java.util.concurrentパッケージによって提供されるような様々なAPIを使うことが強く勧められますExecutor、ThreadPoolExecutor、およびFutureTask。
2015年5月更新:このトピックをカバーしている一連の優れた講義を見つけました。
これはGoogleの検索です: ダグラスシュミット講演Android同時性と同期
これはYouTubeでの 最初の講義のビデオです
これはすべての一部ですCS 282(2013):Android用システムプログラミング from Vanderbilt University。これが YouTubeプレイリストです
ダグラスシュミットは優秀な講師のようです
重要:スレッドの問題を解決するためにAsyncTask
を使用することを検討している時点では、まず最初にcheck out ReactiveX/RxAndroid
=より適切なプログラミングパターンの場合。概観を得るための非常に良いリソースは、 Android用RxJava 2を学習することです 。
AsyncTask
とHandler
のソースコードを見ると、それらのコードが純粋にJavaで書かれているのがわかります。 (もちろん、いくつか例外がありますが、それは重要な点ではありません。)
そのためAsyncTask
やHandler
には魔法はありません。開発者としての仕事を簡単にするだけです。
たとえば、プログラムAがメソッドA()を呼び出す場合、メソッドA()はプログラムAとは別のスレッドで実行することができます。
Thread t = Thread.currentThread();
int id = t.getId();
なぜあなたは新しいスレッドを使うべきなのでしょうか。あなたはそれをグーグルすることができます。多くの理由があります。
それで、Thread
、AsyncTask
、およびHandler
の違いは何ですか?
AsyncTask
とHandler
はJavaで書かれているため(内部的にはThread
を使用します)、Handler
またはAsyncTask
を使用してできることはすべてThread
を使用しても実現できます。
Handler
とAsyncTask
は、本当に役に立ちますか?
最も明白な理由は、呼び出し元スレッドとワーカースレッドの間の通信です。 (Caller Thread:タスクを実行するためにWorker Threadを呼び出すスレッド。CallerThreadは必ずしもUIスレッドである必要はありません)。もちろん、他の方法で2つのスレッド間で通信することもできますが、スレッドの安全性の問題から多くの不利益(および危険性)があります。
それがHandler
とAsyncTask
を使うべき理由です。彼らはあなたのためにほとんどの仕事をします、あなたはただどのメソッドをオーバーライドするべきかを知る必要があります。
Handler
とAsyncTask
の違いは次のとおりです。Caller threadがI Threadの場合はAsyncTask
を使用します。これはAndroidのドキュメントが言うことです:
AsyncTaskを使用すると、UIスレッドを適切かつ簡単に使用できます。このクラスを使用すると、スレッドやハンドラを操作しなくても、バックグラウンド操作を実行して結果をUIスレッドに公開できます。
2点を強調したい。
1)UIスレッドの使いやすさ(つまり、呼び出し元スレッドがUIスレッドの場合に使用).
2)ハンドラを操作する必要はありません。 (意味:AsyncTaskの代わりにHandlerを使用できますが、AsyncTaskの方が簡単です)。
この投稿にはまだ私はまだ話していないことがたくさんあります。たとえば、UI Threadとは何ですか、それがなぜそれが簡単なのか。あなたはそれぞれの種類の背後にあるいくつかの方法を知っていてそれを使用しなければなりません。
@:Androidのドキュメントを読むと、次のように表示されます。
ハンドラを使用すると、スレッドのMessageQueueに関連付けられているMessageオブジェクトおよびRunnableオブジェクトを送信して処理できます。
彼らは最初は奇妙に思えるかもしれません。各スレッドがそれぞれのメッセージキューを持っていることを理解してください(to doリストのように)、そしてスレッドは各メッセージを受け取り、メッセージキューが空になるまでそれを行います(あなたが仕事を終えて寝るように)。そのため、Handler
が通信するときには、呼び出し元スレッドにメッセージを送信するだけで、処理を待機します。複雑ですか? Handler
は安全な方法で呼び出し側のスレッドと通信できることを忘れないでください。
徹底的に見た後、それは率直です。
AsyncTask
:
それはスレッドを使う簡単な方法ですJavaスレッドモデルについて何も知らずに。 AsyncTask
は、ワーカースレッドとメインスレッドに関連するさまざまなコールバックを提供します。
次のような小さな待機操作に使用します。
Handler
:
Androidにアプリケーションをインストールすると、そのアプリケーション用のMAIN UI Threadというスレッドが作成されます。すべてのアクティビティはそのスレッド内で実行されます。 Androidのシングルスレッドモデルのルールでは、そのアクティビティ内で定義されている別のスレッドのUI要素(ビットマップ、テキストビューなど)に直接アクセスすることはできません。
ハンドラを使用すると、他のバックグラウンドスレッドからUIスレッドと通信することができます。 Androidは他のスレッドがUIスレッドと直接通信することを許可していないため、これはAndroidで役に立ちます。ハンドラは、スレッドのMessageQueueに関連付けられているMessageオブジェクトおよびRunnableオブジェクトを送信および処理できます。各Handlerインスタンスは、単一のスレッドとそのスレッドのメッセージキューに関連付けられています。新しいHandlerが作成されると、それを作成しているスレッドのスレッド/メッセージキューにバインドされます。
それはに最適です:
Thread
:
それではスレッドについて話しましょう。
スレッドはAsyncTask
とHandler
の両方の親です。両方とも内部的にthreadを使用します。つまり、AsyncTask
やHandler
のように独自のスレッドモデルを作成することもできますが、それにはの知識が必要です。/Javaのマルチスレッド実装。
AsyncTask
は、何らかのバックグラウンド計算を行い、結果をUIスレッドに発行するために使用されます(オプションの進行状況の更新と共に)。あなたはUIに関心がないので、Handler
またはThread
がより適切であると思われます。
Thread
のHandler
メソッドを使用して、バックグラウンドのpost
を生成し、メッセージをメインスレッドに渡すことができます。
Androidは標準のJavaスレッドをサポートします。標準のスレッドとパッケージ“ Java.util.concurrent
”のツールを使ってアクションをバックグラウンドにすることができます。唯一の制限は、バックグラウンドプロセスからUIを直接更新できないことです。
バックグラウンドタスクからUIを更新する必要がある場合は、Android固有のクラスをいくつか使用する必要があります。これにはクラス「Android.os.Handler
」またはクラス「AsyncTask
」を使用できます。
クラス“ Handler
”はUIを更新できます。ハンドルは、メッセージを受信して実行可能ファイルを処理するためのメソッドを提供します。ハンドラーを使用するには、それをサブクラス化し、メッセージを処理するためにhandleMessage()
をオーバーライドする必要があります。 Runable
を処理するには、メソッドpost();
を使用することができます。アクティビティに必要なハンドラのインスタンスは1つだけです。
スレッドはメソッドsendMessage(Message msg)
またはsendEmptyMessage
を介してメッセージを投稿できます。
コンテンツをダウンロードしたりバックグラウンドで実行できる操作を実行する必要があるActivity
がある場合、AsyncTask
を使用すると、レスポンシブユーザーインターフェイスを維持し、それらの操作の進行状況をユーザーに公開できます。
詳細については、これらのリンクを見てください。
http://mobisys.in/blog/2012/01/Android-threads-handlers-and-asynctask-tutorial/
http://www.slideshare.net/HoangNgoBuu/Android-thread-handler-and-asynctask
Thread
:
UI Threadに影響を与えることなく、長時間実行されるバックグラウンドタスクに新しいThread
を使用できます。 Java Threadから、UI Threadを更新することはできません。
Normal Thread はAndroidアーキテクチャにはあまり役に立ちませんので、スレッド化のためのヘルパークラスが導入されました。
あなたの質問に対する答えは Threading performance ドキュメントのページにあります。
ハンドラ :
Handler
を使用すると、スレッドのRunnable
に関連付けられているMessageオブジェクトおよびMessageQueue
オブジェクトを送信および処理できます。各Handler
インスタンスは、単一のスレッドとそのスレッドのメッセージキューに関連付けられています。
Handler
には2つの主な用途があります。
メッセージとランナブルが将来のある時点で実行されるようにスケジュールする。
自分のスレッドとは異なるスレッドで実行されるアクションをエンキューする。
AsyncTask
は、UIスレッドの適切で簡単な使用を可能にします。このクラスを使用すると、スレッドやハンドラを操作しなくても、バックグラウンド操作を実行して結果をUIスレッドに公開できます。
欠点:
デフォルトでは、アプリは作成したすべてのAsyncTask
オブジェクトを単一のスレッドにプッシュします。したがって、それらはシリアルに実行され、メインスレッドと同様に、特に長い作業パケットがキューをブロックする可能性があります。このため、5ミリ秒の長さより短い作業項目を処理するにはAsyncTaskを使用してください。
AsyncTask
オブジェクトは、暗黙的な参照の問題に対する最も一般的な違反者です。 AsyncTask
オブジェクトは、明示的な参照に関連するリスクも提示します。
より長いスレッドで作業ブロックを実行するためのより伝統的なアプローチ(AsyncTaskとは異なり、5msのワークロードで使用する必要があります)、およびそのワークフローを手動で管理するための機能が必要です。ハンドラスレッドは事実上、キューから作業を取得してそれを操作する長期実行スレッドです。
このクラスは、スレッドのグループの作成を管理し、それらの優先順位を設定し、作業がそれらのスレッド間でどのように分散されるかを管理します。作業負荷が増加または減少すると、クラスは作業負荷に適応するためにより多くのスレッドをスピンアップまたは破棄します。
ワークロードがもっと多く、単一のHandlerThread
で十分でない場合は、ThreadPoolExecutor
を選択できます。
ただし、サービス内でソケット接続を実行したいのですが。これはハンドラーまたはスレッド、あるいはAsyncTaskでさえ実行されるべきですか? UIの操作はまったく必要ありません。使用するパフォーマンスの面で違いはありますか?
UIの操作は必要ないので、AsyncTask
に移動することはできません。通常のスレッドはあまり有用ではないので、HandlerThread
が最良の選択肢です。ソケット接続を維持しなければならないので、メインスレッドのHandlerはまったく役に立ちません。 HandlerThread
を作成し、Handler
のルーパーからHandlerThread
を取得します。
HandlerThread handlerThread = new HandlerThread("SocketOperation");
handlerThread.start();
Handler requestHandler = new Handler(handlerThread.getLooper());
requestHandler.post(myRunnable); // where myRunnable is your Runnable object.
あなたがUIスレッドに戻って通信したい場合は、応答を処理するためにもう一つのハンドラを使用することができます。
final Handler responseHandler = new Handler(Looper.getMainLooper()) {
@Override
public void handleMessage(Message msg) {
//txtView.setText((String) msg.obj);
Toast.makeText(MainActivity.this,
"Foreground task is completed:"+(String)msg.obj,
Toast.LENGTH_LONG)
.show();
}
};
あなたのRunnable
に、あなたは追加することができます
responseHandler.sendMessage(msg);
実装に関する詳細はこちらにあります。
私の考えでは、スレッドはソケット接続を行うための最も効率的な方法ではありませんが、実行中のスレッドに関しては最も機能的です。経験上、スレッドを長時間実行すると、デバイスが非常にホットでリソース集約的になるためです。簡単なwhile(true)
でさえ数分で電話を熱します。 UIのやりとりは重要ではないと言うのなら、おそらくAsyncTask
は長期プロセス向けに設計されているので良いでしょう。これは私の意見です。
UPDATE
私の上記の答えを無視してください!私は2011年にこの質問に答えました。上記の私の答えは誤解を招くものであり、間違っていると見なされます。多くの人が私の訂正の下でそれについてコメントしたので私はそれをそこに残しています、そして私は私のレッスンを学びました。
このスレッドには他にも優れた回答がありますが、少なくとももっと適切な回答をします。通常のJava Thread
を使用しても問題ありません。ただし、間違った方法で実行するとプロセッサに負荷がかかる可能性があるため、実装方法には細心の注意を払う必要があります(最も顕著な症状は、デバイスが過熱することです)。 AsyncTask
sは、バックグラウンドで実行したいほとんどのタスクにとって非常に理想的です(一般的な例はディスクI/O、ネットワークコール、データベースコールです)。ただし、AsyncTask
sは、ユーザーがアプリを閉じた後やデバイスをスタンバイにした後も継続する必要がある可能性がある、特に長いプロセスには使用しないでください。ほとんどの場合、UIスレッドに属さないものはすべてAsyncTask
で処理できます。
AsyncTask
は、バックグラウンドで行われる操作を数秒以内で実行するように設計されています(サーバーからのメガバイト単位のファイルダウンロードまたはfile IO操作などのCPU集中処理タスクにはお勧めできません)。長時間実行する操作を実行する必要がある場合は、Javaネイティブスレッドを使用することを強くお勧めします。 Javaはあなたが必要なことをするためにあなたに様々なスレッド関連クラスを提供します。 UIスレッドを更新するにはHandler
を使用します。
public class RequestHandler {
public String sendPostRequest(String requestURL,
HashMap<String, String> postDataParams) {
URL url;
StringBuilder sb = new StringBuilder();
try {
url = new URL(requestURL);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setReadTimeout(15000);
conn.setConnectTimeout(15000);
conn.setRequestMethod("POST");
conn.setDoInput(true);
conn.setDoOutput(true);
OutputStream os = conn.getOutputStream();
BufferedWriter writer = new BufferedWriter(
new OutputStreamWriter(os, "UTF-8"));
writer.write(getPostDataString(postDataParams));
writer.flush();
writer.close();
os.close();
int responseCode = conn.getResponseCode();
if (responseCode == HttpsURLConnection.HTTP_OK) {
BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream()));
sb = new StringBuilder();
String response;
while ((response = br.readLine()) != null){
sb.append(response);
}
}
} catch (Exception e) {
e.printStackTrace();
}
return sb.toString();
}
private String getPostDataString(HashMap<String, String> params) throws UnsupportedEncodingException {
StringBuilder result = new StringBuilder();
boolean first = true;
for (Map.Entry<String, String> entry : params.entrySet()) {
if (first)
first = false;
else
result.append("&");
result.append(URLEncoder.encode(entry.getKey(), "UTF-8"));
result.append("=");
result.append(URLEncoder.encode(entry.getValue(), "UTF-8"));
}
return result.toString();
}
}
ここで例を挙げて質問に答えてみましょう:) - MyImageSearch [メインアクティビティ画面の画像をここで参考にしてください - 編集テキスト/検索ボタン/グリッド表示を含む]
MyImageSearchの説明 - ユーザーが編集テキストフィールドに詳細を入力して検索ボタンをクリックすると、flickrが提供するWebサービスを介してインターネット上の画像が検索されます(必要なのは]キー= /シークレットトークンを取得するためにそこに登録するには - 検索のために、グリッドビューをロードするために使用する個々の画像のURLを含むHTTP RequestとGET JSON Dataを返信します。
私の実装 - メインアクティビティでは、AsyncTaskを拡張してdoInBackGroundメソッドでHTTPリクエストを送信し、JSONレスポンスを取得してローカルのFlickrItemのArrayListを更新するインナークラスを定義します。 (BaseAdapterを拡張する)FlickrAdapterを介して私のGridViewを更新し、グリッドビューをリロードするためにAsyncTaskのonPostExecute()でadapter.notifyDataSetChanged()を呼び出すために使用します。ここではHTTPリクエストがブロッキングコールであることに注意してください。そのため、私はAsyncTaskを介してそれを行いました。そして、パフォーマンスを向上させるためにアダプタにアイテムをキャッシュしたり、SDカードに保存したりすることができます。私がFlickrAdapterで膨らませるグリッドは、私の実装にはプログレスバーと画像ビューを含みます。以下に、私が使ったmainActivityのコードがあります。
質問への回答 - 個々の画像を取得するためのJSONデータを取得したら、Handlers、Threads、またはAsyncTaskを使用して画像をバックグラウンドで取得するロジックを実装できます。ダウンロードした私の画像はUI /メインスレッドに表示される必要があるので、コンテキストにアクセスできないため、単純にスレッドを使用することはできません。 FlickrAdapterでは、私が考えることができる選択肢:
ここでのソースコード:
public class MainActivity extends ActionBarActivity {
GridView imageGridView;
ArrayList<FlickrItem> items = new ArrayList<FlickrItem>();
FlickrAdapter adapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
imageGridView = (GridView) findViewById(R.id.gridView1);
adapter = new FlickrAdapter(this, items);
imageGridView.setAdapter(adapter);
}
// To avoid a memory leak on configuration change making it a inner class
class FlickrDownloader extends AsyncTask<Void, Void, Void> {
@Override
protected Void doInBackground(Void... params) {
FlickrGetter getter = new FlickrGetter();
ArrayList<FlickrItem> newItems = getter.fetchItems();
// clear the existing array
items.clear();
// add the new items to the array
items.addAll(newItems);
// is this correct ? - Wrong rebuilding the list view and should not be done in background
//adapter.notifyDataSetChanged();
return null;
}
@Override
protected void onPostExecute(Void result) {
super.onPostExecute(result);
adapter.notifyDataSetChanged();
}
}
public void search(View view) {
// get the flickr data
FlickrDownloader downloader = new FlickrDownloader();
downloader.execute();
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
}
私の答えが、細かい詳細を理解するのに長い間役立つことを願っています。
どちらを選択するかは、要件に基づいて異なります
ハンドラーは、主に他のスレッドからメインスレッドに切り替えるために使用され、ハンドラーは実行可能なタスクをキューにポストするルーパーに接続されます。あなたが既に他のスレッドにいてメインスレッドに切り替える場合、非同期タスクまたは他のスレッドの代わりにハンドルが必要です
ルーパーではないメインスレッド以外で作成されたハンドラーがハンドルを作成するときにエラーが発生しない場合、そのスレッドはロッパーにする必要があります
AsyncTaskは、バックグラウンドスレッドで実行され、その結果をメインスレッドに渡すコードを数秒間実行するために使用されます** * AsyncTask Limitations 1。ローダーにはこの制限はありませんが、アクティビティが破棄されても実行され続けます。2.すべての非同期タスクは、実行のために同じバックグラウンドスレッドを共有し、アプリのパフォーマンスにも影響します
Threadはアプリでもバックグラウンドで使用されますが、メインスレッドでコールバックすることはありません。要件が1つのスレッドではなくいくつかのスレッドに適しており、タスクを何度も実行する必要がある場合は、スレッドプールエグゼキューターの方が適しています。
スレッド
アプリを起動すると、コードを実行するためのプロセスが作成されます。コンピューティングリソースを効率的に使用するために、プロセス内でスレッドを開始して、一度に複数のタスクを実行することができます。そのため、スレッドを使用すると、アイドル時間なしでCPUを効率的に利用して効率的なアプリケーションを構築できます。
Androidでは、すべてのコンポーネントはメインスレッドと呼ばれる単一のスレッド上で実行されます。 Androidのシステムはタスクをキューに入れ、メインスレッドでそれらを一つずつ実行します。長時間実行されているタスクが実行されると、アプリが応答しなくなります。
これを防ぐために、ワーカースレッドを作成し、バックグラウンドまたは長時間実行タスクを実行することができます。
ハンドラ
Androidはシングルスレッドモデルを使用しているため、UIコンポーネントはスレッドセーフではない状態で作成されるので、UIコンポーネントはメインスレッドでのみ更新されます。 UIコンポーネントはメインスレッドで実行されるため、ワーカースレッドで実行されるタスクはUIコンポーネントを変更できません。これが、Handlerが登場するところです。 Looperの助けを借りてハンドラーは、新しいスレッドまたは既存のスレッドに接続し、接続されたスレッドでそれが含むコードを実行することができます。
ハンドラはスレッド間通信を可能にします。 Handlerを使用すると、バックグラウンドスレッドはそれに結果を送信でき、メインスレッドに接続されているハンドラはメインスレッドのUIコンポーネントを更新できます。
AsyncTask
Androidが提供するAsyncTaskはスレッドとハンドラの両方を使用して、バックグラウンドで単純なタスクを実行し、バックグラウンドスレッドからメインスレッドに結果を簡単に更新できます。
例として Androidスレッド、ハンドラー、asynctaskおよびスレッドプール を参照してください。
Handler
- スレッド間の通信媒体です。 Androidでは、ハンドラを介してメッセージを作成および送信することによってメインスレッドと通信するために主に使用されます。
AsyncTask
- バックグラウンドスレッドで長時間実行されるアプリケーションを実行するために使用されます。 nAsyncTask
を使用すると、バックグラウンドスレッドで操作を実行し、アプリケーションのメインスレッドで結果を取得できます。
Thread
- 同時実行性と最大のCPU使用率を達成するための軽量プロセスです。 Androidでは、スレッドを使用してアプリのUIに触れないアクティビティを実行できます