It’s now or never

IT系の技術ブログです。気になったこと、勉強したことを備忘録的にまとめて行きます。

【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を使う上で幾つか注意すべき点があります。


  1. 呼び出し元のActivityがアクティブでないと、onLoadFinished()コールバックが呼ばれないため、 それを考慮した実装を行う必要があります。

  2. 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に対してタブコントロールを実装することができました。

f:id:inon29:20140311214238p:plain


今回実装した、サンプルソースを記載します。

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>

参考

http://www.techdoctranslator.com/android/guide/ui/actionbar

【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;
    }
}