web-dev-qa-db-ja.com

フラグメントの状態を保存/復元android

Jack WhartonのViewPagerライブラリ( こちら )を使用して、すべてのページの画像のみを使用するアプリを作成しようとしています(Priking( こちら )メイン画面など)。フラグメントのsaveInstanceを除いて、すべてが正常に動作します。

ジャックウォートンの例では、テキストをmContentという名前の文字列変数に格納し、それをonCreateに復元していますが、私の場合はどうすればよいですか?ビットマップを保存/復元しますか?!客観的な答えがあれば大歓迎です!

私はアプリケーションを使用するこのFragmentに非常に慣れていないので、私が見たすべての例を示し、基本のみを示し、より複雑なものでは難しくなっています。

PS。知っておくと便利な場合は、CirclePageIndicatorを使用しています。

ここに現在のフラグメントコード:

    public final class SpecialOfferFragment extends Fragment {

    private int imageResourceId;

    public static SpecialOfferFragment newInstance(int i) {

        //probably I'll use a bitmap(downloaded) as parameter instead of using static images
        SpecialOfferFragment fragment = new SpecialOfferFragment();

        fragment.imageResourceId = i;

        return fragment;
    }


    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // if ((savedInstanceState != null) { }

    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {

        ImageView image = new ImageView(getActivity());
        image.setImageResource(imageResourceId);
        image.setScaleType(ScaleType.FIT_XY);

        LinearLayout layout = new LinearLayout(getActivity());
        layout.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT,
                LayoutParams.FILL_PARENT));

        layout.setGravity(Gravity.CENTER);
        layout.addView(image);

        return layout;
    }

    @Override
    public void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        //smth to save here..
    }
}

このアプリの現在の状態で、次の例外が発生します。

04-12 07:28:17.760: E/AndroidRuntime(31903): FATAL EXCEPTION: main 
04-12 07:28:17.760: E/AndroidRuntime(31903): Java.lang.NullPointerException
04-12 07:28:17.760: E/AndroidRuntime(31903): at Android.support.v4.app.FragmentManagerImpl.saveFragmentBasicState(FragmentManager.Java:1576)
04-12 07:28:17.760: E/AndroidRuntime(31903):    at Android.support.v4.app.FragmentManagerImpl.saveAllState(FragmentManager.Java:1617)
04-12 07:28:17.760: E/AndroidRuntime(31903):    at Android.support.v4.app.FragmentActivity.onSaveInstanceState(FragmentActivity.Java:481)
04-12 07:28:17.760: E/AndroidRuntime(31903):    at Android.app.Activity.performSaveInstanceState(Activity.Java:1113)
04-12 07:28:17.760: E/AndroidRuntime(31903):    at Android.app.Instrumentation.callActivityOnSaveInstanceState(Instrumentation.Java:1188)
04-12 07:28:17.760: E/AndroidRuntime(31903):    at Android.app.ActivityThread.performStopActivityInner(ActivityThread.Java:2804)
04-12 07:28:17.760: E/AndroidRuntime(31903):    at Android.app.ActivityThread.handleStopActivity(ActivityThread.Java:2862)
04-12 07:28:17.760: E/AndroidRuntime(31903):    at Android.app.ActivityThread.access$900(ActivityThread.Java:127)
04-12 07:28:17.760: E/AndroidRuntime(31903):    at Android.app.ActivityThread$H.handleMessage(ActivityThread.Java:1175)
04-12 07:28:17.760: E/AndroidRuntime(31903):    at Android.os.Handler.dispatchMessage(Handler.Java:99)
04-12 07:28:17.760: E/AndroidRuntime(31903):    at Android.os.Looper.loop(Looper.Java:137)
04-12 07:28:17.760: E/AndroidRuntime(31903):    at Android.app.ActivityThread.main(ActivityThread.Java:4511)
04-12 07:28:17.760: E/AndroidRuntime(31903):    at Java.lang.reflect.Method.invokeNative(Native Method)
04-12 07:28:17.760: E/AndroidRuntime(31903):    at Java.lang.reflect.Method.invoke(Method.Java:511)
04-12 07:28:17.760: E/AndroidRuntime(31903):    at com.Android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.Java:980)
04-12 07:28:17.760: E/AndroidRuntime(31903):    at com.Android.internal.os.ZygoteInit.main(ZygoteInit.Java:747)
04-12 07:28:17.760: E/AndroidRuntime(31903):    at dalvik.system.NativeStart.main(Native Method)

