问题
I am new in Android and I don't really understand why a Fragment
's content which was added dynamically (for example some image which was added after a button click) is disappearing after scrolling some count of Fragment
s and then come back.
There is really simple code Activity
and Fragment
:
public class MyActivity extends FragmentActivity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
final ViewPager viewPager = (ViewPager) findViewById(R.id.viewPager);
final CustomAdapter adapter = new CustomAdapter(getSupportFragmentManager());
viewPager.setAdapter(adapter);
}
class CustomFragment extends Fragment {
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment, container, false);
}
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
getView().findViewById(R.id.clickMeButton).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
getView().findViewById(R.id.image).setVisibility(View.VISIBLE);
}
});
}
}
class CustomAdapter extends FragmentStatePagerAdapter {
private List<CustomFragment> fragments = Arrays.asList(
new CustomFragment(),
new CustomFragment(),
new CustomFragment()
);
public CustomAdapter(FragmentManager fm) {
super(fm);
}
@Override
public Fragment getItem(int i) {
return fragments.get(i);
}
@Override
public int getCount() {
return fragments.size();
}
}
}
and appropriate xmls:
main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<android.support.v4.view.ViewPager
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:id="@+id/viewPager" />
</LinearLayout>
fragment.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<Button
android:id="@+id/clickMeButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="click me"/>
<ImageView
android:id="@+id/image"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/ic_launcher"
android:visibility="gone"/>
</LinearLayout>
Logic is simple. On each Fragment
I can click on a Button
and as result an image appears.
And it works. But ...
When I show image on the first fragment, then scroll to the third one and come back to first one again image is gone.
What should I do to prevent this ? Should I somehow save state of visibility?
回答1:
This is happening because FragmentStatePagerAdapter
releases the memory associated with a Fragment
when it is scrolled out of view. From the docs:
When pages are not visible to the user, their entire fragment may be destroyed, only keeping the saved state of that fragment. This allows the pager to hold on to much less memory associated with each visited page as compared to FragmentPagerAdapter at the cost of potentially more overhead when switching between pages.
You can try one of the following four options:
1. Since you have a small number of pages, you can use FragmentPagerAdapter
instead of FragmentStatePagerAdapter
. FragmentPagerAdapter
holds onto the created Fragment
s and does not destroy them on swipe.
2. In your Fragment
, store a boolean
in a SharedPreference
and set (or clear) its value when you make the image visible or invisible. Then in the onResume()
method of your Fragment
, make the image visible or invisible based on the value of the SharedPreference
.
3. In the onCreate()
of your Fragment
, call setRetainInstance(true);
.
4. If the number of fragments is fixed & relatively small, then in your onCreate()
add the following code:
mViewPager = (ViewPager)findViewById(R.id.pager);
mViewPager.setOffscreenPageLimit(limit); /* limit is a fixed integer*/
回答2:
Whats happening is
Since you are using adapter there may be a number of fragments active at a time like 3 or 4 for example.
Adapter will render the views dynamically to reduce the memory usage. In your case
Fragment 1 -> Fragment 2 - > Fragment 3
Let the active fragment be 3 now, So Fragment 1
may be removed from memory when you scroll back , it will redraw the fragment by
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment, container, false);
}
So the image is still invisible
and in its initial stage.
Answer
Set a flag to identify the status of the image and use it in onCreateView()
to make it visible
or invisible
.
UPDATE
mViewPager = (ViewPager)findViewById(R.id.viewPager);
mViewPager.setOffscreenPageLimit(yourLimit);
yourLimit
is the number of fragments you want to keep alive which is not in screen currently.
NOTE: This is memory intensive.
回答3:
save the visibility of image in onSaveInstance
method of your fragment class CustomFragment
. Override onSaveInstanceState in the fragment activity class onSaveInstanceState
call super.onSaveInstanceState(bundle) in that overridden method
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putString("visibility", visibility);
}
Then you can retain the state in the onActivityCreated
method of your fragment class CustomFragment
int visibility = View.INVISIBLE;
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
if(savedInstanceState!=null)
visibility = savedInstanceState.getInt("visibility");
getView().findViewById(R.id.image).setVisibility(visibility);
getView().findViewById(R.id.clickMeButton)
.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
getView().findViewById(R.id.image).setVisibility(View.VISIBLE);
}
});
}
回答4:
mViewPager.setOffscreenPageLimit(limit);
It worked for me thanks ! I had a viewpager with 3 fragments and a recyclerview in the first one. When i clicked on the last one my recyclerview disappeared..
Not checked yet about performance
来源:https://stackoverflow.com/questions/24217621/android-viewpager-fragments-refreshed-when-swiped