素人のアンドロイドアプリ開発日記

ActivityとThreadについて

2011.04.13

Threadを使ったプラグラムを書いていると、GUI(グラフィックユーザーインターフェース)をいじる場合には、handlerを使わなくてはいけない。

と言う問題につきあたって、

AndroidのHandlerとは何か?

でhandlerの中身の理解をしようという結論になったのですが、「AndroidアプリのUIはシングル・スレッド モデルです。」と書いてあって、よく読むとAndroidのActivityは言わば、Threadをひとつ動かしている。と言う結論に達しました。ですが、Activityってrun()とかないし。。

と言う事を今回、調べました。

 

簡単にthreadを勉強をすると、

Thread trd = new Thread(new Runnable(){
 public void run() {}
});
trd.start();

と言う構成で、runの中身を上から順番に実行をしていく。

sample

Thread trd = new Thread(new Runnable(){
 public void run() {
 sampleFunc();
 try{
 Thread.sleep(1000);
 }catch(Exception e){}
 sampleFunc();
 try{
 Thread.sleep(1000);
 }catch(Exception e){}
 sampleFunc();
 }
});
trd.start();

上記で一秒毎にsampleFunc()が実行されるthreadを作成できました。

 

Activityにはrun()と言う動く部分がないので、onCreateのファンクションの中に

try{
 Thread.sleep(1000);
}catch(Exception e){}

を記載してみると、エラーなく登録ができてページを開くと、1秒の暗い状態の後に表示がされました。

つまり、1秒間のsleepが実行されていた事がわかりました。onCreateの終了までは表示に関しては、文字などを変更をしても確認する事ができませんでした。(表示されませんでした。)

Log.d("ThreadPra", "1");
try{
 Thread.sleep(2000);
}catch(Exception e){}
Log.d("ThreadPra", "2");

でログを取得してみると

04-13 08:46:27.063: DEBUG/ThreadPra(1332): 1
04-13 08:46:29.107: DEBUG/ThreadPra(1332): 2

ログでは時間がsleepの後は2秒経過後に実行をされているのを確認できました。

以上より、ライフサイクルの根幹には、Threadが存在しているのが分かりました。onCreateもThreadのrunのように使えました。

「基本のthreadからのGUIの変更はできるが、他のthreadからできない」と書いてあるのだけど、言うなれば、「onCreateとかでGUIの変更はしてもいいけど、Threadを他に作成をした場合には、GUIの変更はバグの原因になるかもしてないので、androidのアプリでは使えなくなってる。」と言う仕様だと思います。(個人的な意見です。)

ただ、やはりthreadで時間毎に変更をする必要が出てきてしまったりする場合に、回避する方法として、handlerと言うクラスがありますよ。と言うのがhandlerかと思います。

Handlerの使い方もついでに紹介します。

Thread trd = new Thread(new Runnable(){
 public void run() {};
});
trd.start();

をonCreate等で作成します。新しいThreadを作成するメリットとしては、onCreateの中のファンクションが全て終わるまでは、何も表示されない事が上記で分かりましたが、別のThreadにファンクションを移す事で、すぐに要素が表示されるようになります。今回はsleep()で擬似でファンクションの遅延を発生させていますが、画像の読み込みなどに有効です。また、threadの作成自体はonCreateの中で大丈夫です。

handlerに関しては、Runnableをpostするだけで使用できるのですが、下記のようなファンクションだと、なぜかうまく効きませんでした。

public void run() {
 handler.post(new Runnable() {
 @Override
 public void run() {
 textview1.setText("START");
 try{
 Thread.sleep(2000);
 }catch(Exception e){};
 textview1.setText("settingText1");
 try{
 Thread.sleep(2000);
 }catch(Exception e){};
 textview1.setText("settingText2");
 }
 });
}

Handlerは「Threadを実現する代替のもの」ではなく、「GUIをいじる為のもの」と考えるべきだと思います。下記のように変更します。

public void run() {
 handler.post(new Runnable() {
 @Override
 public void run() {
 textview1.setText("START");
 }
 });
 try{
 Thread.sleep(2000);
 }catch(Exception e){};
 handler.post(new Runnable() {
 @Override
 public void run() {
 textview1.setText("settingText1");
 }
 });
 try{
 Thread.sleep(2000);
 }catch(Exception e){}
 handler.post(new Runnable() {
 @Override
 public void run() {
 textview1.setText("settingText2");
 }
 });
}