これは、ホームボタンを押すなど、このフラグメントを含むアクティビティを一時停止/停止するたびに発生します。

**

コードで編集:

**

 public class MainMenu extends FragmentActivity {

    //private List<CategoriesHolder> categoriesList = new ArrayList<CategoriesHolder>();
    //private CategoriesAdapter categoriesAdapter = null;
    //private GridView gv_mainmenu_categories;

    SpecialOfferFragmentAdapter mAdapter;
    ViewPager mPager;
    PageIndicator mIndicator;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_mainmenu);

        linkUI();
        setAction();

        // just for testing
        String[] imagesUrls = null;

        mAdapter = new SpecialOfferFragmentAdapter(getSupportFragmentManager(),
                this, imagesUrls);

        //categoriesAdapter = new CategoriesAdapter(this, categoriesList);

        // used for Categories GridView
        //gv_mainmenu_categories.setAdapter(categoriesAdapter);

        // used for ViewPager
        mPager.setAdapter(mAdapter);
        mIndicator.setViewPager(mPager);

    }

    private void linkUI() {
        mPager = (ViewPager) findViewById(R.id.vp_mainmenu_special_offers);
        mIndicator = (CirclePageIndicator) findViewById(R.id.indicator);

        //gv_mainmenu_categories = (GridView) findViewById(R.id.gv_mainmenu_categories);

    }

    private void setAction() {

    }
} 

    public class SpecialOfferFragmentAdapter extends FragmentPagerAdapter implements
        IconPagerAdapter {

    private int[] mCarouselImages = new int[] { R.drawable.pic1,
            R.drawable.pic2, R.drawable.pic3, R.drawable.pic4, R.drawable.pic5

    };

    private String[] imagesUrls;
    private Context context;

    public static final int[] ICONS = new int[] {
            R.drawable.perm_group_calendar, R.drawable.perm_group_camera,
            R.drawable.perm_group_device_alarms, R.drawable.perm_group_location };

    private int mCount = mCarouselImages.length;

    public SpecialOfferFragmentAdapter(FragmentManager fm, Context context,
            String[] imagesUrls) {
        super(fm);
        this.context = context;
        this.imagesUrls = imagesUrls;
    }

    @Override
    public Fragment getItem(int position) {

        return SpecialOfferFragment.newInstance(mCarouselImages[position]);
    }

    @Override
    public int getCount() {
        return mCount;
    }

    @Override
    public int getIconResId(int index) {
        return ICONS[index % ICONS.length];
    }

    public void setCount(int count) {
        if (count > 0 && count <= 10) {
            mCount = count;
            notifyDataSetChanged();
        }
    }
}
13
DoruAdryan

必要なことを達成するには、整数値を使用して現在の位置をViewPagerに保存し、その後この値を使用して正しい位置をViewPagerに設定する必要があります。

たとえば、FragmentActivityで次のようにします。

_@Override
public void onSaveInstanceState(Bundle savedInstanceState) {
  super.onSaveInstanceState(savedInstanceState);
  savedInstanceState.putInt("mMyCurrentPosition", mPager.getPosition());
}

@Override
public void onRestoreInstanceState(Bundle savedInstanceState) {
  super.onRestoreInstanceState(savedInstanceState);
  mMyCurrentPosition = savedInstanceState.getInt("mMyCurrentPosition");
  // where mMyCurrentPosition should be a public value in your activity.
}
_

これにより、ViewPagerの最後の位置が保存されます。そしてその後、例えばあなたのonResume()であなたはチェックすることができます

_if(mMyCurrentPosition != 0){
    mPager.setCurrentItem(mMyCurrentPosition);
}
_

