问题
I have 4 fragments in a viewpager. And FragmentStatePagerAdapter inside the activity where my viewpager is. FragmentStatePagerAdapter's newInstance() method takes as parameter layout id, therefore each fragment has it's own layout:
ViewPager pager;
public class MainActivity extends FragmentActivity{
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
pager = (ViewPager) findViewById(R.id.viewPager);
pager.setAdapter(new MyPagerAdapter(getSupportFragmentManager()));}
private static class MyPagerAdapter extends FragmentStatePagerAdapter {
FragmentManager fm;
SparseArray<Fragment> registeredFragments = new SparseArray<Fragment>();
public MyPagerAdapter(FragmentManager fm) {
super(fm);
this.fm = fm;
}
@Override
public Fragment getItem(int pos) {
if(pos!=0){
pos = pos%4;
}
Fragment frag;
switch(pos) {
case 0: frag = FirstFragment.newInstance(R.layout.fire_room_wall1);
return frag;
case 1: frag = FirstFragment.newInstance(R.layout.fire_room_wall2);
return frag;
case 2: frag = FirstFragment.newInstance(R.layout.fire_room_wall3);
return frag;
case 3: frag = FirstFragment.newInstance(R.layout.fire_room_wall3);
return frag;
default: return FirstFragment.newInstance(R.layout.fire_room_wall1);
}
}
@Override
public int getCount() {
return 444444;
}
@Override
public Object instantiateItem(ViewGroup container, int position) {
Fragment fragment = (Fragment) super.instantiateItem(container, position);
registeredFragments.put(position, fragment);
return fragment;
}
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
registeredFragments.remove(position);
super.destroyItem(container, position, object);
}
public Fragment getRegisteredFragment(int position) {
return registeredFragments.get(position);
}
}
}
Here is FirstFragment:
public class FirstFragment extends Fragment{
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
int layout = getArguments().getInt("layout");
View v = inflater.inflate(layout, container, false);
return v;
}
public static FirstFragment newInstance(int layout) {
FirstFragment f = new FirstFragment();
Bundle b = new Bundle();
b.putInt("layout", layout);
f.setArguments(b);
return f;
}
}
And activity_main.xml:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity" >
<FrameLayout android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v4.view.ViewPager
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/viewPager"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
/>
<com.example.viewpagerfragement.CustomView android:id="@+id/customView"
android:layout_width="fill_parent" android:layout_height="fill_parent" />
</FrameLayout>
</RelativeLayout>
and one of the newInstance parameters fire_room_wall1.xml:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:background="@drawable/wall_nobrainjar"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:id="@+id/first" >
//some other child views
<ImageView
android:id="@+id/zoomed_image"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:visibility="gone"/>
//some other child views
</RelativeLayout>
Now at some point in my program I want to change background image of the current fragment's layout. And I attempted to do it like this:
int i = pager.getCurrentItem();
Fragment page = ((MyPagerAdapter)pager.getAdapter()).getRegisteredFragment(i);
((BitmapDrawable)page.getView().getBackground()).getBitmap().recycle();
page.getView().setBackgroundResource(R.drawable.wall3_nopaperball);
But the line "((BitmapDrawable)page.getView().getBackground()).getBitmap().recycle();
" returns NullPointerException because page.getView().getBackground()
is null. What I'm doing wrong or how can I change background image?
P.S. for some reason page.getView()'s type is NoSaveStateFrameLayout, not RelativeLayout as one would expect
回答1:
Solution:--
actually your problem is you are recycling bitmap i.e you are freeing that bitmap and the pixel data so, obviously you will get the null .!
It is already mentioned in android api documents:--
You just need to do this:--
int i = pager.getCurrentItem();
Fragment page = ((MyPagerAdapter)pager.getAdapter()).getRegisteredFragment(i);
Bitmap bitmapNeedTobeRecycled = ((BitmapDrawable)page.getView().getBackground()).getBitmap()
page.getView().setBackgroundResource(R.drawable.wall3_nopaperball);
bitmapNeedTobeRecycled.recycle();
It works then..Enjoy..!
回答2:
First of all do not keep a list of fragments in your adapter. Pager adapters should be served with data through custom method and then your getItem()
should use it to create Fragments. Instead randomising layouts in getItem()
do it on your item list(see code below) before you pass it to adapter. Do not override initialiseItem()
or destroyItem()
. Also you do not have to keep reference to FragmentManager
. You can implement your adapter like this:
Create custom class to holds your data.
public class MyItem {
private int layout;
private int bitmap;
public MyItem(layout, bitmap) {
this.layout = layout;
this.bitmap = bitmap;
}
//implement getters and setters
}
Next implement adapter like this:
public static class MyPagerAdapter extends FragmentStatePagerAdapter {
private List<MyItem> items = new ArrayList<MyItem>(0);
public void setItems(List<MyItem> items) {
this.items = items;
}
@Override
public Fragment getItem(int pos) {
MyItem item = items.get(pos);
return FirstFragment.newInstance(item.getLayout(), item.getBitmap());
}
@Override
public int getCount() {
return items.size();
}
public void updateItemBitmap(int position, int bitmap) {
MyItem myItem = items.get(position);
myItem.setBitmap(bitmap);
notifyDataSetChanged();
}
@Override
public int getItemPosition(Object object) {
return POSITION_NONE;
}
}
Then in getItem()
method you initialise your fragments based on that data. Next create method for updating items which is updating provided position and then invalidate adapter. Don't forget to implement getItemPosition()
, it makes ViewPager to invalidate all items, also those which are already created.
Finally, you can update it in your activity like this:
int i = pager.getCurrentItem();
((MyPagerAdapter)pager.getAdapter()).updateItemBitmap(i,R.drawable.wall3_nopaperball);
Your fragment implementation would look like this:
public class FirstFragment extends Fragment{
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
int layout = getArguments().getInt("layout");
int bitmap = getArguments().getInt("bitmap");
View v = inflater.inflate(layout, container, false);
v.setBackgroundResource(bitmap);
return v;
}
public static FirstFragment newInstance(int layout, int bitmap) {
FirstFragment f = new FirstFragment();
Bundle b = new Bundle();
b.putInt("layout", layout);
b.putInt("bitmap",bitmap);
f.setArguments(b);
return f;
}
}
来源:https://stackoverflow.com/questions/21181193/changing-background-image-of-current-fragment-in-viewpager