Android 非同期処理についてまとめてみた
Androidには、UIに影響を与えないよういくつか非同期処理が用意されています。
今回は非同期処理の代表的な
・Service
・IntentService
・HandlerThread
について違いを踏まえながらまとめます!
非同期処理について(http://codezine.jp/article/detail/9746)
まずはServiceとIntentServiceについて説明します。
■ Service
・メリット
– Activityに依存せずに長時間のバックグラウンド処理に向いている。
– Contextを持っている。
・デメリット
– メインスレッド上(UIスレッド上)で動作するため、重い処理を行うと画面のレスポンスが遅くなったり、アプリが落ちる。
※Serviceの優位性
ServiceはActivityと同一のスレッドで動いているため、
Serviceを使わずにActivityからスレッドを生成すればいいのでは?と思った方がいるのではないでしょうか?
重要なのはServiceはContext(アプリの状態)を保持していることです。
Activityからでもスレッドは生成し処理を行うことは可能ですが、Activityが終了してしまうと、Activityに関連したContext(アプリの状態を保持した情報)は使用できなくなります。
そのため、Contextを利用したバックグラウンド処理にはServiceを使う必要があります。
■ IntentService
・メリット
– Activityに依存せず非同期の処理に向いている。
– 内部にHandlerThreadを持っているため、メインスレッドとは別のスレッド上で逐次処理を行う。
ServiceとIntentServiceの違いを見てみる
下記にServiceを使った処理とIntentServiceを使った処理を記載します。
ActivityからIntentを使ってService/IntentServiceを呼び出します。
・Activity
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
public class MainActivity extends AppCompatActivity implements View.OnClickListener { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // リスナーをセット findViewById(R.id.servicebutton).setOnClickListener(this); findViewById(R.id.intentServicebutton).setOnClickListener(this); @Override public void onClick(View v) { if (v.getId() == R.id.servicebutton) { //Serviceクラスを起動させる。通知を表示するServiceを起動 Intent intent = new Intent(this, HelloIntentService.class); //Intent intent = new Intent(this, MyService.class); intent.setAction("show"); startService(intent); } else if (v.getId() == R.id.intentServicebutton) { //IntentServiceクラスを起動させる。通知を表示するIntentServiceを起動 Intent intent = new Intent(this, MyIntentService.class); intent.setAction("show"); startService(intent); } } } |
・Service(あえてfor文を使い重い処理を行う)
1 2 3 4 5 6 7 8 |
public class MyService extends Service { public MyService() { } @Override public int onStartCommand(Intent intent, int flags, int startId) { //重い処理を行う。 return START_NOT_STICKY; } |
→アプリが落ちる。
・IntentService(あえてfor文を使い重い処理を行う)
1 2 3 4 5 6 7 8 9 10 |
public class MyIntentService extends IntentService { public MyIntentService() { super("HelloIntentService"); } @Override protected void onHandleIntent(Intent intent) { //重い処理を行う。 } } |
→UIに影響を与えないため、アプリは落ちない。
次にHandlerとHandlerThreadについて説明します。
HandlerThreadについて
HandlerThreadは内部にLooperを持ち、Handlerによって送られてきたメッセージを逐次処理するための仕組みです。わからない用語が出てきたので、まずは”Looper”と”Handler”について説明します。
LooperとHandlerについて
Looperとは
Looperとは内部にMessageキューを持ち、順番にキューから取り出したメッセージを処理する仕組みです。
これはAndroidの基本的な仕組みとなっておりActivityやServiceなどもこのLooper上で動作しています(デバックしてみるとわかります。はい)。
そしてこのActivityやServiceは特別なメインルーパー(メインスレッド)で動作しており、画面に関するウィジェットの変更はメインルーパーで行わなければなりません。
※別スレで行うとエラーが出ます。
Handlerとは
HandlerとはそのLooperにMessage(タスク)を届けるためのメッセンジャーです。
HandlerとHandlerThreadの違いを見てみる
Handlerはメインスレッド上で行われています。
HandlerThreadは新たにThreadを生成して、そこで処理を行います。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
public class HandlerDefault extends AppCompatActivity { private String s; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_handler_default); Handler handler = new Handler(); handler.post(new Runnable() { @Override public void run() { ////重たい処理を記述 s = Thread.currentThread().getName(); } }); } } |
→デバックして変数sの中身を確認する。
s = main
メインスレッド上の処理のため、重たい処理を記載するとアプリは落ちる。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
public class HandlerThreadDefault extends AppCompatActivity { private String s; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_handler_thread_default); // 別スレ生成 -> 開始 HandlerThread handlerThread = new HandlerThread("other"); handlerThread.start(); //作成したHandlerThread(別スレ)内部のLooperを引数として、HandlerThread(のLooper)にメッセージを送るHandlerを生成する。 Handler handler = new Handler(handlerThread.getLooper()); //Handlerのpostメソッドでメッセージ(タスク:重たい処理)を送信する。 handler.post(new Runnable() { @Override public void run() { //重たい処理を記述 s = Thread.currentThread().getName(); } }); } } |
→デバックして変数sの中身を確認する。
s = other
別スレッドを生成しているため、重たい処理を記載してもUIに影響を与えることはなくアプリが落ちる心配はない。
なるほどなるほど、ここで疑問。
Q 画面に関する操作はメインスレッド上で行わなければならないとのこと。もし、別スレッド上で行ったらどうなるのだろうか?
1 2 3 4 5 6 7 8 |
@Override public void run() { System.out.println(Thread.currentThread().getName()); s = Thread.currentThread().getName(); Log.v("hoge", "thread name:" + Thread.currentThread().getName()); //変更箇所:別スレッド(other)からメインスレッドの画面を切り替える処理を行ってみる。できるのかな? View v = findViewById(R.id.button); } |
・結果
問題なく、ボタンが読み込まれました。
Handlerの引数(メインスレッドのLooper)にHandlerThreadのLooper処理の結果を渡してるから、
別スレッドの処理結果をメインスレッドに渡しているからなんだ。
1 |
Handler handler = new Handler(handlerThread.getLooper()); |
(http://ichitcltk.hustle.ne.jp/gudon2/index.php?
pageType=file&id=Android010_Handler)
手順
1.別スレッド(HandlerThread)を生成
2.別スレッド開始
3.HandlerThreadインスタンス から Looperインスタンス 取得
4.Handlerインスタンスを生成(3で取得した Looperインスタンス を 引数指定)
5.4 で作成した Handlerインスタンス を使用(Handler#post 等)
参考
・http://daichan4649.hatenablog.jp/entry/20111004/1317724067
・https://realm.io/jp/news/android-thread-looper-handler/
UIスレッドからのみ画面操作が可能
・http://dev.classmethod.jp/etc/22853/

関連記事
-
-
TypeScriptについてまとめてみた
はじめに JavaScript がとりあえずそのまま動くので、雰囲気で使ってしまいがちな TypeScript。初心者向けに基本的なことをまとめてみました。 TypeScript って何? TypeScript はマイクロソフトが開発したプログラミング言語で、オープンソースでメンテナンスされています …
-
-
意外と知らないかも? Chrome DevTools の機能10選
みんな使っている Chrome DevTools。 Web開発やトラブルシューティングには必須ですが、便利な機能を知らないで使っている人がいたり、Web で使い方を調べても古い情報だったりすることがあるので、部内で Chrome DevTools についての勉強会を開催しました。 ここでは、その中か …
-
-
modern.IEを使ってMac上でWindows10を動かす
Microsoftが提供している modern.IE というプロジェクトがある。そこで提供されている仮想環境を使って、MacにWindows10をインストールしてみる。ちなみに、このプロジェクトの本来の目的はInternet Explorerの表示確認やデバッグの支援。 VirtualBoxの準備 …
-
-
kubernetes の全ノード上で同じコンテナを動かす
今回は、kubernetes上で同一コンテナを全ノードで動かす方法を紹介したいと思います。kubernetes自体の起動方法はここでは割愛します。 はじめに 以前、CoreOSのFleet上でmackerel-agentを動かすということを行いました。今回は、kubernetes上で同じようにクラス …
-
-
【HTML5】4ツール出力ファイルサイズ比較
こんにちは、近江です。 前回もHTML5のSwiffyについて書かせて頂きましたが、まだまだHTML5について調査しています。 今回はSwiffyを含めた4つのHTML5系ツールで、同じ素材で同じアニメーションを作成した時のファイルサイズを比較したいと思います。 何故ファイルサイズの比較をするかと言 …
-
-
Selenium × PHP でテスト自動化!【環境構築編】
はじめに みなさんこんにちは、プロダクト開発本部の亀梨です。 普段はXmediaOneというメディアプランニング・広告運用管理・トラッキング・マーケティング分析を行う 統合プラットフォームの開発を担当しています。 テスト自動化の背景 わたくしが担当するXmediaOneでは品質担保のために①コードベ …
-
-
Scala入門 基礎編「Scalaの書き方を理解しよう」 – PHP使いからScala使いへ転身!
はじめに みなさんこんにちは、プロダクト開発本部の亀梨です。 普段はXmediaOneというメディアプランニング・広告運用管理・トラッキング・マーケティング分析を行う 統合プラットフォームの開発を担当しています。 さて、今回はScala入門第二弾として、Scalaの書き方を紹介する基礎編をお送りしま …
-
-
Bootstrapのモーダル機能で多重表示する際に解決しなければならない2つの問題
はじめに みなさんこんにちは、プロダクト開発本部の亀梨です。 普段はXmediaOneというメディアプランニング・広告運用管理・トラッキング・マーケティング分析を行う 統合プラットフォームの開発・保守を担当しています。 エンジニアの皆さん、デザインってどうしてます? わたくしはプライベートでとあるW …
-
-
gulp.jsで広告タグの開発環境を整える
SEOの観点から、サイト表示速度の高速化のためJavaScriptファイルから不用な空白や改行、 コメントを除去したりやローカル変数名を短縮するminifyが奨励されていますが、 これはタスクランナーのgulp.jsとプラグインを使って自動化する事が可能です。 ※gulpの基本的な使い方については下 …
-
-
(社内新卒・PHPビギナー向け)MacでPHP7開発環境を構築しよう!
はじめに みなさんこんにちは、プロダクト開発本部の亀梨です。 普段はXmediaOneというメディアプランニング・広告運用管理・トラッキング・マーケティング分析を行う 統合プラットフォームの開発を担当しています。 えっ!?新卒のプログラミング研修はPHPで行われるって?!俺の得意言語やないか!! は …