私はこれがうまくいくと思います、画像/ビットマップをまとめて保存するのは良い習慣ではありません(そしてあなたがそれを行うことができるとは思いません)。

10
h4rd4r7c0r3

これは私にとってあなたの主な活動の中で簡単かつ簡単に働きました

 @Override
    protected void onRestoreInstanceState(Bundle savedInstanceState) {
        super.onRestoreInstanceState(savedInstanceState);
        onCreate(savedInstanceState);
    }

そしてあなたのマニフェストの中

 <activity
            Android:configChanges="orientation|screenSize"/>
2

さて、最初のidは、savedinstancestateに関する混乱を解決するかもしれない何かを片付けたいです。 Savedinstancestateは、プリミティブ(int、double、float、byte ..)とStringオブジェクトのみを処理できます。これで十分ですが、他のオブジェクトのインスタンスも保存したい場合もあります。これには、ジョブを実行するために他のパターンが必要になります。たとえば、すべてのビットマップの配列を保持するファクトリパターンなどです。たとえば、ビットマップの静的なArrayListを保持するImageFactoryクラスを作成します。デバイスを回転させるたびに、oncreateviewメソッドとonactivitycreatedメソッドが再度呼び出されます。これが、ファクトリから情報を取得するかどうかを確認するときです。例えば

if(savedInstanceState!= null){// savedinstancestateがあるため、保存された画像が存在する可能性がありますImageFactory.getBMPs(); }

この情報で何かできることを願っています。幸運を

2
JanCor

SharedPreferenceを使用してタブが変更されているときにフラグメントデータを保存するための独自のメソッドを作成しました。

次のような方法:

  public void saveData() {

    Log.d("msg", "Save Instance");
    SharedPreferences.Editor outState = getActivity().getSharedPreferences("order", Context.MODE_APPEND).edit();

    orderDate = orderDateEditText.getText().toString();
    orderBy = orderByEditText.getText().toString();
    orderMobileNo = orderMobileNoEditText.getText().toString();
    orderTransport = orderTransportEditText.getText().toString();
    orderInvoicePer = orderInvoicePerEditText.getText().toString(); 
    orderCharge = orderChargeEditText.getText().toString();
    orderGoodsDispatch = orderGoodsDispatchEditText.getText().toString();
    orderOthers = orderOthersEditText.getText().toString();
    orderIsDirect = orderIsDirectCheckBox.isChecked() ? 1 : 0;

    outState.putBoolean("saved", true);

    outState.putString("orderDate", orderDate);
    outState.putString("orderBy", orderBy);
    outState.putString("orderMobileNo", orderMobileNo);
    outState.putString("orderTransport", orderTransport);
    outState.putString("orderInvoicePer", orderInvoicePer);
    outState.putString("orderCharge", orderCharge);
    outState.putString("orderGoodsDispatch", orderGoodsDispatch);
    outState.putString("orderOthers", orderOthers);
    outState.putInt("orderIsDirect", orderIsDirect);

    outState.commit();
}

このメソッドを呼び出すとき

    @Override
    public void onStop() {
    // TODO Auto-generated method stub
        super.onStop();

        saveData();
}

保存したデータをEditTextで置き換える:

@Override
public void onActivityCreated(Bundle savedInstanceState) {
    // TODO Auto-generated method stub
    super.onActivityCreated(savedInstanceState);

    /***** PUT DATA IN EDITTEXT is ITS AVAILABLE IN BUNDLE *****/
    SharedPreferences orderData = getActivity().getSharedPreferences("order", Context.MODE_APPEND);
    Log.d("msg", ""+orderData.getBoolean("saved", false));

    if(orderData.getBoolean("saved", false))
    {
        orderDate = orderData.getString("orderDate", "");
        orderBy = orderData.getString("orderBy", "");
        orderMobileNo = orderData.getString("orderMobileNo", "");
        orderTransport = orderData.getString("orderTransport", "");
        orderInvoicePer = orderData.getString("orderInvoicePer", ""); 
        orderCharge = orderData.getString("orderCharge", "");
        orderGoodsDispatch = orderData.getString("orderGoodsDispatch", "");
        orderOthers = orderData.getString("orderOthers", "");
        orderIsDirect = orderData.getInt("orderIsDirect", 0);

        orderDateEditText.setText(orderDate);
        orderByEditText.setText(orderBy);
        orderMobileNoEditText.setText(orderMobileNo);
        orderTransportEditText.setText(orderTransport);
        orderInvoicePerEditText.setText(orderInvoicePer);
        orderChargeEditText.setText(orderCharge);
        orderGoodsDispatchEditText.setText(orderGoodsDispatch);
        orderOthersEditText.setText(orderOthers);
        if(orderIsDirect == 0)
            orderIsDirectCheckBox.setChecked(false);
        else
            orderIsDirectCheckBox.setChecked(true);
    }
}

このコードが役に立ちますように...

ありがとう...

1
Pratik Butani

数か月が経過しているため、この質問がまだあなたを悩ませているかどうか、私にはよくわかりません。しかし、私がこれに対処した方法を共有したいと思います。ここにソースコードがあります:

int FLAG = 0;
private View rootView;
private LinearLayout parentView;

/**
 * The fragment argument representing the section number for this fragment.
 */
private static final String ARG_SECTION_NUMBER = "section_number";

/**
 * Returns a new instance of this fragment for the given section number.
 */
public static Fragment2 newInstance(Bundle bundle) {
    Fragment2 fragment = new Fragment2();
    Bundle args = bundle;
    fragment.setArguments(args);
    return fragment;
}

public Fragment2() {

}

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    super.onCreateView(inflater, container, savedInstanceState);
    Log.e("onCreateView","onCreateView");
    if(FLAG!=12321){
        rootView = inflater.inflate(R.layout.fragment_create_new_album, container, false);
        changeFLAG(12321);
    }       
    parentView=new LinearLayout(getActivity());
    parentView.addView(rootView);

    return parentView;
}

