Windows8を導入したので、Androidアプリの開発環境を一から構築しました。
公式ドキュメントはAndroid Developersのここに掲載されているので、基本はここを参照すれば万事とどこおりなく作業は完了する
が、現時点でSystem requirementを見るとWindows8がない・・・しかもJDK6って、もうサポート終了で時代はJDK7なんですけど・・・古いセキュリティサポートの切れたJAVAなんて使いたくない・・・
ってとこだが、普通に最新のWindows8 + JDK7で動いた!良かった!
(Googleはさっさとドキュメント改訂しろと・・・なにか問題あるの???)
で、下記が手順です。前提はWindows8 PRO 64bitでSDKはADT Bundle for Windows版をインストールです。
まずはJDK7の最新版をインストール。32bit/64bitあるので自分のマシン環境にあわせて選択。自分のは64bitなので64bitを選択した。
続いて環境変数の設定(コンパネのシステムから詳細設定で環境変数を選択)
システム環境変数に対して、下記を設定
PATHを追加、例) C:\Program Files\Java\jdk1.7.0_40\bin
JAVA_HOMEを新規作成、例)C:\Program Files\Java\jdk1.7.0_40
そしたら本命のAndroid SDKをダウンロード
ZIPファイルなので適当に展開する。自分はCドライブ直下に展開。これは展開するだけで完了!
Eclipseも最新のSDKもすべて内蔵しているので、いきなり終了。これは楽ちん。
Eclipseを起動する
例)C:\adt-bundle-windows-x86_64\eclipse.exe
ショートカットは手動で作成してデスクトップなどへおけば便利
漏れなく記載できていれば、以上の手順で問題なく使えるはず
そして、エミュレーターでなく実際の端末を使ってアプリを開発するなら、Windowsの場合、もう1つやるべきことがある
WindowsはUSBドライバのインストールが必要!
USBドライバは各社で異なるので、自分の端末にあわせてドライバをインストールする
幸いなことにGoogleがここ(OEM USB Drivers)にまとめてくれている
基本Nexus系はGoogleのドライバ(サムソン除く)、それ以外は各社のドライバを使う
所望のドライバをダウンロードしたら、手動でインストールが必要
まずは端末をUSB接続するのだが、端末のUSBデバッグが有効になっていることを確認
詳しくはここを参照
Androidのversionによって有効にする方法が異なる(初期値はいずれもOFF)
特に4.2以降は隠されていて、記載されている特殊操作をしないとでてこないので要注意
(開発をしない普通の人に対して隠しモードにしたのかな?きっと)
有効にできたら、コンパネのデバイスマネージャーでUSBドライバを確認。?マークがついてるはずなので、ドライバのアップデートを実行し、フォルダ指定でダウンロードしたドライバのフォルダを指定する。ドライバが正しければ、うまくいく。
EclipseのRunタブにあるRun configurationsのTargetで、アプリ実行するときどの端末またはエミュレータで実行するかを設定できるので、適宜設定する
Showing posts with label 開発TIPS. Show all posts
Showing posts with label 開発TIPS. Show all posts
October 6, 2013
December 5, 2012
BACKキーで確認画面を表示する
BACKキーを押すと通常はそのActivityを終了して前のActivityに戻るといった動作をしますが、例えば、データ入力をするActivityでBACKキーを押されたとき、ポップアップを表示して入力をキャンセルして本当に前の画面に戻るかどうか促す、というUIにしたいときがあります。こういう処理をしたいときは、BACKキーのイベントをオーバーライドすることで自由に制御を変更して対応することができます。
例:BACKキーをおされたときにポップアップを表示してキャンセルか続行か促す
まずは、バックキーのイベントを取得して、ポップアップダイアログを表示します。ダイアログの結果を受け取って、キャンセルならfinish()でActivityを終了します。そうでなければ何もしません。
ポップアップダイアログを表示するメソッドです。Yes/Noの2つのボタンを表示して、結果を返します。
結果を渡すためのインターフェースです。
例:BACKキーをおされたときにポップアップを表示してキャンセルか続行か促す
まずは、バックキーのイベントを取得して、ポップアップダイアログを表示します。ダイアログの結果を受け取って、キャンセルならfinish()でActivityを終了します。そうでなければ何もしません。
@Override public boolean onKeyDown (int keyCode, KeyEvent event) { if (keyCode == KeyEvent.KEYCODE_BACK) { showAlert(mContext, new OnMyAlert() { @Override public void onResult(boolean isYes) { if (isYes) { finish(); } } }); } return false; }
ポップアップダイアログを表示するメソッドです。Yes/Noの2つのボタンを表示して、結果を返します。
private void showAlert(Context context, final OnMyAlert onMyAlert) { // Build AlertDialog.Builder builder = new AlertDialog.Builder(context); builder.setTitle(R.string.warning); builder.setMessage(R.string.mes_warn_cancel); // Left button builder.setPositiveButton(R.string.answer_no, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { onMyAlert.onResult(false); } }); // Right button builder.setNegativeButton(R.string.answer_yes, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { onMyAlert.onResult(true); } }); // Show builder.create().show(); }
結果を渡すためのインターフェースです。
public interface OnMyAlert { public abstract void onResult(boolean isYes); }
December 3, 2012
Intentにオブジェクトを付加して送信する
Intentを送るとき、さまざまな情報(intやStringなど)を付加することができますが、自分で作ったクラスのオブジェクトそのものを付加することもできます。
ただし、どんなクラスでも付加できるわけではなく、条件としてそのクラスがSerializableインターフェースを実装している必要があります。もちろんクラス内部のメンバー変数もすべてSerializableを実装したクラス、またはintなどのプリミティブである必要があります。
Serializableへの対応は特殊な使い方をしない限り、特に必須で実装するものはありません。通常は"implements Serializable"をクラスに追加し、serialVersionUIDを定義するだけです(eclipseで自動生成できます)。このUIDの値も気にする必要はありません。
例:クラスの定義
例:intentを送る
例:intentを受ける
オブジェクトを送ることができると書きましたが、送り側と受け手側で同じ中身のオブジェクトが受け取れるという意味で、インスタンスは異なります。
参考:Android Developers:Serializable
参考:Android Developers:Intent
ただし、どんなクラスでも付加できるわけではなく、条件としてそのクラスがSerializableインターフェースを実装している必要があります。もちろんクラス内部のメンバー変数もすべてSerializableを実装したクラス、またはintなどのプリミティブである必要があります。
Serializableへの対応は特殊な使い方をしない限り、特に必須で実装するものはありません。通常は"implements Serializable"をクラスに追加し、serialVersionUIDを定義するだけです(eclipseで自動生成できます)。このUIDの値も気にする必要はありません。
例:クラスの定義
public class SampleClass implements Serializable { private static final long serialVersionUID = 1L;
例:intentを送る
public class SampleClass implements Serializable { SampleClass sample = new SampleClass(); Intent intent = new Intent(getApplicationContext(), MyActivity.class); intent.putExtra("Foo", sample); startActivity(intent);
例:intentを受ける
SampleClass sample = (SampleClass) getIntent().getSerializableExtra("Foo");
オブジェクトを送ることができると書きましたが、送り側と受け手側で同じ中身のオブジェクトが受け取れるという意味で、インスタンスは異なります。
参考:Android Developers:Serializable
参考:Android Developers:Intent
CharSequenceとStringの関係
コードの中で文字列の定義は通常Stringを使うと思いますが、UI系のメソッドをみると、文字列の受け取り側は大抵はStringでなくCharSequenceだったりします。が、Stringをそのまま渡すことができるので、その関係を整理してみました。
CharSequenceはインターフェースです。メソッドを見ると文字列を制御するための最小限のみ定義されています。Android Developersで確認すると多くのクラスがこれを実装しているのがわかります。
StringもCharSequenceを実装しているクラスなので、そのまま渡せるというわけです。
参考:Android Developers:CharSequence
参考:Android Developers:String
CharSequenceはインターフェースです。メソッドを見ると文字列を制御するための最小限のみ定義されています。Android Developersで確認すると多くのクラスがこれを実装しているのがわかります。
StringもCharSequenceを実装しているクラスなので、そのまま渡せるというわけです。
参考:Android Developers:CharSequence
参考:Android Developers:String
stringリソースからString文字列を取得する
文字列は通常はstringリソースファイルに記述します。このときリソースidであれば、R.string.XXXで直接取得できますが、文字列を取得する場合は、ContextにあるgetString(int resId)を使って取得します。
例:
参考:Android Developers:Content - getString
例:
getString(R.string.sample)
参考:Android Developers:Content - getString
November 28, 2012
スクリーンのON/OFFイベントを検出する
スクリーン(LCD)のON/OFFイベントを検出する方法です。
スクリーンのON/OFFはシステムからBroadcast intentで飛んできますので、それを取得することで対応できます。受信するにはIntentFilterに取得したいIntent(この場合はACTION_SCREEN_OFF)を指定してBroadcast receiverを登録します。例ではOFFの1つだけですが、複数登録することももちろんできます。Activityが有効な間受信したい場合はonCreateで登録し、onDestroyで解除します。受信するとBroadcastReceiverのonReceiveがコールされます。
例)ActivityでスクリーンOFFを検出します
public class SampleAppActivity extends Activity { private BroadcastReceiver screenStatusReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { // Receive screen off if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) { // OFF } } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // Register a receiver to receive screen status updates IntentFilter filter = new IntentFilter(); filter.addAction(Intent.ACTION_SCREEN_OFF); registerReceiver(screenStatusReceiver, filter); } @Override protected void onDestroy() { super.onDestroy(); // Unregister a receiver unregisterReceiver(screenStatusReceiver); } }
参考:Android Developers:BroadcastReceiver
July 13, 2012
JellyBean(4.1)のソースコードを取得する
JellyBean(4.1)のソースコードがリリースされましたので、取得方法です。
$ repo init -u https://android.googlesource.com/platform/manifest -b android-4.1.1_r1
$ repo sync
今回はMacのターミナル上で実行しましたが、取得するにはrepoコマンドが必要です。
ホームフォルダにbinフォルダを作成して、そこにrepoコマンドをインストールしました。
$ mkdir bin
$ PATH=~/bin:$PATH
$ curl https://dl-ssl.google.com/dl/googlesource/git-repo/repo > ~/bin/repo
$ repo init -u https://android.googlesource.com/platform/manifest -b android-4.1.1_r1
$ repo sync
今回はMacのターミナル上で実行しましたが、取得するにはrepoコマンドが必要です。
ホームフォルダにbinフォルダを作成して、そこにrepoコマンドをインストールしました。
$ mkdir bin
$ PATH=~/bin:$PATH
$ curl https://dl-ssl.google.com/dl/googlesource/git-repo/repo > ~/bin/repo
$ chmod a+x ~/bin/repo
これでインストール完了です。
July 9, 2012
bindService()で始める、Binderクラスで作るService
Binderクラスを使って作る最も一般的なServiceの作成方法です。
bindService()を使ってServiceをBindし、Serviceで提供するユーザー関数を直接コールすることができます。Bindしている間Serviceは存在し、Unbindすると削除されます。複数のActivityからマルチでBindすることもできます。
bindService()を使ったServiceの作り方は3種類ありますが、今回紹介する方法が最も一般的です。なぜなら、アプリ内(正確にはServiceと同一プロセスで動くコンポーネントにServiceを提供する場合)でServiceを提供する場合はこの方法が最も適切かつ簡単なため、他のプロセスやアプリに機能を提供するなど特別なケースでない限り、他の方法を使う必要がないからです。
おおざっぱな流れは、Service側のクラスはBinderを拡張したユーザークラスを作成します。bindService()を実行するとonBind()がコールされるので、そのユーザーインスタンスを返します。呼び出し側のActivityではBindされるとServiceConnectionクラスのonServiceConnected()が呼ばれるので、ここでBinder経由でServiceインスタンスを取得します。あとはそのServiceインスタンスを使って、Service側でユーザー定義した関数を直接コールすることができます。
参考:Android Developers:Bound Services
bindService()を使ってServiceをBindし、Serviceで提供するユーザー関数を直接コールすることができます。Bindしている間Serviceは存在し、Unbindすると削除されます。複数のActivityからマルチでBindすることもできます。
bindService()を使ったServiceの作り方は3種類ありますが、今回紹介する方法が最も一般的です。なぜなら、アプリ内(正確にはServiceと同一プロセスで動くコンポーネントにServiceを提供する場合)でServiceを提供する場合はこの方法が最も適切かつ簡単なため、他のプロセスやアプリに機能を提供するなど特別なケースでない限り、他の方法を使う必要がないからです。
おおざっぱな流れは、Service側のクラスはBinderを拡張したユーザークラスを作成します。bindService()を実行するとonBind()がコールされるので、そのユーザーインスタンスを返します。呼び出し側のActivityではBindされるとServiceConnectionクラスのonServiceConnected()が呼ばれるので、ここでBinder経由でServiceインスタンスを取得します。あとはそのServiceインスタンスを使って、Service側でユーザー定義した関数を直接コールすることができます。
public class SampleService extends Service { private final static String TAB = "SampleService"; private final IBinder mBinder = new LocalBinder(); public class LocalBinder extends Binder { SampleService getService() { return SampleService.this; } } @Override public void onCreate() { Log.i(TAB,"onCreate"); } @Override public IBinder onBind(Intent intent) { return mBinder; } @Override public void onDestroy() { Log.i(TAB,"onDestroy"); } // Methods for client public void userFunction() { Log.i(TAB,"userFunction"); } }
public class SampleAppActivity extends Activity { private final static String TAB = "SampleAppActivity"; private SampleService mSampleService; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); Log.i(TAB,"onCreate"); setContentView(R.layout.main); Button button = (Button) findViewById(R.id.button); button.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { mSampleService.userFunction(); } }); } @Override public void onStart() { Log.i(TAB,"onStart"); super.onStart(); // Bind Intent intent = new Intent(getApplicationContext(), SampleService.class); bindService(intent, mSampleServiceConnection, Context.BIND_AUTO_CREATE); } @Override public void onStop() { Log.i(TAB,"onStop"); super.onStop(); // Unbind unbindService(mSampleServiceConnection); } private ServiceConnection mSampleServiceConnection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { SampleService.LocalBinder binder = (SampleService.LocalBinder)service; mSampleService = binder.getService(); } @Override public void onServiceDisconnected(ComponentName name) { } }; }
参考:Android Developers:Bound Services
July 6, 2012
startService()で始めるService
startService()で始めるServiceとは、intentを使ってServiceを起動し、バックグラウンドで指定された処理を実行するものです。
最も簡単に実装するには、Serviceクラスでなく、IntentServiceクラスを利用することです。その場合下記の例のようになります。ServiceクラスそのものはUIスレッドで動作するため、ブロックしないために通常はスレッドを作って、そちらで処理を実行しますが、IntentServiceはそのような面倒な処理がすべて実装されていて、コンストラクタとスレッドで実行する処理内容をonHandleIntent()をオーバーライドして実装するだけです。onHandleIntentはもちろん別スレッドで実行されます。
例:呼び出し側のstartService()
例:受け取り側のService
あえてService()で実装しなければいけないケースは、マルチスレッドで同時実行したい特殊な例だけです。IntentServiceはシングルスレッドのため、実行中に次の要求(startService())がきた場合はキューイングされ、逐次実行になります。すべての処理がおわるとIntentServiceは終了します。
参考までにあえてIntentServiceと同じ動作をするものをServiceを使って作成すると下記のようになります。
簡単に説明するとonCreate()でThreadとHandlerを新規作成します。Handlerは継承したユーザークラスを作り、handleMessage()に処理を記述します。startService()するとonStartCommand()がコールされ、Handlerから生成したMessageをThreadに送信し、Thread上でそのMessageとともにhandlerMessage()が実行されます。
マルチスレッドにする場合はonCreate()ではなくonStartCommand()がくるたびにスレッドを生成するようにするなど工夫する必要があります。
参考:Android Developers:Services
最も簡単に実装するには、Serviceクラスでなく、IntentServiceクラスを利用することです。その場合下記の例のようになります。ServiceクラスそのものはUIスレッドで動作するため、ブロックしないために通常はスレッドを作って、そちらで処理を実行しますが、IntentServiceはそのような面倒な処理がすべて実装されていて、コンストラクタとスレッドで実行する処理内容をonHandleIntent()をオーバーライドして実装するだけです。onHandleIntentはもちろん別スレッドで実行されます。
例:呼び出し側のstartService()
startService(new Intent(getApplicationContext(), SampleService.class));
例:受け取り側のService
public class SampleService extends IntentService { public SampleService() { super("SampleService"); } @Override protected void onHandleIntent(Intent intent) { Log.i(TAB,"onHandleIntent"); // Execute something... } }
あえてService()で実装しなければいけないケースは、マルチスレッドで同時実行したい特殊な例だけです。IntentServiceはシングルスレッドのため、実行中に次の要求(startService())がきた場合はキューイングされ、逐次実行になります。すべての処理がおわるとIntentServiceは終了します。
参考までにあえてIntentServiceと同じ動作をするものをServiceを使って作成すると下記のようになります。
public class SampleService extends Service { private ServiceHandler mServiceHandler; private final class ServiceHandler extends Handler { public ServiceHandler(Looper looper) { super(looper); } @Override public void handleMessage(Message msg) { // Execute something... // Stop the service with start id stopSelf(msg.arg1); } } @Override public void onCreate() { // Create and start new thread and handler HandlerThread thread = new HandlerThread("SampleService", Process.THREAD_PRIORITY_BACKGROUND); thread.start(); mServiceHandler = new ServiceHandler(thread.getLooper()); } @Override public int onStartCommand(Intent intent, int flags, int startId) { // Create message Message msg = mServiceHandler.obtainMessage(); // Set start id msg.arg1 = startId; // Send message mServiceHandler.sendMessage(msg); return START_STICKY; } @Override public IBinder onBind(Intent intent) { return null; } }
簡単に説明するとonCreate()でThreadとHandlerを新規作成します。Handlerは継承したユーザークラスを作り、handleMessage()に処理を記述します。startService()するとonStartCommand()がコールされ、Handlerから生成したMessageをThreadに送信し、Thread上でそのMessageとともにhandlerMessage()が実行されます。
マルチスレッドにする場合はonCreate()ではなくonStartCommand()がくるたびにスレッドを生成するようにするなど工夫する必要があります。
参考:Android Developers:Services
July 5, 2012
プロセス情報を取得する
システム上で動作しているプロセス情報を取得する方法です。
デバッグなどでバックグラウンドで存在しているプロセスを調べるのに利用できます。
例)プロセス情報をすべて取得し、プロセスID、パッケージ名を表示します。
プロセス情報を取得するにはパーミッションの設定が必要です。
実行すると下記のように表示されます。
参考:Android Developers:ActivityManager
デバッグなどでバックグラウンドで存在しているプロセスを調べるのに利用できます。
例)プロセス情報をすべて取得し、プロセスID、パッケージ名を表示します。
ActivityManager manager = (ActivityManager) getSystemService(ACTIVITY_SERVICE); List<RunningAppProcessInfo> appList = manager.getRunningAppProcesses(); Log.i(TAB, "Total apps:" + appList.size()); for (RunningAppProcessInfo info:appList) { Log.i(TAB,"PID:" + info.pid + " Name:" + info.processName); }
プロセス情報を取得するにはパーミッションの設定が必要です。
<uses-permission android:name="android.permission.GET_TASKS"/>
実行すると下記のように表示されます。
ちなみにプロセスを停止させる場合は、ActivityManagerのkillBackgroundProcesses(パッケージ名)を使います。停止させる場合もパーミッションの設定が必要です。
<uses-permission android:name="android.permission.KILL_BACKGROUND_PROCESSES"/>
参考:Android Developers:ActivityManager
onDestroy()してもプロセスは死なない
アプリはプロセスが割り当てられて動作しますが、ひとたび起動したアプリは、たとえ全てのActivityがonDestroy()してもプロセスは死にません。タスクはなくなってもプロセスは残ったままになります。アプリのActivityがonDestroy()まで到達し、タスクもなくなれば完全終了した気になりますが、実はプロセスとしてはまだ生きています。
例えば1つのActivityを持つアプリがあったとして、onCreate()で無限ループのThreadを起動したとします。Activityをバックキーで終了させ、onDestroy()までコールされるのですが、このThreadはだれも終了させることなく動作し続けます。Threadのdaemonフラグに関係なく生き残る仕様のようです。
設定アプリの「アプリケーションの管理」で表示されるアプリに「強制停止」ボタンがありますが、これはプロセスを殺す、ということをしています。プロセスがなくなって初めて起動していない元の状態に戻ります。
ここでなにが言いたいかというと、バックグラウンドで動作するThreadなどをうっかり終了し忘れると、生き残って動き続けてしまう、ということです。当然CPUには負荷がかかり、アプリを終わったのに端末の処理が重い、というのはこういう不具合で発生します。アプリでバックグラウンド処理を実行する場合は、きちんと終了できているか十分に確認することが必要です。
例えば1つのActivityを持つアプリがあったとして、onCreate()で無限ループのThreadを起動したとします。Activityをバックキーで終了させ、onDestroy()までコールされるのですが、このThreadはだれも終了させることなく動作し続けます。Threadのdaemonフラグに関係なく生き残る仕様のようです。
設定アプリの「アプリケーションの管理」で表示されるアプリに「強制停止」ボタンがありますが、これはプロセスを殺す、ということをしています。プロセスがなくなって初めて起動していない元の状態に戻ります。
ここでなにが言いたいかというと、バックグラウンドで動作するThreadなどをうっかり終了し忘れると、生き残って動き続けてしまう、ということです。当然CPUには負荷がかかり、アプリを終わったのに端末の処理が重い、というのはこういう不具合で発生します。アプリでバックグラウンド処理を実行する場合は、きちんと終了できているか十分に確認することが必要です。
July 4, 2012
アプリケーションとLooperとHandlerの関係
アプリケーションとLooperとHandlerの関係についての説明です。Androidフレームワークの内部に踏み込んだお話です。
「スレッドからUIを操作する」で、UIスレッドで実行させるために他のスレッドからHandlerクラスを使って処理内容を送信すると説明しましたが、なぜnew Handler()としただけのインスタンスにpost()しただけでUIスレッドに送信されてしまうか?という疑問への回答です。
まずAndroidのアプリケーションは1つのプロセスが割り当てられて動作しています。別々のアプリは別々のプロセス(つまりメモリ空間が異なる)で動いています。
UIスレッドとはメインスレッドとも呼ばれ、内部ではActivityThreadクラスのことを指します。このクラスはStatic変数のLooperクラスを所持しており(つまり1プロセスに1つしかない)、メイン関数でLooperクラスのメインループを実行しています。Looperクラスの処理は単純で、メッセージキューに入ってきた処理があれば実行する、だけです。つまりどこかのスレッドからメッセージをLooperに送信すれば、ActivityThread(UIスレッド)で実行してくれるという仕組みになっています。その送信するのがHandlerクラスになります。Handlerクラスは引数なしでnewすると内部でStatic変数のLooperクラスを送信先とします。つまりActivityThreadが送信先になるということです。
ここでいうメッセージとは、内部ではMessageクラスを使っており、Handlerのインスタンスでpost()するときのRunnableインスタンスを渡しています。それがLooperのメイン関数で、渡されたRunnableのrun()を実行しています。
より詳細はAndroidのソースコードを読む必要があります。
「スレッドからUIを操作する」で、UIスレッドで実行させるために他のスレッドからHandlerクラスを使って処理内容を送信すると説明しましたが、なぜnew Handler()としただけのインスタンスにpost()しただけでUIスレッドに送信されてしまうか?という疑問への回答です。
まずAndroidのアプリケーションは1つのプロセスが割り当てられて動作しています。別々のアプリは別々のプロセス(つまりメモリ空間が異なる)で動いています。
UIスレッドとはメインスレッドとも呼ばれ、内部ではActivityThreadクラスのことを指します。このクラスはStatic変数のLooperクラスを所持しており(つまり1プロセスに1つしかない)、メイン関数でLooperクラスのメインループを実行しています。Looperクラスの処理は単純で、メッセージキューに入ってきた処理があれば実行する、だけです。つまりどこかのスレッドからメッセージをLooperに送信すれば、ActivityThread(UIスレッド)で実行してくれるという仕組みになっています。その送信するのがHandlerクラスになります。Handlerクラスは引数なしでnewすると内部でStatic変数のLooperクラスを送信先とします。つまりActivityThreadが送信先になるということです。
ここでいうメッセージとは、内部ではMessageクラスを使っており、Handlerのインスタンスでpost()するときのRunnableインスタンスを渡しています。それがLooperのメイン関数で、渡されたRunnableのrun()を実行しています。
より詳細はAndroidのソースコードを読む必要があります。
- android/os/Handler.java
- android/os/Looper.java
- android/os/Message.java
- android/app/ActivityThread.java
July 3, 2012
ランチャーからアプリを起動するときのIntent
ランチャー(ホームメニューからのアプリランチャー)からアプリを起動するときに飛んでくるIntentは下記のような設定になっています。
フラグの意味は、アプリが起動していなければ新規起動、起動済みであればそれをフォアグラウンドに持ってくるだけです。
参考:Android Developers:Intent
- Action:android.intent.action.MAIN
- Category:android.intent.category.LAUNCHER
- Flags:FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
<application android:icon="@drawable/ic_launcher" android:label="@string/app_name"> <activity android:name="SampleAppActivity" android:label="@string/app_name" > <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity>
フラグの意味は、アプリが起動していなければ新規起動、起動済みであればそれをフォアグラウンドに持ってくるだけです。
参考:Android Developers:Intent
July 1, 2012
タスク情報を取得する
システム上で動作しているタスク情報を取得する方法です。
デバッグなどでタスクがどう生成されているか理解するのに役に立ちます。
例)タスク情報をすべて取得し、タスクの先頭Activity、スタックされているActivity数を表示します。
タスク情報を取得するにはパーミッションの設定が必要です。
実行すると下記のように表示されます。
参考:Android Developers:ActivityManager
デバッグなどでタスクがどう生成されているか理解するのに役に立ちます。
例)タスク情報をすべて取得し、タスクの先頭Activity、スタックされているActivity数を表示します。
ActivityManager manager = (ActivityManager) getSystemService(ACTIVITY_SERVICE); List<RunningTaskInfo> list = manager.getRunningTasks(100); Log.i(TAB, "Total tasks:" + list.size()); for (RunningTaskInfo info:list) { Log.i(TAB, "ID:" + info.id + " Top:" + info.topActivity.getClassName() + "Num:" + info.numActivities); }
タスク情報を取得するにはパーミッションの設定が必要です。
<uses-permission android:name="android.permission.GET_TASKS"/>
実行すると下記のように表示されます。
参考:Android Developers:ActivityManager
June 29, 2012
NotificationのUIをカスタマイズする
NotificationのUIのカスタマイズ方法です。
Notificationのデフォルト表示方法は「Notificationで通知する」を参照してください。ここではそこからのカスタマイズ方法を説明します。
例)独自のレイアウトでNotificationを表示し、さらにその中の画像をクリックするとServiceにIntentを飛ばします。これはNotification上のボタンからServiceで動作している機能に、いろいろな操作(例:音楽再生の操作とか)が出来ることを意味します。
まずはNotificationに表示するレイアウトを作成します。ここでは画像とテキスト2つです。背景色がデバイスによって異なる可能性があるため、テキストには標準のstyleを設定しています。注意事項は高さがGingerBread(2.3.x)までは固定のようです。HoneyComb(3.x)以降は高さもコンテンツにあわせて変化します。
レイアウトはRemoteViewsクラスを使って上記のレイアウトを生成し、notificationに設定します。またsetOnClickPendingIntentを使って画像をクリックするとServiceにIntentを飛ばすようにnotificationに設定します。ここではactionに"Play"を付加しています。注意事項として、このような画像クリックはHoneyComb(3.x)以降でないと機能しないようです。通常のクリックと同じ扱いになってしまいます。
Intentを受け取るServiceクラスは下記のようにしています。Intentを受け取るとonStartCommand()が呼ばれますので、そのときのactionをログ表示します。ここに必要な機能を作り込みます。
実行すると下記のようになります。画像をクリックするとServiceにintentが飛びます。
参考:Android Developers:Status Notifications
参考:Android Developers:RemoteViews
Notificationのデフォルト表示方法は「Notificationで通知する」を参照してください。ここではそこからのカスタマイズ方法を説明します。
例)独自のレイアウトでNotificationを表示し、さらにその中の画像をクリックするとServiceにIntentを飛ばします。これはNotification上のボタンからServiceで動作している機能に、いろいろな操作(例:音楽再生の操作とか)が出来ることを意味します。
まずはNotificationに表示するレイアウトを作成します。ここでは画像とテキスト2つです。背景色がデバイスによって異なる可能性があるため、テキストには標準のstyleを設定しています。注意事項は高さがGingerBread(2.3.x)までは固定のようです。HoneyComb(3.x)以降は高さもコンテンツにあわせて変化します。
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent"> <ImageView android:id="@+id/icon" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentLeft="true" /> <TextView android:id="@+id/title" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_toRightOf="@id/icon" style="@android:style/TextAppearance.StatusBar.EventContent.Title" /> <TextView android:id="@+id/text" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_toRightOf="@id/icon" android:layout_below="@id/title" style="@android:style/TextAppearance.StatusBar.EventContent" /> </RelativeLayout>
レイアウトはRemoteViewsクラスを使って上記のレイアウトを生成し、notificationに設定します。またsetOnClickPendingIntentを使って画像をクリックするとServiceにIntentを飛ばすようにnotificationに設定します。ここではactionに"Play"を付加しています。注意事項として、このような画像クリックはHoneyComb(3.x)以降でないと機能しないようです。通常のクリックと同じ扱いになってしまいます。
private void showNotification() { NotificationManager manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE); Intent intent = new Intent(this, SubAppActivity.class); PendingIntent contentIntent = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT); String tickerText = getString(R.string.hello); // Customized Layout RemoteViews contentView = new RemoteViews(getPackageName(), R.layout.row); contentView.setImageViewResource(R.id.icon, R.drawable.jelly); contentView.setTextViewText(R.id.title, "Title"); contentView.setTextViewText(R.id.text, "text message!"); Intent intent2 = new Intent(this, SampleService.class); intent2.setAction("Play"); PendingIntent pi2 = PendingIntent.getService(this, 0, intent2, PendingIntent.FLAG_UPDATE_CURRENT); contentView.setOnClickPendingIntent(R.id.icon, pi2); // Notify Notification notification; try { Class.forName("android.app.Notification$Builder"); notification = new Notification.Builder(this) .setContentIntent(contentIntent) .setContent(contentView) .setSmallIcon(android.R.drawable.stat_sys_download) .setTicker(tickerText) .setWhen(System.currentTimeMillis()) .getNotification(); } catch (ClassNotFoundException e) { notification = new Notification(android.R.drawable.stat_sys_download, tickerText, System.currentTimeMillis()); notification.contentIntent = contentIntent; notification.contentView = contentView; } manager.notify(1, notification); }
Intentを受け取るServiceクラスは下記のようにしています。Intentを受け取るとonStartCommand()が呼ばれますので、そのときのactionをログ表示します。ここに必要な機能を作り込みます。
public class SampleService extends Service { @Override public int onStartCommand(Intent intent, int flags, int startId) { String action = intent.getAction(); Log.i("Service", action); return START_STICKY; } }
実行すると下記のようになります。画像をクリックするとServiceにintentが飛びます。
参考:Android Developers:Status Notifications
参考:Android Developers:RemoteViews
June 26, 2012
Notificationで通知する
Notificationを使って通知する方法です。通常はBackgroundで動作しているServiceからユーザーに何かを通知するのが目的で使います。
通知はTickerと呼ばれる通知時のみ速報のように表示されるテキストメッセージと、通知欄に表示されるアイコン、通知を開いた時に表示されるタイトルとテキスト、通知をタップしたときの動作(Intent)が最小構成となります。
通知は自分で割り振ったID番号で管理することができ、通知ごとに新しい通知を作ることもできれば、通知済みであれば1つの通知に集約して作らないこともできます。基本は集約して同じ通知は1つにまとめるUIが推奨されています。
オプションで通知時にバイブレーション、LED、音楽再生もセットできます。また通知のUIレイアウトもカスタマイズ可能です。
例)通知します。タップすると単独の別Activityを起動します。通知は1つに集約するようにしています。
通知はいろいろな情報をセットしたNotificationを作成し、それをNotificationManagerを使って通知を実行します。IntentはPendingIntentというものに包み込んでセットします。これはそのIntentが自分のアプリが発行したかのように他のアプリから実行することができる特別なIntentになります。NotificationはAPI Level 11から作成方法が異なり、以前はnewしていましたが、今はNotification.Builderを使って作成するため、両方の作り方を記載しています。
ここでは通知の発行は下記の関数を用意しました。
タップされると起動するSubAppActivityは単独のタスクとするため、AndroidManifestで下記のようにActivityを設定します。
実行すると、まずアイコンとTickerが表示されます。
通知を開くとアイコン、TitleとTextが表示され、タップするとSubAppActivityが独立したタスクで起動します。
参考:Android Developers:Status Notifications
通知はTickerと呼ばれる通知時のみ速報のように表示されるテキストメッセージと、通知欄に表示されるアイコン、通知を開いた時に表示されるタイトルとテキスト、通知をタップしたときの動作(Intent)が最小構成となります。
通知は自分で割り振ったID番号で管理することができ、通知ごとに新しい通知を作ることもできれば、通知済みであれば1つの通知に集約して作らないこともできます。基本は集約して同じ通知は1つにまとめるUIが推奨されています。
オプションで通知時にバイブレーション、LED、音楽再生もセットできます。また通知のUIレイアウトもカスタマイズ可能です。
例)通知します。タップすると単独の別Activityを起動します。通知は1つに集約するようにしています。
通知はいろいろな情報をセットしたNotificationを作成し、それをNotificationManagerを使って通知を実行します。IntentはPendingIntentというものに包み込んでセットします。これはそのIntentが自分のアプリが発行したかのように他のアプリから実行することができる特別なIntentになります。NotificationはAPI Level 11から作成方法が異なり、以前はnewしていましたが、今はNotification.Builderを使って作成するため、両方の作り方を記載しています。
ここでは通知の発行は下記の関数を用意しました。
private void showNotification() { NotificationManager manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE); Intent intent = new Intent(this, SubAppActivity.class); PendingIntent contentIntent = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT); String tickerText = getString(R.string.hello); Notification notification; try { Class.forName("android.app.Notification$Builder"); notification = new Notification.Builder(this) .setContentIntent(contentIntent) .setSmallIcon(android.R.drawable.stat_sys_download) .setTicker(tickerText) .setContentTitle("Title") .setContentText("Text") .setWhen(System.currentTimeMillis()) .getNotification(); } catch (ClassNotFoundException e) { notification = new Notification(android.R.drawable.stat_sys_download, tickerText, System.currentTimeMillis()); notification.setLatestEventInfo(this, "TITLE", "TEXT", contentIntent); } manager.notify(1, notification); }
タップされると起動するSubAppActivityは単独のタスクとするため、AndroidManifestで下記のようにActivityを設定します。
<activity android:name="SubAppActivity" android:launchMode="singleTask" android:taskAffinity="" android:excludeFromRecents="true"> </activity>
実行すると、まずアイコンとTickerが表示されます。
通知を開くとアイコン、TitleとTextが表示され、タップするとSubAppActivityが独立したタスクで起動します。
参考:Android Developers:Status Notifications
June 17, 2012
List Viewの作り方とカスタマイズ
List Viewの作り方とカスタマイズ方法です。
List Viewはその名の通り、リスト表示を行う専用のViewです。標準はテキストのみのリスト表示ですが、カスタマイズすることで画像付きのテキストなど自由なレイアウトでリスト表示することができるようになります。
リスト表示するときは通常のActivityではなく、ListActivityというリスト表示専用のActivityを使います。このListActivityのデフォルトはsetContentViewでレイアウトを指定しなくても全画面がListViewになっていますが、あえて設定することで通常のActivityのように自由なレイアウトでListViewを配置することもできます。ただし配置できるListViewは1つだけで、そのid属性に"@android:id/list"とする必要があります。
例)中央にリスト表示、最上部にタイトルのテキスト、最下部にボタンの3段構成で表示する場合、レイアウトは下記のようにします。
リスト表示の1行ごとのレイアウトとそこで表示するデータを決めます。ここでは左端にアイコン画像、右側にテキストを表示するレイアウトにします。
表示に必要なデータはクラスで定義します。コンストラクタで初期値を設定できるようにしておくと便利です。
このデータを使ってレイアウトに表示するクラスを作ります。ArrayAdapterを継承して独自のカスタマイズクラスを作ります。このクラスの役割はgetView()で上記で作ったレイアウトに指定された行のデータを設定したViewを生成することです。そのViewがリストの1行として表示されます。
ListActivityで実際に表示する具体的なデータのリストをArrayListで作成し、それを使って上記のMyListAdapterを作成します。それをListActivityに設定すればリスト表示の完成です。また、アイテムをクリックされた時の処理は、ListActivityが持っているListViewのOnItemClickListenerが呼ばれるので、ここではデータのリストからタイトルを取得して表示するようにしています。
実行すると下記のような表示になります。
参考:Android Developers:ListActivity
参考:Android Developers:ListView
参考:Android Developers:ArrayAdapter
参考:Android Developers:Hello, Views - List View
List Viewはその名の通り、リスト表示を行う専用のViewです。標準はテキストのみのリスト表示ですが、カスタマイズすることで画像付きのテキストなど自由なレイアウトでリスト表示することができるようになります。
リスト表示するときは通常のActivityではなく、ListActivityというリスト表示専用のActivityを使います。このListActivityのデフォルトはsetContentViewでレイアウトを指定しなくても全画面がListViewになっていますが、あえて設定することで通常のActivityのように自由なレイアウトでListViewを配置することもできます。ただし配置できるListViewは1つだけで、そのid属性に"@android:id/list"とする必要があります。
例)中央にリスト表示、最上部にタイトルのテキスト、最下部にボタンの3段構成で表示する場合、レイアウトは下記のようにします。
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/layout" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <TextView android:id="@+id/text" android:background="#EE3333" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="@string/myname" /> <ListView android:id="@android:id/list" android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1" /> <Button android:id="@+id/button" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="@string/launch" /> </LinearLayout>
リスト表示の1行ごとのレイアウトとそこで表示するデータを決めます。ここでは左端にアイコン画像、右側にテキストを表示するレイアウトにします。
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="horizontal" > <ImageView android:id="@+id/icon" android:layout_width="wrap_content" android:layout_height="wrap_content" /> <TextView android:id="@+id/title" android:layout_width="0dip" android:layout_weight="1" android:layout_height="wrap_content" /> </LinearLayout>
表示に必要なデータはクラスで定義します。コンストラクタで初期値を設定できるようにしておくと便利です。
public class MyItems { public int mIconId; public String mTitle; public MyItems(int iconId, String title) { mIconId = iconId; mTitle = title; } }
このデータを使ってレイアウトに表示するクラスを作ります。ArrayAdapterを継承して独自のカスタマイズクラスを作ります。このクラスの役割はgetView()で上記で作ったレイアウトに指定された行のデータを設定したViewを生成することです。そのViewがリストの1行として表示されます。
public class MyListAdapter extends ArrayAdapter<MyItems> { private LayoutInflater mInflater; public MyListAdapter(Context context, int textViewResourceId, List<MyItems> objects) { super(context, textViewResourceId, objects); mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); } @Override public View getView(int position, View convertView, ViewGroup parent) { MyItems items = getItem(position); if (convertView == null) { convertView = mInflater.inflate(R.layout.row, null); } // Icon ImageView imageView = (ImageView) convertView.findViewById(R.id.icon); imageView.setImageResource(items.mIconId); // Title TextView textView = (TextView) convertView.findViewById(R.id.title); textView.setText(items.mTitle); return convertView; } }
ListActivityで実際に表示する具体的なデータのリストをArrayListで作成し、それを使って上記のMyListAdapterを作成します。それをListActivityに設定すればリスト表示の完成です。また、アイテムをクリックされた時の処理は、ListActivityが持っているListViewのOnItemClickListenerが呼ばれるので、ここではデータのリストからタイトルを取得して表示するようにしています。
public class SampleAppActivity extends ListActivity { private final static String TAB = "SampleAppActivity"; private List<MyItems> mMylist; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); mMylist = new ArrayList<MyItems>(); mMylist.add(new MyItems(android.R.drawable.ic_menu_today, "Today")); mMylist.add(new MyItems(android.R.drawable.ic_menu_agenda, "Agenda")); mMylist.add(new MyItems(android.R.drawable.ic_menu_gallery, "Gallery")); mMylist.add(new MyItems(android.R.drawable.ic_menu_month, "Month")); mMylist.add(new MyItems(android.R.drawable.ic_menu_mylocation, "My Location")); mMylist.add(new MyItems(android.R.drawable.ic_menu_rotate, "Rotate")); mMylist.add(new MyItems(android.R.drawable.ic_menu_more, "More...")); setListAdapter(new MyListAdapter(this, 0, mMylist)); getListView().setOnItemClickListener(new OnItemClickListener() { @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { MyItems items = mMylist.get(position); Log.i(TAB, "Clicked:" + items.mTitle); } }); } }
実行すると下記のような表示になります。
参考:Android Developers:ListActivity
参考:Android Developers:ListView
参考:Android Developers:ArrayAdapter
参考:Android Developers:Hello, Views - List View
Action Barからサブメニューを表示する
Action Barのオプションメニューからサブメニューを表示する方法です。
Action Barにオプションメニューを表示するまでは「Action Barにオプションメニューを表示する」を参照してください。ここでは、そこからの差分を説明します。
サブメニューを表示するには、ActionProviderクラスを使用します。このクラスを継承してユーザー独自のクラスを作ることでオリジナルのサブメニューが表示できます。
呼び出し先のActionProviderクラスを作成します。後でViewを作成するためにコンストラクタでcontextを保存しておくのが通例です。onCreateActionViewではViewを返す必要はなくnullで構いません。サブメニューがあることを伝えるためにhasSunMenu()ではtrueを返します。メニュー表示のたびにonPrepareSubMenu()が呼ばれるので、そこでサブメニューを作成します。この例ではxmlで作ったmenuリソースをセットし、それをクリックしたときのリスナーを自分自身になるようにしています(onMenuItemClick()が呼ばれます)。
実行すると下記のようになります。Action Barのオプションメニューの2番目のShareアイコンのボタンを押すとサブメニューが現れます。
Action Barにオプションメニューを表示するまでは「Action Barにオプションメニューを表示する」を参照してください。ここでは、そこからの差分を説明します。
サブメニューを表示するには、ActionProviderクラスを使用します。このクラスを継承してユーザー独自のクラスを作ることでオリジナルのサブメニューが表示できます。
まずはオプションメニューからサブメニューを呼び出します。呼び出すには"actionProviderClass"属性にクラス名を設定します。これでこのメニューアイテムが選択されると、このクラスを呼び出します。
<?xml version="1.0" encoding="utf-8"?> <menu xmlns:android="http://schemas.android.com/apk/res/android" > <item android:id="@+id/item1" android:showAsAction="ifRoom|collapseActionView" android:icon="@android:drawable/ic_menu_search" android:actionViewClass="android.widget.SearchView"></item> <item android:id="@+id/item2" android:icon="@android:drawable/ic_menu_share" android:showAsAction="ifRoom" android:actionProviderClass="jp.myapp.sample.SampleActionProvider"></item> <item android:id="@+id/item3" android:title="@string/menu3" android:showAsAction="ifRoom"></item> <item android:id="@+id/item4" android:title="@string/menu4" android:showAsAction="ifRoom"></item> </menu>
呼び出し先のActionProviderクラスを作成します。後でViewを作成するためにコンストラクタでcontextを保存しておくのが通例です。onCreateActionViewではViewを返す必要はなくnullで構いません。サブメニューがあることを伝えるためにhasSunMenu()ではtrueを返します。メニュー表示のたびにonPrepareSubMenu()が呼ばれるので、そこでサブメニューを作成します。この例ではxmlで作ったmenuリソースをセットし、それをクリックしたときのリスナーを自分自身になるようにしています(onMenuItemClick()が呼ばれます)。
public class SampleActionProvider extends ActionProvider implements OnMenuItemClickListener { private final static String TAB = "SampleActionProvider"; private Context mContext; public SampleActionProvider(Context context) { super(context); mContext = context; } @Override public View onCreateActionView() { return null; } @Override public boolean hasSubMenu() { return true; } @Override public void onPrepareSubMenu(SubMenu subMenu) { subMenu.clear(); MenuInflater inflator = new MenuInflater(mContext); inflator.inflate(R.menu.provider_menu, subMenu); for (int i = 0; i < subMenu.size(); ++i) { subMenu.getItem(i).setOnMenuItemClickListener(this); } } @Override public boolean onMenuItemClick(MenuItem item) { Log.i(TAB, "Title:" + item.getTitle()); return true; } }
<?xml version="1.0" encoding="utf-8"?> <menu xmlns:android="http://schemas.android.com/apk/res/android" > <item android:id="@+id/item1" android:title="@string/menu1" android:icon="@android:drawable/ic_menu_compass"></item> <item android:id="@+id/item2" android:title="@string/menu2" android:icon="@android:drawable/ic_menu_camera"></item> </menu>
実行すると下記のようになります。Action Barのオプションメニューの2番目のShareアイコンのボタンを押すとサブメニューが現れます。
June 16, 2012
Action Barにオプションメニューを表示する
Action Barにオプションメニューを表示する方法です。Action BarはAndroid 3.0(API 11)から追加された機能ですので、それ以上のデバイスで有効です。Action Barとは画面最上部に表示されるバー(アイコンやタイトルなどが表示される)のことです。
オプションメニューの作り方は「オプションメニューの表示」を参照してください。ここではその差分を説明します。
メニューのリソースを下記のように作成します。差分は"showAsAction"属性に"ifRoom"を設定していることです。この設定をすると、スペースがあればAction Barに表示するようになります。
縦スクリーンで表示した場合、一部のみAction Barに表示されています。残りはオプションメニューでの表示となります。
横スクリーンで表示した場合、スペースがあるため、すべてAction Barに表示されています。
Action Barはアイコン優先、オプションメニューではテキストが表示されます。
また、縦スクリーンでは右上に表示するのではなく、画面下部に分割して表示することも可能です(横幅が狭いときのみ有効なので、幅広な横スクリーンでは使えません)。AndroidManifest.xmlのapplicationやactivityに下記のような"uiOptions"を設定します。
参考:Android Developers:Action Bar
参考:Android Developers:Action Bar Icons
オプションメニューの作り方は「オプションメニューの表示」を参照してください。ここではその差分を説明します。
メニューのリソースを下記のように作成します。差分は"showAsAction"属性に"ifRoom"を設定していることです。この設定をすると、スペースがあればAction Barに表示するようになります。
<?xml version="1.0" encoding="utf-8"?> <menu xmlns:android="http://schemas.android.com/apk/res/android" > <item android:id="@+id/item1" android:title="@string/menu1" android:showAsAction="ifRoom" android:icon="@android:drawable/ic_menu_add"></item> <item android:id="@+id/item2" android:icon="@android:drawable/ic_menu_share" android:showAsAction="ifRoom"></item> <item android:id="@+id/item3" android:title="@string/menu3" android:showAsAction="ifRoom"></item> <item android:id="@+id/item4" android:title="@string/menu4" android:showAsAction="ifRoom"></item> </menu>
縦スクリーンで表示した場合、一部のみAction Barに表示されています。残りはオプションメニューでの表示となります。
横スクリーンで表示した場合、スペースがあるため、すべてAction Barに表示されています。
Action Barはアイコン優先、オプションメニューではテキストが表示されます。
また、縦スクリーンでは右上に表示するのではなく、画面下部に分割して表示することも可能です(横幅が狭いときのみ有効なので、幅広な横スクリーンでは使えません)。AndroidManifest.xmlのapplicationやactivityに下記のような"uiOptions"を設定します。
<application android:icon="@drawable/ic_launcher" android:label="@string/app_name" android:uiOptions="splitActionBarWhenNarrow">
参考:Android Developers:Action Bar
参考:Android Developers:Action Bar Icons
オプションメニューの表示
オプションメニューの表示方法です。メニューボタンを押すと表示されるオプションメニューのことです。
作り方は、menuリソース(xml)を作成し、res/menuにおきます。初期化時に1回だけonCreateOptionsMenu()が呼ばれるので、そこでメニューアイテムを登録し、メニューアイテムが選択されるとonOptionsItemSelected()が呼ばれるので、そこに押された時の処理を加えます。
例)4つのメニューアイテムを持つ場合
メニュー1だけシステムの画像を設定して表示していますが、独自の画像を使うこともできます(デザイン方法は参考を参照)。メニューアイテムは最大6つまで同時に表示され、それ以上は6つ目のアイテムがMoreにかわり、ダイアログがでて6つ以上のメニューアイテムも選択できます。
Android 2.3(API 10)までのデバイスで実行すると下記のように表示されます。
Android 3.0(API 11)以降のデバイスで実行すると下記のように表示されます。
この違いは、今回の手法がAndroid2.3(API 10)までを対象としたやり方のためです。Android 3.0からは物理的なメニューボタンを必須からオプション扱いにしたため、それにあわせてオプションメニューに対するUIも変更したからです。Android 3.0からはAction Barというものが表示されるようになり、基本的にオプションメニューはそこに表示して、よりダイレクトに選択できるUIにかえています。
Android 3.0以降でもAction Barなしのテーマを選択している場合、Action BarがないのでAndroid 2.3以前と同様な表示になります。
参考:Android Developers:Activity
参考:Android Developers:Say Goodbye to the Menu Button
参考:Android Developers:Menu Icons
作り方は、menuリソース(xml)を作成し、res/menuにおきます。初期化時に1回だけonCreateOptionsMenu()が呼ばれるので、そこでメニューアイテムを登録し、メニューアイテムが選択されるとonOptionsItemSelected()が呼ばれるので、そこに押された時の処理を加えます。
例)4つのメニューアイテムを持つ場合
public class SampleAppActivity extends Activity { private final static String TAB = "SampleAppActivity"; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); } @Override public boolean onCreateOptionsMenu(Menu menu) { super.onCreateOptionsMenu(menu); MenuInflater inflater = getMenuInflater(); inflater.inflate(R.menu.mymenu, menu); return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { boolean ret = true; switch (item.getItemId()) { case R.id.item1: Log.i(TAB, "Menu item 1"); break; case R.id.item2: Log.i(TAB, "Menu item 2"); break; case R.id.item3: Log.i(TAB, "Menu item 3"); break; case R.id.item4: Log.i(TAB, "Menu item 4"); break; default: ret = super.onOptionsItemSelected(item); } return ret; } }
<?xml version="1.0" encoding="utf-8"?> <menu xmlns:android="http://schemas.android.com/apk/res/android" > <item android:id="@+id/item1" android:title="@string/menu1" android:icon="@android:drawable/ic_menu_add"></item> <item android:id="@+id/item2" android:title="@string/menu2"></item> <item android:id="@+id/item3" android:title="@string/menu3"></item> <item android:id="@+id/item4" android:title="@string/menu4"></item> </menu>
メニュー1だけシステムの画像を設定して表示していますが、独自の画像を使うこともできます(デザイン方法は参考を参照)。メニューアイテムは最大6つまで同時に表示され、それ以上は6つ目のアイテムがMoreにかわり、ダイアログがでて6つ以上のメニューアイテムも選択できます。
Android 2.3(API 10)までのデバイスで実行すると下記のように表示されます。
Android 3.0(API 11)以降のデバイスで実行すると下記のように表示されます。
この違いは、今回の手法がAndroid2.3(API 10)までを対象としたやり方のためです。Android 3.0からは物理的なメニューボタンを必須からオプション扱いにしたため、それにあわせてオプションメニューに対するUIも変更したからです。Android 3.0からはAction Barというものが表示されるようになり、基本的にオプションメニューはそこに表示して、よりダイレクトに選択できるUIにかえています。
Android 3.0以降でもAction Barなしのテーマを選択している場合、Action BarがないのでAndroid 2.3以前と同様な表示になります。
参考:Android Developers:Activity
参考:Android Developers:Say Goodbye to the Menu Button
参考:Android Developers:Menu Icons
Subscribe to:
Posts (Atom)