Androidにはコンテキストが多々出てくる。
ややこしいため、調べたことを記載。
コンテキストとは、アプリ環境のグローバルな情報へのインタフェース。
Contextクラスを利用して
アプリケーションのリソース、クラス、
アプリケーションレベルのオペレーション(アクティビティの起動、ブロードキャスト、インテントの受信など)
にアクセスすることができる。
現在のアプリやオブジェクトの状態取得できる窓口であるが、以下の3種類で取得できる。
・Activityクラスのthis (アクティビティ・コンテキスト)
・getApplicationContext() (アプリ・コンテキスト)
・getBaseContext() (ベース・コンテキスト)
(注1:ベース・コンテキストは、公式な名称ではなく、勝手に命名してます。)
(注2:サービスクラスのthisは、何コンテキストと言うのか不明)
アクティビティやサービスのthisは、
アプリコンテキストとベースコンテキストの参照を持っていることを確認。
(※参照を持っているだけで、アクティビティ・コンテキストが、
アプリ・コンテキストやベース・コンテキストを生成しているとは考えにくい)
なお、アクティビティやサービスは、Contextクラスを継承しているため、thisやContextメソッドが使用できる。
ところが、googleエンジニアの一人は、ベース・コンテキスト(getBaseContext)は使用しないで、と言っている。
(今まで、getBaseContext使っているところは、見直す必要がありそうだ)
アプリ・コンテキストおよび、アクティビティ・コンテキストのライフサイクルは、
アプリはアプリ、アクティビティはアクティビティのライフサイクルに依存する。
サービスの登録と解除に関しては、アクティビティ・コンテキストで登録したものは、
アクティビティ破棄時に、開発者がサービス解除を忘れても、フレームワークが解除するとのこと。
ただし、アプリ・コンテキストの場合は、解除わすれるとメモリリークになるとのこと。
Code-Diving
プログラムTIPを整理するためのメモ用ブログです。
2011年7月18日月曜日
2011年7月15日金曜日
定期的にIntentServiceを起動する
IntentServiceは、
Activityからの呼び出し時にAlarmManagerと併用することにより、
定期的な呼び出しを行うことができる。
AlarmManagerは、引数にPendingIntentを要求するため、
PendingIntentを取得する必要がある。
ただ、特に細かい設定はなく、サービスのIntentを型変換しているような感じだ。
■定期的に動くIntentServiceを作る(AlarmManaerを利用)
1)新規のAndroidプロジェクトを以下のように作成する。
「プロジェクト名」:AlarmManagerIntentService
「ビルドターゲット」:Android 1.6
「パッケージ名」:jp.co.example.alarmmanagerintentservice
「アクティビティ名」:AlarmManagerIntentServiceActivity
2)サービスクラスを作成する。
プロジェクトのsrcのパッケージ配下に、『MyIntentService』クラスを作成
ソース内容は以下の通り。
基本的には、MyIntentServiceクラスをIntentServiceクラスの継承クラスとする。
Seriviceの継承とは異なり、コンストラクターのみ強制オーバーライドであった。
Eclipseのコードアシスタントでは、第一引数ありのコンストラクタを生成してくれる、
しかし、
ActivityからAlarmManagerを利用して呼ぶ場合、引数なしのコンストラクタが必要である。
onHandleIntentメソッドには、ログを入れた。
これは、onHandleIntentがどのスレッドで動くか調べるためだ。
結果、onHandleIntentは、時間毎に新規スレッドが生まれる形で動作した。
以下のコードにおけるIntentServiceは、
Activityと同プロセスだが、別スレッドで動作している。
res\layout\main.xmlに、ボタンを2つ作成。
ソースは以下のようになる。
4)サービスをスタート/ストップするアクティビティを作る
以下の処理を行っている。
スタートボタン押下処理をstartAlarmServiceメソッドとした。
ストップボタン押下処理をstopAlarmServiceメソッドとした。
詳細は、ソースコードコメントに記載する。
全体のコードは以下の通り。
5)マニフェストでサービス許可する
AndroidManifest.xmlに<service>タグにサービスクラス名を指定して、以下のようにサービスを許可する。
Activityからの呼び出し時にAlarmManagerと併用することにより、
定期的な呼び出しを行うことができる。
AlarmManagerは、引数にPendingIntentを要求するため、
PendingIntentを取得する必要がある。
ただ、特に細かい設定はなく、サービスのIntentを型変換しているような感じだ。
■定期的に動くIntentServiceを作る(AlarmManaerを利用)
1)新規のAndroidプロジェクトを以下のように作成する。
「プロジェクト名」:AlarmManagerIntentService
「ビルドターゲット」:Android 1.6
「パッケージ名」:jp.co.example.alarmmanagerintentservice
「アクティビティ名」:AlarmManagerIntentServiceActivity
2)サービスクラスを作成する。
プロジェクトのsrcのパッケージ配下に、『MyIntentService』クラスを作成
ソース内容は以下の通り。
基本的には、MyIntentServiceクラスをIntentServiceクラスの継承クラスとする。
Seriviceの継承とは異なり、コンストラクターのみ強制オーバーライドであった。
Eclipseのコードアシスタントでは、第一引数ありのコンストラクタを生成してくれる、
しかし、
ActivityからAlarmManagerを利用して呼ぶ場合、引数なしのコンストラクタが必要である。
onHandleIntentメソッドには、ログを入れた。
これは、onHandleIntentがどのスレッドで動くか調べるためだ。
結果、onHandleIntentは、時間毎に新規スレッドが生まれる形で動作した。
以下のコードにおけるIntentServiceは、
Activityと同プロセスだが、別スレッドで動作している。
package jp.co.example.alarmmanagerintentservice; import android.app.IntentService; import android.content.Intent; import android.util.Log; public class MyIntentService extends IntentService { private final String TAG = this.getClass().getSimpleName(); public MyIntentService(String name) { super(name); // TODO 自動生成されたコンストラクター・スタブ Log.d(TAG, Thread.currentThread().getStackTrace()[2].getMethodName()); } public MyIntentService() { super("MyIntentService"); // TODO 自動生成されたコンストラクター・スタブ Log.d(TAG, Thread.currentThread().getStackTrace()[2].getMethodName()); } @Override protected void onHandleIntent(Intent intent) { // TODO 自動生成されたメソッド・スタブ Log.d(TAG, Thread.currentThread().getStackTrace()[2].getMethodName()); } }3)画面にスタートボタン、ストップボタンを作る
res\layout\main.xmlに、ボタンを2つ作成。
ソースは以下のようになる。
<?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" > <Button android:text="Alarm Start" android:id="@+id/start_button" android:layout_width="wrap_content" android:layout_height="wrap_content"></Button> <Button android:text="Alarm Stop" android:id="@+id/stop_button" android:layout_width="wrap_content" android:layout_height="wrap_content"></Button> </LinearLayout>
4)サービスをスタート/ストップするアクティビティを作る
以下の処理を行っている。
スタートボタン押下処理をstartAlarmServiceメソッドとした。
ストップボタン押下処理をstopAlarmServiceメソッドとした。
詳細は、ソースコードコメントに記載する。
全体のコードは以下の通り。
package jp.co.example.alarmmanagerintentservice; import android.app.Activity; import android.app.AlarmManager; import android.app.PendingIntent; import android.content.Context; import android.content.Intent; import android.os.Bundle; import android.util.Log; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; public class AlarmManagerIntentServiceActivity extends Activity { private final String TAG = this.getClass().getSimpleName(); Button alarmStartButton; Button alarmStopButton; /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); Log.d(TAG, Thread.currentThread().getStackTrace()[2].getMethodName()); setContentView(R.layout.main); findViews(); alarmStartButton.setOnClickListener(new OnClickListener() { public void onClick(View v) { // TODO 自動生成されたメソッド・スタブ startAlarmService(); } }); alarmStopButton.setOnClickListener(new OnClickListener() { public void onClick(View v) { // TODO 自動生成されたメソッド・スタブ stopAlarmService(); } }); } protected void findViews() { alarmStartButton = (Button)findViewById(R.id.start_button); alarmStopButton = (Button)findViewById(R.id.stop_button); } protected void startAlarmService() { Log.d(TAG, Thread.currentThread().getStackTrace()[2].getMethodName()); Context context = getBaseContext(); // サービスのIntentを生成 Intent intent = new Intent(context, MyIntentService.class); // PendingIntentを取得 PendingIntent pendingIntent = PendingIntent.getService( context, -1, // requestCode is currently not used intent, // 起動するサービスのIntent PendingIntent.FLAG_UPDATE_CURRENT //flags: FLAG_CANCEL_CURRENT :過去の設定をキャンセルし現在の設定を使う。 // FLAG_NO_CREATE :存在してなければnullを返す。新規作成しない。 // FLAG_ONE_SHOT :一度だけ使用できる。 // FLAG_UPDATE_CURRENT :過去の設定があればそれを使う。再設定しない。 ); AlarmManager alarmManager = (AlarmManager)context.getSystemService(ALARM_SERVICE); alarmManager.setInexactRepeating( AlarmManager.RTC, // type: // ELAPSED_REALTIME :SystemClock.elapsedRealtime() によるアラーム時間 (スリープを含む起動してからの時間) // ELAPSED_REALTIME_WAKEUP :ELAPSED_REALTIME と同様だが、スリープしている時は起きる // INTERVAL_DAY :一日間隔 // INTERVAL_FIFTEEN_MINUTES:15分間隔 // INTERVAL_HALF_DAY :半日間隔 // INTERVAL_HALF_HOUR :30分間隔 // INTERVAL_HOUR :一時間間隔 // RTC :System.currentTimeMillis() によるアラーム時間 (UTC) // RTC_WAKEUP :RTC と同様だが、スリープしている時は起きる System.currentTimeMillis(), // triggerAtTime 5000, // interval pendingIntent // operation ); } protected void stopAlarmService() { Log.d(TAG, Thread.currentThread().getStackTrace()[2].getMethodName()); Context context = getBaseContext(); // サービスのIntentを生成 Intent intent = new Intent(context, MyIntentService.class); // PendingIntentを取得 PendingIntent pendingIntent = PendingIntent.getService( context, -1, // requestCode is currently not used intent, PendingIntent.FLAG_UPDATE_CURRENT ); AlarmManager alarmManager = (AlarmManager)context.getSystemService(ALARM_SERVICE); alarmManager.cancel(pendingIntent); } }
5)マニフェストでサービス許可する
AndroidManifest.xmlに<service>タグにサービスクラス名を指定して、以下のようにサービスを許可する。
<application android:icon="@drawable/icon" android:label="@string/app_name"> (略) <service android:name=".MyIntentService"/> </application>
ラベル:
AlarmManager,
IntentService
別スレッドで動くIntentService(後始末が自動的)
Androidにはサービスという、Linux等でいうデーモンのような仕組みがある。
何もしないシンプルなサービスでは、Serviceクラスを継承した。
今回は、IntentServiceクラスを継承する。
2つの違いは、以下の通り。
・IntentServiceのonHandleIntentメソッドが、別スレッドで実行される(非同期)
非同期の関連キーワード:AsyncTask、Thread、Runnable
・IntentServiceは、処理が終わると、自動的にonDestroyメソッドが呼ばれサービスが停止すること。
■別スレッドで動くIntentServiceを作る
1)新規のAndroidプロジェクトを以下のように作成する。
「プロジェクト名」:IntentServiceTest0
「ビルドターゲット」:Android 1.6
「パッケージ名」:jp.co.example.intentservicetest0
「アクティビティ名」:IntentServiceTest0Activity
2)サービスクラスを作成する。
プロジェクトのsrcのパッケージ配下に、『MyIntentService』クラスを作成
ソース内容は以下の通り。
基本的には、MyIntentServiceクラスをIntentServiceクラスの継承クラスとする。
Seriviceの継承とは異なり、コンストラクターのみ強制オーバーライドであった。
Eclipseのコードアシスタントでは、第一引数ありのコンストラクタを生成してくれる、
しかし、
Activityで以下のコードでサービスを起動するには、
引数なしのコンストラクタが必要となることに注意。
onBind、onCreate、onDestroy、onStartは、オーバーライドは任意。
今回はログ確認用に、オーバーライドしている。
また、別スレッドで動くonHandleIntentメソッドには、スリープを5秒間入れた。
これは、onHandleIntentがどのスレッドで動くか調べるためだ。
結果、onHandleIntentは、新規スレッドで動作した。
つまりは、以下のコードにおけるIntentServiceは、
Activityと同プロセスだが、別スレッドで動作している。
res\layout\main.xmlに、ボタンを2つ作成。
ソースは以下のようになる。
4)サービスをスタート/ストップするアクティビティを作る
以下の処理を行っている。
スタートボタン押下で次を実行。
全体のコードは以下の通り。
5)マニフェストでサービス許可する
AndroidManifest.xmlにタグにサービスクラス名を指定して、以下のようにサービスを許可する。
何もしないシンプルなサービスでは、Serviceクラスを継承した。
今回は、IntentServiceクラスを継承する。
2つの違いは、以下の通り。
・IntentServiceのonHandleIntentメソッドが、別スレッドで実行される(非同期)
非同期の関連キーワード:AsyncTask、Thread、Runnable
・IntentServiceは、処理が終わると、自動的にonDestroyメソッドが呼ばれサービスが停止すること。
■別スレッドで動くIntentServiceを作る
1)新規のAndroidプロジェクトを以下のように作成する。
「プロジェクト名」:IntentServiceTest0
「ビルドターゲット」:Android 1.6
「パッケージ名」:jp.co.example.intentservicetest0
「アクティビティ名」:IntentServiceTest0Activity
2)サービスクラスを作成する。
プロジェクトのsrcのパッケージ配下に、『MyIntentService』クラスを作成
ソース内容は以下の通り。
基本的には、MyIntentServiceクラスをIntentServiceクラスの継承クラスとする。
Seriviceの継承とは異なり、コンストラクターのみ強制オーバーライドであった。
Eclipseのコードアシスタントでは、第一引数ありのコンストラクタを生成してくれる、
しかし、
Activityで以下のコードでサービスを起動するには、
引数なしのコンストラクタが必要となることに注意。
startService(new Intent(getBaseContext(), MyIntentService.class));
onBind、onCreate、onDestroy、onStartは、オーバーライドは任意。
今回はログ確認用に、オーバーライドしている。
また、別スレッドで動くonHandleIntentメソッドには、スリープを5秒間入れた。
これは、onHandleIntentがどのスレッドで動くか調べるためだ。
結果、onHandleIntentは、新規スレッドで動作した。
つまりは、以下のコードにおけるIntentServiceは、
Activityと同プロセスだが、別スレッドで動作している。
package jp.co.example.intentservicetest0; import android.app.IntentService; import android.content.Intent; import android.os.IBinder; import android.util.Log; public class MyIntentService extends IntentService{ private final String TAG = this.getClass().getSimpleName(); public MyIntentService(String name) { super(name); // TODO 自動生成されたコンストラクター・スタブ Log.d(TAG, Thread.currentThread().getStackTrace()[2].getMethodName()); } public MyIntentService() { super("MyIntentService"); Log.d(TAG, Thread.currentThread().getStackTrace()[2].getMethodName()); } @Override protected void onHandleIntent(Intent arg0) { // TODO 自動生成されたメソッド・スタブ Log.d(TAG, Thread.currentThread().getStackTrace()[2].getMethodName()); try { Thread.sleep(5000); } catch (InterruptedException e) { // TODO 自動生成された catch ブロック e.printStackTrace(); } } @Override public IBinder onBind(Intent intent) { // TODO 自動生成されたメソッド・スタブ Log.d(TAG, Thread.currentThread().getStackTrace()[2].getMethodName()); return super.onBind(intent); } @Override public void onCreate() { // TODO 自動生成されたメソッド・スタブ super.onCreate(); Log.d(TAG, Thread.currentThread().getStackTrace()[2].getMethodName()); } @Override public void onDestroy() { // TODO 自動生成されたメソッド・スタブ super.onDestroy(); Log.d(TAG, Thread.currentThread().getStackTrace()[2].getMethodName()); } @Override public void onStart(Intent intent, int startId) { // TODO 自動生成されたメソッド・スタブ super.onStart(intent, startId); Log.d(TAG, Thread.currentThread().getStackTrace()[2].getMethodName()); } }3)画面にスタートボタン、ストップボタンを作る
res\layout\main.xmlに、ボタンを2つ作成。
ソースは以下のようになる。
<?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" > <Button android:text="Start" android:id="@+id/start_button" android:layout_width="wrap_content" android:layout_height="wrap_content"></Button> <Button android:text="Stop" android:id="@+id/stop_button" android:layout_width="wrap_content" android:layout_height="wrap_content"></Button> </LinearLayout>
4)サービスをスタート/ストップするアクティビティを作る
以下の処理を行っている。
スタートボタン押下で次を実行。
startService(new Intent(getBaseContext(), MyIntentService.class));ストップボタン押下で次を実行。
stopService(new Intent(getBaseContext(), MyIntentService.class));
全体のコードは以下の通り。
package jp.co.example.intentservicetest0; import android.app.Activity; import android.content.Intent; import android.os.Bundle; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; public class IntentServiceTest0Activity extends Activity { Button startButton; Button stopButton; /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); findViews(); startButton.setOnClickListener(new OnClickListener() { public void onClick(View v) { // TODO 自動生成されたメソッド・スタブ startService(new Intent(getBaseContext(), MyIntentService.class)); } }); stopButton.setOnClickListener(new OnClickListener() { public void onClick(View v) { // TODO 自動生成されたメソッド・スタブ stopService(new Intent(getBaseContext(), MyIntentService.class)); } }); } protected void findViews() { startButton = (Button)findViewById(R.id.start_button); stopButton = (Button)findViewById(R.id.stop_button); } }
5)マニフェストでサービス許可する
AndroidManifest.xmlに
<application android:icon="@drawable/icon" android:label="@string/app_name"> (略) <service android:name=".MyIntentService"/> </application>
ラベル:
IntentService
2011年7月14日木曜日
簡単なソースでサービスを調べる
Androidにはサービスという、Linux等でいうデーモンのような仕組みがある。
一口にサービスといっても、色々なコーディング方法がある。
まずは、何もしないサービスをActivityから呼び出して、調査しよう。
■何もしないサービスを作る
1)新規のAndroidプロジェクトを以下のように作成する。
「プロジェクト名」:ServiceTest0
「ビルドターゲット」:Android 1.6
「パッケージ名」:jp.co.example.servicetest0
「アクティビティ名」:ServiceTest0Activity
2)サービスクラスを作成する。
プロジェクトのsrcのパッケージ配下に、『MyService』クラスを作成
ソース内容は以下の通り。
基本的には、MyServiceクラスをServiceクラスの継承クラスとし、
onBindメソッドは、親のServiceクラスでabstractなので、強制的にオーバーライド。
onCreate、onDestroy、onStartは、オーバーライドは任意。
だが、何か処理をするためのサービスなので、通常はオーバーライド必須だろう。
各メソッドには、ログを埋め込んだ。
また、onStartメソッドには、スリープを5秒間入れた。
これは、onStartがどのスレッドで動くか調べるためだ。
結果、onStartは、Activityと同じmainスレッドで動作した。
つまりは、以下のコードにおけるサービスとは、
Activityと別プロセスどころか、別スレッドでもない。
(注:別プロセスで動くサービスもちゃんと用意されている)
res\layout\main.xmlに、ボタンを2つ作成。
ソースは以下のようになる。
4)サービスをスタート/ストップするアクティビティを作る
以下の処理を行っている。
スタートボタン押下で次を実行。
全体のコードは以下の通り。
5)マニフェストでサービス許可する
AndroidManifest.xmlにタグにサービスクラス名を指定して、以下のようにサービスを許可する。
一口にサービスといっても、色々なコーディング方法がある。
まずは、何もしないサービスをActivityから呼び出して、調査しよう。
■何もしないサービスを作る
1)新規のAndroidプロジェクトを以下のように作成する。
「プロジェクト名」:ServiceTest0
「ビルドターゲット」:Android 1.6
「パッケージ名」:jp.co.example.servicetest0
「アクティビティ名」:ServiceTest0Activity
2)サービスクラスを作成する。
プロジェクトのsrcのパッケージ配下に、『MyService』クラスを作成
ソース内容は以下の通り。
基本的には、MyServiceクラスをServiceクラスの継承クラスとし、
onBindメソッドは、親のServiceクラスでabstractなので、強制的にオーバーライド。
onCreate、onDestroy、onStartは、オーバーライドは任意。
だが、何か処理をするためのサービスなので、通常はオーバーライド必須だろう。
各メソッドには、ログを埋め込んだ。
また、onStartメソッドには、スリープを5秒間入れた。
これは、onStartがどのスレッドで動くか調べるためだ。
結果、onStartは、Activityと同じmainスレッドで動作した。
つまりは、以下のコードにおけるサービスとは、
Activityと別プロセスどころか、別スレッドでもない。
(注:別プロセスで動くサービスもちゃんと用意されている)
package jp.co.example.servicetest0; import android.app.Service; import android.content.Intent; import android.os.IBinder; import android.util.Log; public class MyService extends Service{ private final String TAG = this.getClass().getSimpleName(); @Override public IBinder onBind(Intent arg0) { // TODO 自動生成されたメソッド・スタブ Log.d(TAG, Thread.currentThread().getStackTrace()[2].getMethodName()); return null; } @Override public void onCreate() { // TODO 自動生成されたメソッド・スタブ super.onCreate(); Log.d(TAG, Thread.currentThread().getStackTrace()[2].getMethodName()); } @Override public void onDestroy() { // TODO 自動生成されたメソッド・スタブ super.onDestroy(); Log.d(TAG, Thread.currentThread().getStackTrace()[2].getMethodName()); } @Override public void onStart(Intent intent, int startId) { // TODO 自動生成されたメソッド・スタブ super.onStart(intent, startId); Log.d(TAG, Thread.currentThread().getStackTrace()[2].getMethodName()); Log.d(TAG, "sleep start"); try { Thread.sleep(5000); } catch (InterruptedException e) { // TODO 自動生成された catch ブロック e.printStackTrace(); } Log.d(TAG, "sleep end"); } }3)画面にスタートボタン、ストップボタンを作る
res\layout\main.xmlに、ボタンを2つ作成。
ソースは以下のようになる。
<?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" > <Button android:text="Start" android:id="@+id/start_button" android:layout_width="wrap_content" android:layout_height="wrap_content"></Button> <Button android:text="Stop" android:id="@+id/stop_button" android:layout_width="wrap_content" android:layout_height="wrap_content"></Button> </LinearLayout>
4)サービスをスタート/ストップするアクティビティを作る
以下の処理を行っている。
スタートボタン押下で次を実行。
startService(new Intent(getBaseContext(), MyService.class));ストップボタン押下で次を実行。
stopService(new Intent(getBaseContext(), MyService.class));
全体のコードは以下の通り。
package jp.co.example.servicetest0; import android.app.Activity; import android.content.Intent; import android.os.Bundle; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; public class ServiceTest0Activity extends Activity { Button startButton; Button stopButton; /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); findViews(); startButton.setOnClickListener(new OnClickListener() { public void onClick(View v) { // TODO 自動生成されたメソッド・スタブ startService(new Intent(getBaseContext(), MyService.class)); } }); stopButton.setOnClickListener(new OnClickListener() { public void onClick(View v) { // TODO 自動生成されたメソッド・スタブ stopService(new Intent(getBaseContext(), MyService.class)); } }); } protected void findViews() { startButton = (Button)findViewById(R.id.start_button); stopButton = (Button)findViewById(R.id.stop_button); } }
5)マニフェストでサービス許可する
AndroidManifest.xmlに
<application android:icon="@drawable/icon" android:label="@string/app_name"> (略) <service android:name=".MyService"/> </application>
2011年7月13日水曜日
Androidの考え方
■OnDestroyが呼ばれても、プロセスがなくなるとは限らない
ActivityのライフサイクルでOnDestroyが呼ばれても、プロセスは残る。
理由は、プロセス生成の電力コストを下げるため、できるだけ再利用したいからだそうだ。
いつアプリのプロセスは終了するのか。
LowMemoryKillerというカーネルのドライバがメモリ不足を検知したとき、
使われていないアプリを停止させる。この時である。
開発時に気をつけること、
staticクラス変数は、LowMemoryKillerがプロセスを停止するまで、維持されること。
逆の発想では、LowMemoryKiller次第で、いつでもstaticクラス変数が破棄されること。
プロセスやstaticクラス変数が、処理中に破棄されては困るなら、
サービスとして作成するのがシンプルな方法の一つである。
ActivityのライフサイクルでOnDestroyが呼ばれても、プロセスは残る。
理由は、プロセス生成の電力コストを下げるため、できるだけ再利用したいからだそうだ。
いつアプリのプロセスは終了するのか。
LowMemoryKillerというカーネルのドライバがメモリ不足を検知したとき、
使われていないアプリを停止させる。この時である。
開発時に気をつけること、
staticクラス変数は、LowMemoryKillerがプロセスを停止するまで、維持されること。
逆の発想では、LowMemoryKiller次第で、いつでもstaticクラス変数が破棄されること。
プロセスやstaticクラス変数が、処理中に破棄されては困るなら、
サービスとして作成するのがシンプルな方法の一つである。
Activityのライフサイクルを確認する
イベントに対応したActivityのライフサイクは以下の通り。
実機およびエミュレータで確認し、作成。
上記を調査したソースは以下の通り。
メソッドをオーバーライドし、ログを埋め込んだだけのソースです。
実機およびエミュレータで確認し、作成。
上記を調査したソースは以下の通り。
メソッドをオーバーライドし、ログを埋め込んだだけのソースです。
package jp.co.example.lifecycle; import android.app.Activity; import android.os.Bundle; import android.util.Log; public class LifeCycleActivity extends Activity { private final String TAG = this.getClass().getSimpleName(); /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); Log.d(TAG, Thread.currentThread().getStackTrace()[2].getMethodName()); setContentView(R.layout.main); } @Override protected void onDestroy() { // TODO 自動生成されたメソッド・スタブ super.onDestroy(); Log.d(TAG, Thread.currentThread().getStackTrace()[2].getMethodName()); } @Override protected void onPause() { // TODO 自動生成されたメソッド・スタブ super.onPause(); Log.d(TAG, Thread.currentThread().getStackTrace()[2].getMethodName()); } @Override protected void onRestart() { // TODO 自動生成されたメソッド・スタブ super.onRestart(); Log.d(TAG, Thread.currentThread().getStackTrace()[2].getMethodName()); } @Override protected void onRestoreInstanceState(Bundle savedInstanceState) { // TODO 自動生成されたメソッド・スタブ super.onRestoreInstanceState(savedInstanceState); Log.d(TAG, Thread.currentThread().getStackTrace()[2].getMethodName()); } @Override protected void onResume() { // TODO 自動生成されたメソッド・スタブ super.onResume(); Log.d(TAG, Thread.currentThread().getStackTrace()[2].getMethodName()); } @Override protected void onSaveInstanceState(Bundle outState) { // TODO 自動生成されたメソッド・スタブ super.onSaveInstanceState(outState); Log.d(TAG, Thread.currentThread().getStackTrace()[2].getMethodName()); } @Override protected void onStart() { // TODO 自動生成されたメソッド・スタブ super.onStart(); Log.d(TAG, Thread.currentThread().getStackTrace()[2].getMethodName()); } @Override protected void onStop() { // TODO 自動生成されたメソッド・スタブ super.onStop(); Log.d(TAG, Thread.currentThread().getStackTrace()[2].getMethodName()); } }
2011年7月11日月曜日
Android開発環境を作成する
Android開発環境を作成する。
■Java Development Kit(JDK)をインストール(本家)
・JDKを選択。(キーワード:Windowsが32bitならWindows x86。64bitならWindows x64)
AndroidSDKには、最新のJDKで動いてもらいましょう。
■AndroidSDKをダウンロード(本家)
・パス設定等自動でするexe版が便利。
・インストールする。
・インストール後、実行するとInstalling Archivesが起動するので、
All Accept(すべて受諾)を選択し、アーカイブをインストールする。
(かなり時間かかります(2、3時間?)。
とりあえず、最低限、必要なバージョンの
「SDK Platform Android」、「Documentation for Android SDK」で動くとのこと。)
■Eclipse3.7(java ee版)をダウンロード(Pleiades All in One 日本語ディストリビューション)
・Java(本家ではJavaEE相当)の(開発環境を固定するため)JREありを選択する。
・ダウンロード後、解凍する。
■EclipseへAndroidプラグインをインストール
・eclipse.exeを起動する。
・メニューの「ヘルプ」→「新規ソフトウェアのインストール」を選択。
・「インストール」画面の(右上)「追加」ボタンを押下。
・「リボジトリーの追加」画面」に以下を入力する。
「名前」:『Android Plugin』、
「ロケーション」:『https://dl-ssl.google.com/android/eclipse/』(※1)
(※1)エラーが発生する場合は『http://dl-ssl.google.com/android/eclipse/』
・「開発ツール」というチェックボックスが表示されるのでチェックする。
(DDMS等、4つにチェックが入るはず)
・「次へ」ボタンや、同意を促すラジオボタンを押下していくと、インストールが始まる。
■eclipseの設定をする。
・メニューの「ウィンドウ」→「設定」を選択し、「設定」ダイアログを出す。
●文字コードの設定(確認)
ダイアログ左から「一般」→「ワークスペース」を選択。
「テキスト・ファイルのエンコード」を「UTF-8」とする。
●Android SDKのパス設定
ダイアログ左から「Android」を選択。
「SDK ロケーション」に先にインストールしたAndroid SDKのパスを入力する。
「適用」ボタン押下し、「ターゲット名」リストに「Android 2.2」等が表示するのを確認。
☆以下、お好みで☆
●エディター行番号の表示(Pleiades版ではデフォルトONです)
ダイアログ左から「一般」→「エディター」→「テキスト・エディター」を選択。
「行番号の表示」チェックボックスをONにする。
■Eclipseのアップデート
メニューの「ヘルプ」→「更新の確認」
(たま~に、Eclipseのバグが目に見えて解消されるので、お勧め。)
■Android Virtual devicesの設定
今回、EclipseのAndroidプラグインから設定する。
メニューの「ウィンドウ」→「Android SDK および AVD マネージャー」を選択し
ダイアログを起動する。
ダイアログ左から「Virtual devices」を選択。ダイアログ右から「New(新規)」ボタン押下。
まずは、万人に利用されるであろう、Android 1.6のAVDを作成します。
「Create new Android Virtual Device (AVD)」画面に以下を設定する。
・「Name(名前)」:『Android1.6』
・「Target(ターゲット)」:『Android 1.6 - API Level 4』
・「SD Card」の「Size(サイズ)」:64M
あとは、必要に応じてAVDを作成することになります。
■Eclipseの便利なショートカット
・インポート宣言の追加 : Ctrl + Shift + M
・インポート宣言の編成 : Ctrl + Shift + O
・コメントの有効・無効 : Ctrl + /
・次を検索 : Ctrl + K
・前を検索 : Ctrl + Shift + K
※注意しなければいけないもの
・行削除 : Ctrl + D (保存するとき間違えて押さないよう)
■Androidエミュレータの画面サイズ
ノートパソコンでAndroidエミュレータを起動すると、およそモニターからはみ出てしまう。
対処法は2つある。
方法1:「Android SDK および AVD マネージャー」からADVを起動しておく方法
ADVを開始する際に表示される「Launch Option」ダイアログで、
「Screen Size」を『6』とすると、1024*768モニターでは丁度いい。
方法2:作成済みAndroidプロジェクトの実行構成の追加オプションで指定する方法
Eclipseの「パッケージ・エクスプローラー」からAndroidプロジェクトを右クリックし、
「実行」→「実行の構成」を選択し、「実行構成」ダイアログを表示。
ダイアログ右の「ターゲット」タブを選択し、
「エミュレーター・コマンド行の追加オプション」へ、『-scale 0.6』を追記する。
■Java Development Kit(JDK)をインストール(本家)
・JDKを選択。(キーワード:Windowsが32bitならWindows x86。64bitならWindows x64)
AndroidSDKには、最新のJDKで動いてもらいましょう。
■AndroidSDKをダウンロード(本家)
・パス設定等自動でするexe版が便利。
・インストールする。
・インストール後、実行するとInstalling Archivesが起動するので、
All Accept(すべて受諾)を選択し、アーカイブをインストールする。
(かなり時間かかります(2、3時間?)。
とりあえず、最低限、必要なバージョンの
「SDK Platform Android」、「Documentation for Android SDK」で動くとのこと。)
■Eclipse3.7(java ee版)をダウンロード(Pleiades All in One 日本語ディストリビューション)
・Java(本家ではJavaEE相当)の(開発環境を固定するため)JREありを選択する。
・ダウンロード後、解凍する。
■EclipseへAndroidプラグインをインストール
・eclipse.exeを起動する。
・メニューの「ヘルプ」→「新規ソフトウェアのインストール」を選択。
・「インストール」画面の(右上)「追加」ボタンを押下。
・「リボジトリーの追加」画面」に以下を入力する。
「名前」:『Android Plugin』、
「ロケーション」:『https://dl-ssl.google.com/android/eclipse/』(※1)
(※1)エラーが発生する場合は『http://dl-ssl.google.com/android/eclipse/』
・「開発ツール」というチェックボックスが表示されるのでチェックする。
(DDMS等、4つにチェックが入るはず)
・「次へ」ボタンや、同意を促すラジオボタンを押下していくと、インストールが始まる。
■eclipseの設定をする。
・メニューの「ウィンドウ」→「設定」を選択し、「設定」ダイアログを出す。
●文字コードの設定(確認)
ダイアログ左から「一般」→「ワークスペース」を選択。
「テキスト・ファイルのエンコード」を「UTF-8」とする。
●Android SDKのパス設定
ダイアログ左から「Android」を選択。
「SDK ロケーション」に先にインストールしたAndroid SDKのパスを入力する。
「適用」ボタン押下し、「ターゲット名」リストに「Android 2.2」等が表示するのを確認。
☆以下、お好みで☆
●エディター行番号の表示(Pleiades版ではデフォルトONです)
ダイアログ左から「一般」→「エディター」→「テキスト・エディター」を選択。
「行番号の表示」チェックボックスをONにする。
■Eclipseのアップデート
メニューの「ヘルプ」→「更新の確認」
(たま~に、Eclipseのバグが目に見えて解消されるので、お勧め。)
■Android Virtual devicesの設定
今回、EclipseのAndroidプラグインから設定する。
メニューの「ウィンドウ」→「Android SDK および AVD マネージャー」を選択し
ダイアログを起動する。
ダイアログ左から「Virtual devices」を選択。ダイアログ右から「New(新規)」ボタン押下。
まずは、万人に利用されるであろう、Android 1.6のAVDを作成します。
「Create new Android Virtual Device (AVD)」画面に以下を設定する。
・「Name(名前)」:『Android1.6』
・「Target(ターゲット)」:『Android 1.6 - API Level 4』
・「SD Card」の「Size(サイズ)」:64M
あとは、必要に応じてAVDを作成することになります。
■Eclipseの便利なショートカット
・インポート宣言の追加 : Ctrl + Shift + M
・インポート宣言の編成 : Ctrl + Shift + O
・コメントの有効・無効 : Ctrl + /
・次を検索 : Ctrl + K
・前を検索 : Ctrl + Shift + K
※注意しなければいけないもの
・行削除 : Ctrl + D (保存するとき間違えて押さないよう)
■Androidエミュレータの画面サイズ
ノートパソコンでAndroidエミュレータを起動すると、およそモニターからはみ出てしまう。
対処法は2つある。
方法1:「Android SDK および AVD マネージャー」からADVを起動しておく方法
ADVを開始する際に表示される「Launch Option」ダイアログで、
「Screen Size」を『6』とすると、1024*768モニターでは丁度いい。
方法2:作成済みAndroidプロジェクトの実行構成の追加オプションで指定する方法
Eclipseの「パッケージ・エクスプローラー」からAndroidプロジェクトを右クリックし、
「実行」→「実行の構成」を選択し、「実行構成」ダイアログを表示。
ダイアログ右の「ターゲット」タブを選択し、
「エミュレーター・コマンド行の追加オプション」へ、『-scale 0.6』を追記する。
登録:
投稿 (Atom)