/* (non-Javadoc)
 * @see Android.support.v4.app.Fragment#onDestroy()
 */
@Override
public void onDestroy() {
    // TODO Auto-generated method stub
    super.onDestroy();
    Log.e("onDestroy","onDestroy");
}

/* (non-Javadoc)
 * @see Android.support.v4.app.Fragment#onStart()
 */
@Override
public void onStart() {
    // TODO Auto-generated method stub
    super.onStart();
    Log.e("onstart","onstart");
}

/* (non-Javadoc)
 * @see Android.support.v4.app.Fragment#onStop()
 */
@Override
public void onStop() {
    // TODO Auto-generated method stub
    super.onStop();
    if(false){
        Bundle savedInstance=getArguments();
        LinearLayout viewParent;

        viewParent= (LinearLayout) rootView.getParent();
        viewParent.removeView(rootView);

    }
    parentView.removeView(rootView);

    Log.e("onStop","onstop");
}
@Override
public void onPause() {
    super.onPause();
    Log.e("onpause","onpause");
}

@Override
public void onResume() {
    super.onResume();
    Log.e("onResume","onResume");
}

そしてここにMainActivityがあります:

/**
 * Fragment managing the behaviors, interactions and presentation of the
 * navigation drawer.
 */
private NavigationDrawerFragment mNavigationDrawerFragment;

/**
 * Used to store the last screen title. For use in
 * {@link #restoreActionBar()}.
 */

public static boolean fragment2InstanceExists=false;
public static Fragment2 fragment2=null;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
    setContentView(R.layout.activity_main);

    mNavigationDrawerFragment = (NavigationDrawerFragment) getSupportFragmentManager()
            .findFragmentById(R.id.navigation_drawer);
    mTitle = getTitle();

    // Set up the drawer.
    mNavigationDrawerFragment.setUp(R.id.navigation_drawer,
            (DrawerLayout) findViewById(R.id.drawer_layout));
}