これで、2秒毎にテキストを変更するthreadが生成されました。

 

以上を含んだサンプルです。

main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
 android:orientation="vertical"
 android:layout_width="fill_parent"
 android:layout_height="fill_parent"
 >
 <TextView 
 android:text="TextView" 
 android:id="@+id/textView1" 
 android:layout_width="wrap_content" 
 android:layout_height="wrap_content"></TextView>
</LinearLayout>

ThreadPra.java

package in.andante.threadpra;

import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.util.Log;
import android.widget.TextView;

public class ThreadPra extends Activity implements Runnable {

 TextView textview1;
 Thread trd;
 Handler handler;
 @Override
 public void onCreate(Bundle savedInstanceState) {
 super.onCreate(savedInstanceState);
 setContentView(R.layout.main);
 textview1 = (TextView)findViewById(R.id.textView1);
 handler = new Handler();
 textview1.setText("onCreateStart");
 Log.d("ThreadPra", "1");
 try{
 Thread.sleep(2000);
 }catch(Exception e){}
 Log.d("ThreadPra", "2");
 textview1.setText("onCreateFinish");
 Thread trd2 = new Thread(this);
 trd2.start();
 }

 public void run() {
 handler.post(new Runnable() {
 @Override
 public void run() {
 textview1.setText("runSTART");
 }
 });
 try{
 Thread.sleep(2000);
 }catch(Exception e){};
 handler.post(new Runnable() {
 @Override
 public void run() {
 textview1.setText("setText");
 }
 });
 try{
 Thread.sleep(2000);
 }catch(Exception e){}
 handler.post(new Runnable() {
 @Override
 public void run() {
 textview1.setText("runFINISH");
 }
 });
 }
}

以上です。

同じカテゴリの記事を紹介します

流れる背景を作るステータスバーの色を好きな色にするカメラの権限の取得をするpush通知の実装を確認をする為に、phpを書くしかないListView GridViewに下部にマージンをあけたい時よくつかうメモListViewの設定split で ドット文字列を、bitmapにするクラスを作ってみた。uriから画像の回転角度を取得するgridviewとlistviewで表示にalphaanimationを使ったら動かないのが存在する問題自分で変数を持つクラスを作ってコピーした時に参照まで渡してしまう問題でかい画像が表示されない。という問題interfaceをandroidで使ってみるフルスクリーンでナビゲーションバーまで消せるパソコンを買ったらする事点滅をさせるスクリプトJsonObjectを扱う時のtry catchが邪魔なのでシンプルにする2chのまとめアプリは気を付けろArrayAdapterの使い方setTimeOutを作るarraylistを並び替えAndroidの勉強で気を付けるべき6つの事staticで変数を持ちまわす時Androidで定規を作る時にサイズを確認してみる。TextureViewがゴミから神になった日ListViewの位置を変更しないで更新する方法animationをxmlで設定するのはアホなようだ。listを作るのがめんどい件について矩形の中の点の存在条件についてScrollViewのScrollToが効かない時Twitterのアプリを暗黙的Intentで狙いうちの巻勉強した内容をクラスにしてみてるText三角形の座標の包括判定をプログラムで実装前回作ったeasingを使って、translateアニメーションにイージングをかける。AndroidのデフォルトのアニメーションがダサいのでEasingをJavascriptから持ってきたmatrixを使って、回転をさせる時に中心点をずらす方法destoryとかで割と実行してるメモリリーク対策AnimationDrawable 動かないTextViewをセンター寄せにする。特定のアプリがインストールされているかを判別する方法surfacevierをaddviewすると、一瞬画面が点滅する件アニメーションで高さを変更listviewで押すとデフォルトで背景に色がつくのを抑止するline-heightをアンドロイドのtextviewで設定をする。listviewの区切り線を消すframelayoutだとmarginが効かない@android2.2アンドロイドのimageviewで背景が透けるという糞仕様を発見ウインドウのサイズを取得する方法decodeResourceは劣化する上に糞遅い。decodeResourceは劣化します。もう一度言います。decodeResourceは劣化します。

カテゴリー:androidアプリTips

公開中のアプリ、是非ダウンロードしてみてください

2chまとめのたね

RSSを利用してさまざまなブログの情報をキュレーションしてくれるアプリ

インストールする

ひらがな戦記

OPENGL ES2 を利用したカルタのソーシャルゲーム

インストールする