Android Compatibility packageを使って、Fragmentsを1.6上で動かす

Honeycomb(3.0)から使えるというFragmentsですが、これを1.6以上でも使えるようにするstatic libraryが公開されました。
http://android-developers.blogspot.com/2011/03/fragments-for-all.html

ぼくが持っているのはあのIS01で、(いろいろしない限り)1.6しか動きません。というわけで、このライブラリを早速使ってみることにしました。

libraryのインストール

  • SDKのUpdate マネージャからダウンロードします。"Android Compatibility package, revision 1" です。
  • extras/android/compatibility/v4/android-support-v4.jar をbuild pathに追加します。
  • android.support.v4.app.* をimportします

これで使えるようになります。import元が3.0とは異なるのがちょっといやですね。

Fragment

Activity.getFragmentManager()はありませんが、代わりにFragmentActivity.getSupportFragmentManager()が定義されています。なお、Fragment.getFragmentManager()はNULLが返ってくるようです。

サンプル

こちらに掲載されているサンプルを1.6でも動くように手直しました。

ちなみに、1.6で動かすために以下の点にひっかかりました。

  • match_parentはAPI Level 8から導入
  • ListViewのidに制限

ちなみに、addToBackStackを呼んでいるので、ボタンを押すたびにFragmentがBackStackに積まれます。

Main.java
package com.example.test.fragment;

import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.support.v4.app.*;

import com.example.test.fragment.R;

public class Main extends FragmentActivity{
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        
        for(int i = 1;i < 6;i++){
            int resId = getResources().getIdentifier("button" + i, "id", getPackageName());
            setCallback((Button)findViewById(resId), i);
        }
    }
    private void setCallback(Button b, final int i){
    	b.setOnClickListener(new OnClickListener() {
		@Override
		public void onClick(View v) {
			stackAFragment(i);
		}
	});
    }
    private void stackAFragment(int nAndroids) {
        Fragment f = new LogoFragment(nAndroids);

        FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
        ft.replace(R.id.the_frag, f);
        ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
        ft.addToBackStack(null);
        ft.commit();
    }
}
LogoFragment.java
package com.example.test.fragment;

import android.content.Context;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.support.v4.app.*;

public class LogoFragment extends Fragment {
    private int nAndroids = 1;

    public LogoFragment(){
    }
    public LogoFragment(int nAndroids) {
	   this.nAndroids = nAndroids;
    }
    @Override
    public void onCreate(Bundle saved) {
        super.onCreate(saved);
        if (null != saved) {
                nAndroids = saved.getInt("nAndroids");
        }
    }
    
    @Override
    public void onSaveInstanceState(Bundle toSave) {
        toSave.putInt("nAndroids", nAndroids);
    }
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle saved) {
        Context c = getActivity().getApplicationContext();
        LinearLayout l = new LinearLayout(c);
        for (int n = 0; n < nAndroids; n++) {
                ImageView i = new ImageView(c);
                i.setImageResource(R.drawable.icon);
                l.addView(i);
        }
        return l;
    }
}
main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="horizontal"
    android:layout_height="fill_parent"
    android:id="@+id/frags" android:layout_width="fill_parent">
    <LinearLayout android:layout_height="fill_parent" android:id="@+id/linearLayout1" android:layout_width="wrap_content" android:orientation="vertical">
        <Button android:text="Button" android:id="@+id/button1" android:layout_width="wrap_content" android:layout_height="wrap_content"></Button>
        <Button android:text="Button" android:id="@+id/button2" android:layout_width="wrap_content" android:layout_height="wrap_content"></Button>
        <Button android:text="Button" android:id="@+id/button3" android:layout_width="wrap_content" android:layout_height="wrap_content"></Button>
        <Button android:text="Button" android:id="@+id/button4" android:layout_width="wrap_content" android:layout_height="wrap_content"></Button>
        <Button android:text="Button" android:id="@+id/button5" android:layout_width="wrap_content" android:layout_height="wrap_content"></Button>
    </LinearLayout>

    <fragment class="com.example.test.fragment.LogoFragment"
            android:id="@+id/the_frag"
            android:layout_width="fill_parent"
            android:layout_height="fill_parent" />
</LinearLayout>

Fragment豆知識

removeとかreplaceしたときメモリはどうなるの?

addToBackStack()を呼んでいると、BackStackに積まれます。呼んでいないとメモリから破棄されます。つまり、onDetach()までが呼ばれます。

BackStackに積まれているときにBackボタンを押したらどうなるの?

その時表示されているFragmentは破棄され(onDetachまで呼ばれる)、BackStackの一番上にあるFragmentがpopされて表示されます。