@Override
public void onNavigationDrawerItemSelected(int position) {
    // update the main content by replacing fragments
    FragmentManager fragmentManager = getSupportFragmentManager();
    FragmentTransaction fragmentTransaction=fragmentManager.beginTransaction();
    switch(position){
    case 0:
        fragmentTransaction.addToBackStack(null);
        fragmentTransaction.replace(R.id.container, Fragment1.newInstance(position+1)).commit();
        break;
    case 1:

        Bundle bundle=new Bundle();
        bundle.putInt("source_of_create",CommonMethods.CREATE_FROM_ACTIVITY);

        if(!fragment2InstanceExists){
            fragment2=Fragment2.newInstance(bundle);
            fragment2InstanceExists=true;
        }
        fragmentTransaction.addToBackStack(null);
        fragmentTransaction.replace(R.id.container, fragment2).commit();

        break;
    case 2:
        fragmentTransaction.addToBackStack(null);
        fragmentTransaction.replace(R.id.container, FolderExplorerFragment.newInstance(position+1)).commit();
        break;
    default: 
        break;
    }
}

ParentViewがキーポイントです。通常、onCreateViewの場合は、return rootViewを使用します。しかし、今はrootViewをparentViewに追加してから、parentViewを返します。 「指定された子にはすでに親があります。..でremoveView()を呼び出す必要があります」というエラーを防ぐには、「parentView.removeView(rootView)」を呼び出す必要があります。そうしないと、指定したメソッドが役に立たなくなります。見つけた方法も共有したいと思います。最初に、インスタンスが存在するかどうかを示すブール値を設定しました。インスタンスが存在する場合、rootViewは再び拡張されません。しかし、その後、logcatは子にすでに親があることを示したので、中間の親ビューとして別の親を使用することにしました。それがどのように機能するかです。お役に立てれば幸いです。

1
butch

その問題を処理する方法を書かせてください。後でやり取りするために、フラグメントオブジェクト変数をアクティビティに保持します。 onCreate()メソッドで、saveedInstanceState(画面の回転などが原因)があるかどうかを確認します。

public class MainActivity extends AppCompatActivity {
PlaceAddFragment mFragment;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    if(savedInstanceState == null) {
        mFragment = new PlaceAddFragment();
        mFragment.setProfileImages(incomingPics);

        getSupportFragmentManager()
                .beginTransaction()
                .replace(R.id.form_fragment_holder, mFragment, PlaceAddFragment.TAG)
                .commit();
    }else{
        mFragment = (PlaceAddFragment) getSupportFragmentManager().findFragmentByTag(PlaceAddFragment.TAG);
    }
}

以下のように、フラグメントクラスでonSaveInstanceStateメソッドをオーバーライドし、それにsetRetainInstance(true)を追加します。

public class PlaceAddFragment extends Fragment {
public static final String TAG = ".PlaceAddFragment";
private ProfileImageAdapter mAdapter;
private List<ProfileImage> mProfileImages;
private Context mContext;

public PlaceAddFragment() {
    // Required empty public constructor
}

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState) {

    mContext = getContext();
    View view = inflater.inflate(R.layout.fragment_place_add, container, false);

    RecyclerView mRecyclerView = (RecyclerView) view.findViewById(R.id.hw_pictures_holder);
    mRecyclerView.setLayoutManager(new LinearLayoutManager(mContext, LinearLayoutManager.HORIZONTAL, false));
    mAdapter = new ProfileImageAdapter(mContext, mProfileImages);
    mRecyclerView.setAdapter(mAdapter);

    return view;
}

@Override
public void onSaveInstanceState(final Bundle outState) {
    super.onSaveInstanceState(outState);
    setRetainInstance(true);
}

@Override
public void onDestroy() {
    super.onDestroy();
    mAdapter = null;
    mProfileImages = null;
}

public void setProfileImages(List<ProfileImage> incomingPics) {
    this.mProfileImages = incomingPics;
}

public List<ProfileImage> getProfileImages() {
    return this.mProfileImages;
}
}

このコードを機能させるには、ProfileImageAdapter mAdapter、ProfileImageオブジェクト、およびそれらのすべてのxmlレイアウトを実装する必要があります。

0
MeLine