My goal is to delete a fragment from a ViewPager upon user button click.
Populating the ViewPager works fine, but when I try to delete it, I get an error indicating a null reference. I incorporated Remove Fragment Page from ViewPager in Android
In my fragment to be deleted I have:
Button delete = (Button) getActivity().findViewById(R.id.dont_show_button_1);
delete.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
db.deletePerson(count); // SQLiteDatabase, works fine
displayActivity.removeCurrentFragment(count-1);
}
});
DisplayActivity is as follows:
public class DisplayActivity extends FragmentActivity {
ViewPager viewPager;
PagerAdapter pagerAdapter;
String TAG = "DisplayActivity";
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.db_layout);
viewPager = (ViewPager) findViewById(R.id.pager);
pagerAdapter = new PagerAdapter(getSupportFragmentManager());
viewPager.setAdapter(pagerAdapter);
}
public void removeCurrentFragment(int position){
pagerAdapter.fragmentArrayList.remove(position);
pagerAdapter.notifyChangeInPosition(1);
pagerAdapter.notifyDataSetChanged();
Log.e(TAG, "in removeCurrentFragment");
}
}
PagerAdapter
public class PagerAdapter extends FragmentPagerAdapter {
long baseId = 0;
public static List<Fragment> fragmentArrayList = new ArrayList<Fragment>();
public PagerAdapter(FragmentManager fm){
super(fm);
fragmentArrayList.add(new FragmentOne());
fragmentArrayList.add(new FragmentTwo());
fragmentArrayList.add(new FragmentThree());
}
#Override
public Fragment getItem(int position) {
return fragmentArrayList.get(position);
}
#Override
public int getCount() {
return fragmentArrayList.size();
}
#Override
public int getItemPosition(Object object){
return PagerAdapter.POSITION_NONE;
}
#Override
public long getItemId(int position) {
// give an ID different from position when position has been changed
return baseId + position;
}
/**
* Notify that the position of a fragment has been changed.
* Create a new ID for each position to force recreation of the fragment
* #param n number of items which have been changed
*/
public void notifyChangeInPosition(int n) {
// shift the ID returned by getItemId outside the range of all previous fragments
baseId += getCount() + n;
}
}
This is the error:
java.lang.NullPointerException: Attempt to invoke virtual method 'void .DisplayActivity.removeCurrentFragment(int)' on a null object reference
Triggered from the fragment
Edit:
public class FragmentOne extends Fragment {
DatabaseHelper db;
WebView mWebView;
DisplayActivity displayActivity;
int count = 1;
This is how I get reference from displayActivity, is this the wrong way to get a reference of it?
if (count > 0) {
displayActivity.removeCurrentFragment(count - 1);
}
Related
I'm using a Fragment on my Activity that will have a picture "swiper". I've created a FragmentStatePagerAdapter which I'm trying to call from this Fragment and for some reason my getItem() method is never being called.
I've searched and found that I need to use getChildFragmentManager() when instantiating my FragmentStatePagerAdapter because I'm calling it from a Fragment. I've tried this as well as getSupportFragmentManager() with no luck from either.
Any ideas?
here's my Fragment that I'm using on my MainActivity with the method that shoudl setup the FragmentStatePagerAdapter:
public class PhotoFlipper extends Fragment {
// properties and fields
// primitive types
String currentImage;
int friendShareType = 0;
ImageView share;
ViewPager pager;
PhotoFlipperItemAdapter pagerAdapter;
LatLng itemPosition;
Activity activity;
FragmentActivity fragActivity;
public ArrayList<MarkerModel> picsAndVids;
// end properties and fields
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View photoFlipperFragmentView = inflater.inflate(R.layout.photo_flipper_layout, container, false);
InitializeFragment(photoFlipperFragmentView);
return photoFlipperFragmentView;
}
private void InitializeFragment(View photoFlipperFragmentView) {
activity = getActivity();
fragActivity = (FragmentActivity)activity;
pager = (ViewPager)photoFlipperFragmentView.findViewById(R.id.photoflipper_pager);
share = (ImageView)photoFlipperFragmentView.findViewById(R.id.photoflipper_share);
share.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
IPictureFlipper iPictureFlipper = (IPictureFlipper)activity;
iPictureFlipper.ShareVideoOrImage(friendShareType, itemPosition, currentImage);
}
});
}
#Override
public void onHiddenChanged(boolean hidden) {
super.onHiddenChanged(hidden);
if (hidden) {
pager.setVisibility(View.GONE);
}
}
public void SetTappedPicture(int index) {
pagerAdapter = new PhotoFlipperItemAdapter(getChildFragmentManager(), picsAndVids, picsAndVids.size());
pager.setAdapter(pagerAdapter);
pager.setCurrentItem(index);
pager.addOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() {
#Override
public void onPageSelected(int position) {
}
});
}
}
And here's my FragmentStatePagerAdapter:
public class PhotoFlipperItemAdapter extends FragmentStatePagerAdapter {
ArrayList<MarkerModel> _markers;
int NUM_PAGES;
String TAG = "home";
public PhotoFlipperItemAdapter(FragmentManager fm, ArrayList<MarkerModel> markers, int numpages){
super(fm);
Log.d(TAG,"in adapter in constructor");
_markers = markers;
NUM_PAGES = numpages;
}
#Override
public Fragment getItem(int position) {
Log.d(TAG,"in adapter in get item");
Fragment fragment = PhotoFlipperItemFragment.create(position, _markers);
return fragment;
}
#Override
public int getCount() {
Log.d(TAG,"in adapter in get count: "+NUM_PAGES);
return NUM_PAGES;
}
}
logcat is showing me that NUM_PAGES is > 0 so that's not my issue. I see my log in the constructor and in getCount() but nothing in getItem().
TIA
I got this sorted out. I was hiding my fragment in my InitializeActivity() right after I added it to my FragmentManager so it was never fully building the Fragment with the ViewPager etc.
I'm going to have to come up with a different solution for hiding/showing the fragment but that was my problem.
I have a ViewPager, and there's a button when clicked, deletes the current fragment from the PagerAdapter, and prevents the user from swiping there. I researched and found this Remove Fragment Page from ViewPager in Android to be the closest to what I want.
In my fragment to be deleted:
#Override
public void onClick(View v) {
db.delete(count); //SqliteDatabase deletion
displayActivity.removeCurrentFragment(0);
}
My PagerAdapter
public class PagerAdapter extends FragmentPagerAdapter {
long baseId = 0;
public static List<Fragment> fragmentArrayList = new ArrayList<Fragment>();
public PagerAdapter(FragmentManager fm){
super(fm);
fragmentArrayList.add(new FragmentOne());
fragmentArrayList.add(new FragmentTwo());
fragmentArrayList.add(new FragmentThree());
}
#Override
public Fragment getItem(int position) {
return fragmentArrayList.get(position);
}
}
#Override
public int getCount() {
return fragmentArrayList.size();
}
#Override
public int getItemPosition(Object object){
return PagerAdapter.POSITION_NONE;
}
#Override
public long getItemId(int position) {
// give an ID different from position when position has been changed
return baseId + position;
}
}
This is the activity (DisplayActivity) that hosts the pagerAdapter
public class DisplayActivity extends AppCompatActivity {
ViewPager viewPager;
PagerAdapter pagerAdapter;
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.db_layout);
viewPager = (ViewPager) findViewById(R.id.pager);
PagerAdapter pagerAdapter = new PagerAdapter(getSupportFragmentManager());
viewPager.setAdapter(pagerAdapter);
}
public void removeCurrentFragment(int position){
pagerAdapter.fragmentArrayList.remove(position);
pagerAdapter.notifyDataSetChanged();
}
What did I do wrong here?
I'm getting an error of
.removeCurrentFragment(int)' on a null object reference
So this error suggests that my method call removeCurrentFragment is referencing a null object, how do I fix it?
You have used
PagerAdapter pagerAdapter = new PagerAdapter(getSupportFragmentManager());
so you are creating a new local variable instead of using your global variable. Instead change your line as
pagerAdapter = new PagerAdapter(getSupportFragmentManager());
It should work.
Your onCreate method should look like this.
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.db_layout);
viewPager = (ViewPager) findViewById(R.id.pager);
pagerAdapter = new PagerAdapter(getSupportFragmentManager());
viewPager.setAdapter(pagerAdapter);
}
My ViewPager will delete a fragment upon button click. But when I click delete, I get "canot change tag" error. Browsing through other similar questions, it was either a problem with the getItem, or getCount in the PagerAdapter, which I think my implementation is fine. Please advice.
This is the fragment to be deleted
#Override
public void onActivityCreated(#Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
displayActivity = (DisplayActivity) getActivity();
initView();
}
Button delete = (Button) getActivity().findViewById(R.id.dont_show_button_1);
delete.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
displayActivity.removeCurrentFragment(count-1);
}
});
My PagerAdapter is
public class PagerAdapter extends FragmentPagerAdapter {
long baseId = 0;
public static List<Fragment> fragmentArrayList = new ArrayList<Fragment>();
public PagerAdapter(FragmentManager fm){
super(fm);
fragmentArrayList.add(new FragmentOne());
fragmentArrayList.add(new FragmentTwo());
fragmentArrayList.add(new FragmentThree());
}
#Override
public Fragment getItem(int position) {
return fragmentArrayList.get(position);
}
#Override
public int getCount() {
return fragmentArrayList.size();
}
#Override
public int getItemPosition(Object object){
return PagerAdapter.POSITION_NONE;
}
#Override
public long getItemId(int position) {
// give an ID different from position when position has been changed
return baseId + position;
}
/**
* Notify that the position of a fragment has been changed.
* Create a new ID for each position to force recreation of the fragment
* #param n number of items which have been changed
*/
public void notifyChangeInPosition(int n) {
// shift the ID returned by getItemId outside the range of all previous fragments
baseId += getCount() + n;
}
}
This is the activity that hosts the ViewPager
public class DisplayActivity extends FragmentActivity {
ViewPager viewPager;
PagerAdapter pagerAdapter;
String TAG = "DisplayActivity";
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.db_layout);
viewPager = (ViewPager) findViewById(R.id.pager);
pagerAdapter = new PagerAdapter(getSupportFragmentManager());
viewPager.setAdapter(pagerAdapter);
}
public void removeCurrentFragment(int position){
pagerAdapter.fragmentArrayList.remove(position);
pagerAdapter.notifyChangeInPosition(1);
pagerAdapter.notifyDataSetChanged();
Log.e(TAG, "in removeCurrentFragment");
}
I'm getting the error:
IllegalStateException: Can't change tag of fragment FragmentTwo{170c98f1 #1 id=0x7f0c006d android:switcher:2131492973:1}: was android:switcher:2131492973:1 now android:switcher:2131492973:3
The problem was with
public class PagerAdapter extends FragmentPagerAdapter
Changing it to
public class PagerAdapter extends FragmentStatePagerAdapter
enabled correct deletion.
This can be attributed to "FragmentStatePagerAdapter disposes of views that fall outside the current and traversable views."
As suggested to this post
Remove Fragment Page from ViewPager in Android
By Looking at your code i think your count value may be wrong.
Button delete = (Button) getActivity().findViewById(R.id.dont_show_button_1);
delete.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// here
displayActivity.removeCurrentFragment(count-1);
//change to
displayActivity.removeCurrentFragment(adapter.getCount()-1);
}
});
Hope it helps.Please post your whole code like where you getting the value of count variable. Post whole Code if Solution Does not Solve Your Problem .
Refer here for example:- https://androidruler.wordpress.com/2016/02/22/working-with-viewpager-as-a-images-slider/
With the help of Vivek Pratap Singh and astuetz codes from following questions(Remove Fragment Page from ViewPager in Android and Android saving dynamically added viewpager's fragment while coming back from another activity and reopening app),
In my previous question in stack overflow I used inbuild method onDestroy, as it looks like it will save all the dynamically added fragments in viewpager.
But it's not happening, I am able to see only one intial static page(i.e. fragment) when I restart my app or navigate to another activity and come back to my activity containing the viewpager with fragments.Could any one please help me on this question.
Here is my source code for your reference:
public class MainActivity extends FragmentActivity implements TextProvider {
private Button mAdd;
private Button mRemove;
private ViewPager mPager;
int position;
private MyPagerAdapter mAdapter;
private ArrayList<String> mEntries = new ArrayList<String>();
#Override
public void onSaveInstanceState(Bundle bundle) {
super.onSaveInstanceState(bundle);
bundle.putInt("currenItem", mPager.getCurrentItem());
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mPager = (ViewPager) findViewById(R.id.pager);
if (savedInstanceState != null) {
mPager.setCurrentItem(savedInstanceState.getInt("currentItem", 0));
}
mEntries.add("page 1");
mAdd = (Button) findViewById(R.id.add);
mRemove = (Button) findViewById(R.id.remove);
mAdd.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View view) {
addNewItem();
}
});
mRemove.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View view) {
removeCurrentItem();
}
});
mAdapter = new MyPagerAdapter(this.getSupportFragmentManager(), this);
mPager.setAdapter(mAdapter);
mPager.setOffscreenPageLimit(3);
}
private void addNewItem() {
// int position = mPager.getCurrentItem();
mEntries.add("page ");
mAdapter.notifyDataSetChanged();
}
private void removeCurrentItem() {
int position = mPager.getCurrentItem();
if(position != 0){
mEntries.remove(position);
}else{
Toast.makeText(getApplicationContext(), "Sorry", Toast.LENGTH_LONG).show();
}
mAdapter.notifyDataSetChanged();
}
#Override
public String getTextForPosition(int position) {
return mEntries.get(position);
}
#Override
public int getCount() {
return mEntries.size();
}
private class MyPagerAdapter extends FragmentPagerAdapter {
private TextProvider mProvider;
private long baseId = 0;
public MyPagerAdapter(FragmentManager fm, TextProvider provider) {
super(fm);
this.mProvider = provider;
}
#Override
public Fragment getItem(int position) {
switch(position) {
case 0:
return FragmentOne.newInstance(mProvider.getTextForPosition(position));
case 1:
return FragmentTwo.newInstance(mProvider.getTextForPosition(position));
case 2:
return FragmentThree.newInstance(mProvider.getTextForPosition(position));
default: return FragmentOne.newInstance(mProvider.getTextForPosition(position));
}
}
#Override
public int getCount() {
return mProvider.getCount();
}
//this is called when notifyDataSetChanged() is called
#Override
public int getItemPosition(Object object) {
// refresh all fragments when data set changed
return PagerAdapter.POSITION_NONE;
}
#Override
public long getItemId(int position) {
// give an ID different from position when position has been changed
return baseId + position;
}
#Override
public void destroyItem(ViewGroup container, int position, Object object) {
}
/**
* Notify that the position of a fragment has been changed.
* Create a new ID for each position to force recreation of the fragment
* #param n number of items which have been changed
*/
public void notifyChangeInPosition(int n) {
// shift the ID returned by getItemId outside the range of all previous fragments
baseId += getCount() + n;
}
}
}
When I close (onPause) my application, and reopen it onResume,
ViewPager adapter that extends FragmentPagerAdapter overriden method getItem() is not invoked. How can I invoke it?
Here is my viewPager adapter:
public class MyPagerAdapter extends FragmentPagerAdapter {
private final String TAG = "MyPagerAdapter";
private int MAX_COUNT = 100;
fragment1 myFragment;
public MyPagerAdapter(FragmentManager fm) {
super(fm);
Log.d(TAG, "Created adapter for pager");
}
public void setCount(int count) {
MAX_COUNT = count;
}
#Override
public Fragment getItem(int position) {
Log.d(TAG, "getting item at " + position);
myFragment = new fragment1();
myFragment.position = position;
Log.d("Fragment", "Position: " + position);
return myFragment;
}
#Override
public int getCount() {
return MAX_COUNT;
}
}
Initialize your view pager in onStart() method of activity . OnCreate() method calls once activity is created . Or call it again on OnRestart() method . See Activity LifeCycle for further details