【Android】Serviceをつかってみる
バックグラウンドで動くプログラムServiceを使ってみました。
Serviceの使用方法
Serviceの起動方法には、
startService()
を使用bindService()
を使用
の大きく分けて2種類があります。
Service起動方法の違い
起動方法による違いは、以下のとおりです。
startService
- Service起動中は、ActivityへIntentの発行が可能。
- Service起動後は、ActivityからServiceを制御する経路がない。
- Serviceの生存期間はActivityに依存しない。明示的にstopServiceが呼ばれるまで動き続ける。
bindService
- バインドを使うことでActivityからServiceを制御できる。
- Serviceの生存期間はコネクションに依存。コネクションが切断されるとServiceは終了する。
startService()を使用した起動
startService()
を使用して、Serviceを起動した時のライフサイクルを以下に記載します。
順序 | メソッド | 説明 |
---|---|---|
1 | onCreate() | Serviceが初回作成時に呼ばれる。 |
2 | onStartCommand() | クライアントが明示的にstartService(Intent)を呼び出したタイミングで呼ばれる。 このメソッドを直接呼び出してはいけない。 APIレベル5以前は、 onStart() が使用されるため注意。 |
3 | onDestroy() | Serviceが使用されなくなったタイミングで呼ばれる Serviceの持っているリソースをクリーンアップする。 |
サンプルソース
■ AndroidManifest.xml
<service android:name="Service名" />
■ Activityの呼び出し
public class MainActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Button startButton = (Button) findViewById(R.id.startService); startButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { // Serviceの起動 Intent intent = new Intent(MainActivity.this, MyService.class); startService(intent); } }); Button stopButton = (Button) findViewById(R.id.stopService); stopButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { // Serviceの停止 Intent intent = new Intent(MainActivity.this, MyService.class); stopService(intent); } }); } }
■ Serviceクラス
public class MyService extends Service { @Override public void onCreate() { super.onCreate(); Log.d("service", "onCreate"); } @Override public int onStartCommand(Intent intent, int flags, int startId) { Log.d("service", "onStartCommand"); return super.onStartCommand(intent, flags, startId); } @Override public void onDestroy() { Log.d("service", "onDestroy"); super.onDestroy(); } }
bindService()を使用した起動方法
bindService()
を使用して、Serviceを起動した時のライフサイクルを以下に記載します。
順序 | メソッド | 説明 |
---|---|---|
1 | onCreate() | Serviceが初回作成時に呼ばれる。 |
2 | onBind() | Service接続時に呼ばれる。ServiceとActivityを仲介するIBinder を返却する。 |
3 | ServiceConnection# onServiceConnected() |
Service接続後、Binderが確立したタイミングで呼び出される。 |
4 | unBind() | クライアントがServiceと切断されたタイミングで呼ばれる。 |
5 | onDestroy() | Serviceが使用されなくなったタイミングで呼ばれる。 Serviceの持っているリソースをクリーンアップする。 |
ServiceをbindService()
経由で呼び出す場合は、インタフェースとしてServiceConnection
を使用します。
ServiceConnectionによって取得するIBinder
を介することで、Serviceへの制御を行うことが可能です。
サンプルソース
■ AndroidManifest.xml
<service android:name="Service名" />
■ Activityの呼び出し
public class MainActivity extends Activity { // Serviceとのインターフェースクラス private ServiceConnection mConnection = new ServiceConnection() { BindService mBindService; public void onServiceConnected(ComponentName className, IBinder service) { // Serviceとの接続確立時に呼び出される。 // service引数には、Onbind()で返却したBinderが渡される mBindService = ((BindService.LocalBinder)service).getService(); //必要であればmBoundServiceを使ってバインドしたServiceへの制御を行う } public void onServiceDisconnected(ComponentName className) { // Serviceとの切断時に呼び出される。 mBindService = null; } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Button bindButton = (Button) findViewById(R.id.bindtService); bindButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { // Serviceをbindする Intent i = new Intent(MainActivity.this,BindService.class); bindService(i, mConnection, Context.BIND_AUTO_CREATE); } }); Button unbindButton = (Button) findViewById(R.id.unbindService); unbindButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { // Serviceをunbindする unbindService(mConnection); } }); } }
■ Serviceクラス
public class BindService extends Service { // Serviceに接続するためのBinderクラスを実装する public class LocalBinder extends Binder { //Serviceの取得 BindService getService() { return BindService.this; } } // Binderの生成 private final IBinder mBinder = new LocalBinder(); @Override public IBinder onBind(Intent intent) { // Service接続時に呼び出される // 戻り値として、Serviceクラスとのbinderを返す。 Log.i("", "onBind" + ": " + intent); return mBinder; } @Override public void onRebind(Intent intent){ // Unbind後に再接続する場合に呼ばれる Log.i("", "onRebind" + ": " + intent); } @Override public boolean onUnbind(Intent intent){ // Service切断時に呼び出される //onUnbindをreturn trueでoverrideすると次回バインド時にonRebildが呼ばれる return true; } }
参考
http://www.techdoctranslator.com/android/guide/services/bound-services
http://yuki312.blogspot.jp/2012/07/androidserviceonstartcommand.html
http://techbooster.org/android/application/3270/
【Andoid】AsyncTaskLoaderを使ってみる
Android 3.0から導入されたLoaderについて、
参考サイトをもとに勉強していましたがいまいちよくわからず。。
Loaderを継承した、AsyncTaskLoader
の方が使い方がわかりやすそうだったので、
まずはこちらを使用してみました。
Loaderの基本クラス
Loader
非同期のデータロードを行う為の抽象クラス。
LoaderManager
Loaderインスタンスを管理するためのクラス。
LoaderManagerインスタンスは、1つ以上のLoaderインスタンスを管理する。
Activityまたは、Fragmentごとに1つしか作られない。
LoaderManager.LoaderCallbacks
Activityまたは、FragmentとLoaderManager間で、
双方向にやりとりするためのコールバックインターフェース。
AsyncTaskLoaderを使ってみる
Activity側の実装
Activity側の実装では、Loaderを管理するLoaderManager
インスタンスを初期化する必要があります。
また、LoaderManagerから状態を受け取るためのコールバックとしてLoaderManager.LoaderCallbacks
インターフェースが用意されているため、Activityにこれを実装します。
LoaderManager
の初期化には、getLoaderManager().initLoader()
を使用します。
initLoader()
は、Activity.onStart()
よりも早く呼び出す必要があります。
引数について、以下のとおりです。
引数 | 詳細 |
---|---|
第一引数: int id |
Loaderの識別子。 onCreateLoader()第一引数に渡される。 |
第二引数: Bundle args |
Loaderへのパラメタ。 onCreateLoaderメソッドの第二引数に渡される。 Loaderがすでに生成されている場合は、この値は無視される。 |
第三引数: LoaderCallback callback |
Loaderの状態変化に使用される。 LoaderCallbackインターフェースを継承したクラスを指定する。 |
以下に、実装のサンプルを記載します。
// LoaderCallbacksのジェネリクスには、Loaderの戻り値の型を指定する(以下は、String) public class MainActivity extends Activity implements LoaderCallbacks<String> { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // LoaderManagerの初期化 getLoaderManager().initLoader(0, null, this); } @Override public Loader<String> onCreateLoader(int id, Bundle args) { // Loderを初期化する MyLoader loader = new MyLoader(this); return loader; } @Override public void onLoadFinished(Loader<String> loader, String data) { // dataでは、Loderクラスの戻り値が返される // Loderの終了処理 Log.d("","onLoadFinished"); } @Override public void onLoaderReset(Loader<String> arg0) { // Loderが、リセットされるときに呼ばれる。 // ここで、もらっているdataを破棄する必要がある。 Log.d("","onLoaderReset"); } }
Loaderの実装
非同期処理を行うLoaderクラスは、AsyncTaskLoader
クラスを継承して作成します。
Loaderが処理を開始するには、forceLoad()
を呼び出す必要があり、
以下のサンプルでは、Loderの準備が完了した際に呼ばれるonStartLoading()
で実行しています。
実際にバックグラウンドで行う処理は、loadInBackground()
に記載します。
public static class MyLoader extends AsyncTaskLoader<String> { public MyLoader(Context context) { super(context); } @Override public void deliverResult(String data) { // Loderが処理した結果を返す。(メインスレッドで実行される) super.deliverResult(data); } @Override public String loadInBackground() { // Loderが実行するバックグラウンド処理 return "abc"; } @Override protected void onStartLoading() { // Loder側の準備ができたタイミングで呼び出される // UIスレッドで実装される forceLoad(); } }
注意点
AsyncTaskLoaderを使う上で幾つか注意すべき点があります。
呼び出し元のActivityがアクティブでないと、
onLoadFinished()
コールバックが呼ばれないため、 それを考慮した実装を行う必要があります。Loaderインスタンスの
onStartLoading()
は、Activityがアクティブになったタイミングで呼ばれます。(何度も呼ばれる) その為、一度処理した内容が再度処理されないように意識した実装を行う必要があります。
※こちらを参考にしました。
これらを考慮したサンプルを以下に記載します。
public static class MyLoader extends AsyncTaskLoader<String> { private String data; public AsyncLoader(Context context) { super(context); } @Override public void deliverResult(D data) { if (isReset()) { return; } this.data = data; super.deliverResult(data); } @Override public String loadInBackground() { return "abc"; } @Override protected void onStartLoading() { if (data != null) { deliverResult(data); } if (takeContentChanged() || data == null) { forceLoad(); } } @Override protected void onStopLoading() { cancelLoad(); } @Override protected void onReset() { super.onReset(); onStopLoading(); data = null; } }
参考
http://www.techdoctranslator.com/android/guide/activities/loaders http://blog.loadlimits.info/2012/09/asynctaskloaderのあるactivityに戻ってきたときに再度loadinbackgroundが呼ば/ http://ijoru.com/ijoru/?p=207
【Android】DialogFragmentを使ってみる
Android 3.0以降、ダイアログの表示には、DialogFragment
を使用することが推奨されているようです。
基本的な表示処理は、Fragmentと変わらないみたいなのですが、
使用したことがなかったので試してみました。
DialogFragmentの表示
ダイアログを表示するには、DialogFragment
を継承したクラスを作成して、
各メソッドを継承します。
最低限ダイアログの表示を確認するのであれば、onCreateDialog()
を継承し、
表示したいDIalog
クラスのインスタンスを返却してあげればOKです。
public class MyDialogFragment extends DialogFragment { @Override public Dialog onCreateDialog(Bundle savedInstanceState) { AlertDialog.Builder alert = new AlertDialog.Builder(getActivity()) .setTitle("タイトル") .setMessage("メッセージ") .setPositiveButton("OK", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { dismiss(); } }); return alert.create(); } }
ただし、Fragment
を継承したDialogFragment
は、
Fragment
と同様に再生成時にデフォルトコンストラクタが呼ばれる使用のため、
初期化時は、以下のようにsetArguments()
を使用するのがお作法です。
public static final MyDialogFragment newInstance(int flags) { Bundle args = new Bundle(); args.putInt("flags", flags); MyDialogFragment fragment = new MyDialogFragment(); fragment.setArguments(args); return fragment; }
ハマったところ
DialogFragmet
の表示処理(初期化を含む)をActivityのOnCreate()
に記載していたのですが、
回転処理で異常終了が発生する不具合がありました。
DialogFragmet
の実装クラスがインナークラスとして宣言されている場合、
Publicな標準コンストラクタが呼び出せず例外が発生するようです。
そのためDialogFragmet
は、Publicなクラスとして使用するのが一般的なようです。
【Android】Fragmentを使ってみる
Fragment は Android 3.0 ( API レベル "Honeycomb" ) から使用できるようになったコンポーネントです。
Fragmentを使用することで、一つのActivityに対して複数のUIを構築することが可能で、
画面の一部に対してのUI切り替えや遷移などを柔軟に行うことができます。
Fragmentの実装
Fragmentを実装するには、最低限、以下のメソッドを実装する必要があります。
Activityの状態 | Fragmentで呼ばれるコールバック |
---|---|
onCreate() | システムが、Fragmentを作成したときに呼び出される。 コンポーネントの初期化処理などをここで行う。 |
onCreateView() | FragmentのUIが描画されるタイミングでよびだされる。 FragmentのレイアウトのRootになっているViewをここでinflateする。 |
onPause() | Fragmentが停止するときによばれる。 Fragmentで変更されたステータスの保存はここで行う。 |
他にも様々なライフサイクルメソッドが存在しますが、今回は割愛します。
Fragmentに対してlayoutを紐付けるには、以下のようにonCreateView()
でinflateを行います。
public class SampleFragment extends Fragment { @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { return inflater.inflate(R.layout.sample_fragmet, container, false); } }
Fragmentの表示方法
Activityから、Fragmentを表示するためには、FragmentManager
を使用します。
Fragmentの追加・削除・交換などのアクションは、FragmentTransaction
によってコミット単位で管理されており、FragmentManager
から取得できるFragmentTransaction
に対して、
各アクションを適用することで、Fragmentの管理を行うことが可能です。
新規で作成したFragmentの表示を行うためには以下のように記載します。
表示したいViewGroupに対して、Fragmentをadd()
メソッドにより追加し
最後にcommit()
を呼び出すことで対象のFragmentを表示することができます。
FragmentManager fragmentManager = getFragmentManager(); FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction(); FirstFragment fragment = new FirstFragment(); fragmentTransaction.add(R.id.fragment_container, fragment, "tag"); fragmentTransaction.commit();
Fragmentをバックスタックに追加する
FragmentをFragmentTransaction
のバックスタックに追加することで、
スタック管理を行うことができます。
バックスタックはActivityにより管理されており、
ユーザがBACKキーを押すことにより前のFragmentへ戻ることが可能です。
以下は、表示中のFragmentを新しいFragmentと入れ替えるサンプルです。
addToBackStack(null)
を呼び出すことにより元のFragmentをバックスタックへ追加しています。
FragmentManager fragmentManager = getFragmentManager(); FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction(); SecondFragment secondFragment = new SecondFragment(); fragmentTransaction.replace(R.id.fragment_container, secondFragment); fragmentTransaction.addToBackStack(null); fragmentTransaction.commit();
Fragment生成時の注意事項
Fragmentの生成処理は、一般的に下記のようなstaticメソッドが使用されます。
public static SampleFragment newInstance(int index) { SampleFragment f = new SampleFragment(); Bundle args = new Bundle(); args.putInt("index", index); f.setArguments(args); return f; }
これは、システムがFragmentの再生成を行うときに、デフォルトのコンストラクタが呼ばれる為、
独自のコンストラクタを使用したパラメタの引き渡しができないという理由からです。
システムは、例えばメモリ不足などで破棄されたFragmentを再生成する時に、 Fragment#instantiate(Context context, String fname, Bundle args)) メソッドを使用します。
このメソッドは、引数で渡されたクラス名(fname)のFragmentを標準コンストラクタで呼び出してインスタンスを生成したのち、第3引数でセットしたBundleをsetArguments()でセットしてから返します。
そのため、Fragment生成に必要な引数がある場合は、
初期化時にsetArguments()
を使用してパラメタを渡す必要があります。
ライフサイクル
Fragmentのライフサイクルは、Activityに似たつくりになっています。
FragmentはActivityによって保持されているため、お互いのライフサイクルは連動していて、
例えば、ActivityがonPause()
を受け取ると、ActivityのそれぞれのFragmentはonPause()
を受け取ります。
Activityの状態とFragmentのコールバックメソッドの関連
Activityの状態 | Fragmentで呼ばれるコールバック |
---|---|
create | OnAttach ↓ OnCreate() ↓ OnCreateView() ↓ OnActivityCreated() |
start | OnStart() |
resume | OnResume() |
pause | OnPause() |
stop | OnStop() |
destroyed | OnDestroyView() ↓ OnDestroy() ↓ OnDetach() |
参考
https://sites.google.com/a/techdoctranslator.com/jp/android/guide/activities/fragments
【Android】ActionBarのAppIconを使ってみる
ActionBarの左上のAppIcon領域には、自由にロゴ画像を配置することが可能です。
また、タップイベントを有効することで画面の遷移ナビゲーションを管理することも可能です。
AppIconのロゴを変更する
1.AndroidManifest.xmlで指定する
AndroidManifest.xml
からAppIconの画像を変更するには、
Activity
要素にあるandroid:logo
に表示したい画像リソースを指定します。
<activity android:name="com.example.actionbarmove.SampleActivity" android:logo="@drawable/icon" > </activity>
2.ソースから指定する
ソース上から、画像を変更するには、getActionBar()
で取得した
ActionBarに対してsetLogo()
を使用します。
getActionBar().setLogo(R.drawable.icon);
タップイベントを取得する
AppIconのタップイベントを取得するには、
ActionBarに対して、setDisplayHomeAsUpEnabled(true)
を実行します。
上記メソッドを実行するとAppIconのアイコンに<
マークが付き、
タップイベントを取得できるようになります。
getActionBar().setDisplayHomeAsUpEnabled(true)
タップイベントを取得するには、
Activityクラスで、onOptionsItemSelected()
メソッドをオーバーライドします。
AppIconには、android.R.id.home
というリソースIDが割り振られいるため、
これをハンドリングします。
下記の実装では、AppIconを押下されたタイミングで、ホーム画面へ遷移を行っています。
Intent.FLAG_ACTIVITY_CLEAR_TOP
を付与して画面遷移を行うことでActivityスタックをクリアし、
どの画面から遷移してもホーム画面へ戻ることが可能です。
@Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case android.R.id.home: // app icon in Action Bar clicked; go home Intent intent = new Intent(this, HomeActivity.class); intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); startActivity(intent); return true; default: return super.onOptionsItemSelected(item); } }
参考
http://www.techdoctranslator.com/android/guide/ui/actionbar
http://dev.classmethod.jp/smartphone/android-tips-10-AppIcon/
【Android】ActionBarにタブコントロールを実装する
ActionBarには、フラグメントを切り替えるタブコントロールを実装することができます。
タブには、タイトル文字列やアイコン画像をセットすることが可能です。
TabListenerの実装
アクションバータブのイベントを制御するにはActionBar.TabListener
を実装する必要があります。
各abstractメソッドは、以下のとおりです。
メソッド | 概要 |
---|---|
onTabSelected() | タブが選択された時に呼ばれる |
onTabUnselected() | タブが非選択になった時に呼ばれる |
onTabReselected() | 同じタブが再度選択された時に呼ばれる |
実装メソッドには、イベントを受け取ったActionBar.Tab
インスタンスおよびFragmentTransaction
インスタンスが引数として渡されます。
コンストラクタにてあらかじめ対象のフラグメントを渡しておき、
上記の実装メソッドでフラグメントの追加や削除を行います。
MyTabListener.java
public class MyTabListener implements ActionBar.TabListener { private Fragment mFragment; // 新規タブを作成する際にフラグメントインスタンスを一緒に渡す public MyTabListener(Fragment fragment) { mFragment = fragment; } @Override public void onTabSelected(Tab tab, FragmentTransaction ft) { // タブが選択された時の処理 // フラグメントを追加する ft.add(R.id.fragment_content, mFragment, null); } @Override public void onTabUnselected(Tab tab, FragmentTransaction ft) { // タブが切り替えられた時の処理 // フラグメントを削除する ft.remove(mFragment); } @Override public void onTabReselected(Tab tab, FragmentTransaction ft) { // 同じタブを再度タップされた時の処理 // do nothing } }
注意事項
トランザクションの管理は、システムが代わりに呼び出しを行うため、
FragmentTransaction
に対してcommit()
を呼び出してはいけません。
自分で呼び出した場合は、例外が投げられる可能性があります。
また、トランザクションをバックスタックに追加することもできません。
ActionBarの実装
ActivityクラスにてgetActionBar()
を使って取得したActionBarインスタンスに対して、
setNavigationMode(ActionBar.NAVIGATION_MODE_TABS)
を設定することで、
ActionBarをタブ表示モードへ切り替えることができます。
final ActionBar actionBar = getActionBar(); actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
ActionBarに対してタブを追加するには、
actionBar.newTab()
で取得したインスタンスをaddTab()
にて追加します。
この時、タブに対してタイトル及びアイコン画像をセットすることが可能です。
また、タブの切り替え制御を行うために、上記で作成したActionBar.TabListener
をセットします。
// フラグメントを生成してTabへセット Fragment fragment1 = new Fragment1(); ActionBar.Tab tab1 = actionBar.newTab(); tab1.setText("タブタイトル1"); // タイトル文字列 tab1.setIcon(R.drawable.ic_launcher); // アイコン tab1.setTabListener(new MyTabListener(fragment1)); // リスナー actionBar.addTab(tab1);
これでActionBarに対してタブコントロールを実装することができました。
今回実装した、サンプルソースを記載します。
MainActivity.java
// APIレベル11以上のみ対応 @SuppressLint("NewApi") public class MainActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // アクションバーを取得してモードをタブモードへセット final ActionBar actionBar = getActionBar(); actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS); // タイトルを非表示 actionBar.setDisplayShowTitleEnabled(false); // フラグメントを生成してTabへセット Fragment fragment1 = new Fragment1(); // 新しく生成したTabインスタンスには、タイトル文字列、アイコン、リスナーをセットすることができる ActionBar.Tab tab1 = actionBar.newTab(); tab1.setText("タブタイトル1"); tab1.setIcon(R.drawable.ic_launcher); tab1.setTabListener(new MyTabListener(fragment1)); actionBar.addTab(tab1); Fragment fragmet2 = new Fragment2(); actionBar.addTab(actionBar.newTab().setText("タブタイトル2") .setTabListener(new MyTabListener(fragmet2))); } @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; } } class Fragment1 extends Fragment { @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { return inflater.inflate(R.layout.tab1_fragment, container, false); } } class Fragment2 extends Fragment { @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { return inflater.inflate(R.layout.tab2_fragment, container, false); } }
tab1_fragment.xml
<?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="vertical" > <TextView android:layout_width="match_parent" android:layout_height="match_parent" android:text="フラグメント1"/> </LinearLayout>
tab2_fragment.xml
<?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="vertical" > <TextView android:layout_width="match_parent" android:layout_height="match_parent" android:text="フラグメント2"/> </LinearLayout>
参考
【Android】ActionBarに検索バーを表示する
ActionBarは、ActionView
というウィジェットを表示する領域が存在します。
ActionView
は、表示するメニューアイテム(ボタン)と連動して対応するウィジェットを表示することが可能です。
今回は、ActionViewに検索バー(SearchView)を表示してみます。
1.メニューリソースを定義
ActionViewのメニューリソースは、以下の2種類の方法で定義することが可能です。
①android:actionViewClass属性を使う場合
menu/menu.main
<menu xmlns:android="http://schemas.android.com/apk/res/android" > <item android:id="@+id/searchView" android:icon="@android:drawable/ic_menu_search" android:showAsAction="always" android:title="hogehoge" android:actionViewClass="android.widget.SearchView"/> </menu>
②android:actionLayout属性を使う場合
menu/menu.main
<menu xmlns:android="http://schemas.android.com/apk/res/android" > <item android:id="@+id/searchView" android:icon="@android:drawable/ic_menu_search" android:showAsAction="always" android:title="hogehoge" android:actionLayout="@layout/layout_search"/> </menu>
layout/layout_search.xml
<?xml version="1.0" encoding="utf-8"?> <SearchView xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" > </SearchView>
2.ソースの実装
ActionViewのインスタンスは、MenuItem
インスタンスのgetActionView()
メソッドで取得が可能です。
以下のサンプルでは、SearchViewで入力した文字をTextViewに反映しています。
public class MainActivity extends Activity implements OnQueryTextListener { TextView mTextView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mTextView = (TextView) findViewById(R.id.textView); } @Override @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); // SearchViewを取得する MenuItem searchItem = menu.findItem(R.id.searchView); final SearchView searchView = (SearchView) searchItem.getActionView(); searchView.setOnQueryTextListener(this); return true; } @Override public boolean onQueryTextChange(String newText) { return false; } @Override public boolean onQueryTextSubmit(String query) { // テキストViewに検索文字列を表示 mTextView.setText(query); return false; } }