Android : FragmentList items repeating themselves - android

I have created a ViewPager in my MainActivity that contains 5 tabs. In the first tab I have put a ListView in order to display some items. The problem is that whenever I swipe to a different tab and then return to the first, the items in the list are duplicated (i.e list contains A-B-C and then A-B-C-A-B-C). The odd thing is that this occurs only when I swipe further than the second tab. Here is my code :
MainActivity :
public class MainActivity extends FragmentActivity implements ActionBar.TabListener {
private ViewPager viewPager;
private TabsPagerAdapter mAdapter;
private ActionBar actionBar;
//private String[] tabs = { "Mixed", "Videos", "Audio", "Text", "Picture" };
final int[] ICONS = new int[] {
R.drawable.mixed,
R.drawable.video,
R.drawable.audio,
R.drawable.note,
R.drawable.photo
};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
viewPager = (ViewPager) findViewById(R.id.pager);
actionBar = getActionBar();
mAdapter = new TabsPagerAdapter(getSupportFragmentManager());
viewPager.setAdapter(mAdapter);
actionBar.setHomeButtonEnabled(false);
actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
// Adding Tabs
for (int i=0;i<ICONS.length;i++) {
actionBar.addTab(actionBar.newTab().setIcon(MainActivity.this.getResources().getDrawable(ICONS[i]))
.setTabListener(this));
}
viewPager.setOnPageChangeListener(new ViewPager.OnPageChangeListener() {
#Override
public void onPageSelected(int position) {
// on changing the page
// make respected tab selected
actionBar.setSelectedNavigationItem(position);
}
#Override
public void onPageScrolled(int arg0, float arg1, int arg2) {
}
#Override
public void onPageScrollStateChanged(int arg0) {
}
});
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
#Override
public void onTabSelected(ActionBar.Tab tab, FragmentTransaction ft) {
viewPager.setCurrentItem(tab.getPosition());
}
#Override
public void onTabUnselected(ActionBar.Tab tab, FragmentTransaction ft) {
}
#Override
public void onTabReselected(ActionBar.Tab tab, FragmentTransaction ft) {
}
public class TabsPagerAdapter extends FragmentPagerAdapter {
public TabsPagerAdapter(FragmentManager fm) {
super(fm);
}
#Override
public android.support.v4.app.Fragment getItem(int index) {
switch (index) {
case 0:
return MixedFragment.newInstance();
case 1:
return new VideosFragment();
case 2:
return new AudioFragment();
case 3:
return new TextFragment();
case 4:
return new PictureFragment();
}
return null;
}
#Override
public int getCount() {
// get item count - equal to number of tabs
return 5;
}
}
}
Fragment Class :
public class MixedFragment extends ListFragment implements AdapterView.OnItemClickListener {
ListView mixed;
JSONArray videos =null;
List<NameValuePair> row;
ArrayAdapter<VideoRow> adapter;
private List<VideoRow> listRow = new ArrayList<>();
private List<String> pathList = new ArrayList<>();
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.mixed, container, false);
mixed = (ListView) v.findViewById(android.R.id.list);
row = new ArrayList<>();
// mixed.setOnItemClickListener(this);
new populateLists().execute();
return v;
}
public static MixedFragment newInstance(){
MixedFragment mx = new MixedFragment();
return mx;
}
public void onItemClick(AdapterView<?> l, View v, int position, long id) {
String sendPath = pathList.get(position);
Intent start = new Intent(getActivity(), PlayVideo.class);
start.putExtra("Path", sendPath);
startActivity(start);
}
class populateLists extends AsyncTask<String,String,String> {
#Override
protected void onPreExecute() {
super.onPreExecute();
}
#Override
protected String doInBackground(String... params) {
JSONParser jParser = new JSONParser();
JSONObject obj = jParser.makeHttpRequest(Config.URL_Populate,"GET",row);
try {
// Checking for SUCCESS TAG
int success = obj.getInt("success");
if (success == 1) {
// videos found
// Getting Array of videos
videos = obj.getJSONArray("video");
// looping through All videos
for (int i = 0; i < videos.length(); i++) {
JSONObject c = videos.getJSONObject(i);
// Storing each json item in variable
String path = Config.URL_2server+c.getString("path");
String thumbnail = c.getString("thumbnail");
String title = c.getString("title");
String name =c.getString("name");
title = "\""+title+"\"";
byte[] bytes = Base64.decode(thumbnail,Base64.DEFAULT);
Bitmap thumb = BitmapFactory.decodeByteArray(bytes, 0, bytes.length);
pathList.add(path);
listRow.add(new VideoRow(path,thumb, name, title));
}
}
adapter = new MyListAdapterFrag(getActivity(), R.layout.enlarged_list_row, listRow,1);
} catch (JSONException e) {
e.printStackTrace();
}
return null;
}
protected void onPostExecute(String file_url) {
mixed.setAdapter(adapter);
}
}
}
ListAdapter :
public class MyListAdapterFrag extends ArrayAdapter<VideoRow> {
List<VideoRow> lRow;
Bitmap myThumb;
int activity;
public MyListAdapterFrag(Context context, int resource, List<VideoRow> listRow, int i) {
super(context, resource, listRow);
lRow=listRow;
activity=i;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder viewHolder;
View row = convertView;
if (row == null) {
LayoutInflater inflater = LayoutInflater.from(getContext());
if (activity == 1) {
row = inflater.inflate(R.layout.list_row, parent, false);
} else if (activity == 2) {
row = inflater.inflate(R.layout.enlarged_list_row, parent, false);
}
viewHolder = new ViewHolder();
viewHolder.txtName = (TextView) row.findViewById(R.id.name);
viewHolder.txtTitle = (TextView) row.findViewById(R.id.title);
viewHolder.imageThumb = (ImageView) row.findViewById(R.id.thumbnail);
row.setTag(viewHolder);
} else {
viewHolder = (ViewHolder) row.getTag();
}
VideoRow thisRow = lRow.get(position);
viewHolder.txtName.setText(thisRow.getName());
Bitmap thumb = thisRow.getThumb();
if (activity == 1) {
myThumb = Bitmap.createScaledBitmap(thumb, 40, 40, true);
} else if (activity == 2) {
myThumb = Bitmap.createScaledBitmap(thumb, 60, 60, true);
}
viewHolder.imageThumb.setImageBitmap(myThumb);
viewHolder.txtTitle.setText(thisRow.getTitle());
return row;
}
private static class ViewHolder {
ImageView imageThumb;
TextView txtTitle;
TextView txtName;
}
}
So, do you guys have any idea what causes this bug ?

The problem is caused by the fact that your fragment gets reinitialized when the ViewPager goes past a certain point.
This is called the off screen page limit.
This means, that once your first Fragment is past the limit, when you return to it, the onCreateView function will be called again. You need to check whether the populateLists AsyncTask really needs to fire or not.
Alternatively, you can increase your off screen page limit, to retain all your Fragments.

When you move to another fragment in ViewPager, the previous fragment's view might be destroyed (I think the default size is two fragments e.g. when fragment#2 gets on screen, fragment#0 is destroyed). When you go back, it's recreated. Every time you return to MixedFragment, its onCreateView method is called but you never clear the adapter when it's destroyed. That's why you see duplicates.
So you can just clear the adapter when its view is destroyed:
#Override
public void onDestroyView() {
super.onDestroyView();
adapter.clear();
}

Related

Adapter is multiplying with the same data android

I have a SwitchTabActivty with 4 items. In my case, I use the second item to get some data from the web through a recyclerview. The problem is that when I press the fourth item (it contains a button that's starting an activity) and I go back to my second tab , my recycler view is multiplied with the same data again.
Switchtabactivity :
public class SwitchTabActivity extends AppCompatActivity {
private SectionsPagerAdapter mSectionsPagerAdapter;
private ViewPager mViewPager;
private boolean pressToExit = false;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_switch_tab);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
// Create the adapter that will return a fragment for each of the three
// primary sections of the activity.
mSectionsPagerAdapter = new SectionsPagerAdapter(getSupportFragmentManager());
// Set up the ViewPager with the sections adapter.
mViewPager = (ViewPager) findViewById(R.id.container);
mViewPager.setAdapter(mSectionsPagerAdapter);
TabLayout tabLayout = (TabLayout) findViewById(R.id.tabs);
tabLayout.setupWithViewPager(mViewPager);
tabLayout.getTabAt(0).setIcon(R.drawable.weather_tab);
tabLayout.getTabAt(1).setIcon(R.drawable.events);
tabLayout.getTabAt(2).setIcon(R.drawable.details_tab);
tabLayout.getTabAt(3).setIcon(R.drawable.settings_tab);
setColorTab(tabLayout);
}
private void setColorTab(TabLayout tab) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
tab.setTabTextColors(getResources().getColorStateList(R.color.tab_colors, null));
} else {
tab.setTabTextColors(getResources().getColorStateList(R.color.tab_colors));
}
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
}
#Override
public void onBackPressed() {
if (!pressToExit) {
Toast.makeText(this, "Press back again to exit.", Toast.LENGTH_SHORT).show();
pressToExit = true;
} else {
Intent intent = new Intent(Intent.ACTION_MAIN);
intent.addCategory(Intent.CATEGORY_HOME);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
}
}
#Override
public void onResume() {
super.onResume();
pressToExit = false;
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_switch_tab, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
public class SectionsPagerAdapter extends FragmentPagerAdapter {
public SectionsPagerAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int position) {
switch (position) {
case 0:
return WeatherFragment.newInstance(position);
case 1:
return EventFragment.newInstance(position);
case 2:
return OwnEventFragment.newInstance(position);
case 3:
return SettingsFragment.newInstance(position);
}
return null;
}
#Override
public int getCount() {
return 4;
}
#Override
public CharSequence getPageTitle(int position) {
switch (position) {
case 0:
return "Weather";
case 1:
return "Events";
case 2:
return "My Events";
case 3:
return "Settings";
}
return null;
}
}
EventFragment :
public class EventFragment extends Fragment implements EventResponse {
private String latitude, longitude;
private static final String ARG_SECTION_NUMBER = "section_number";
private RecyclerView eventList;
private EventAdapter adapter;
private TextView ifNullEvents;
private final ArrayList<EventData> eventsData = new ArrayList<>();
private UserDataBase db;
private List<String> latLonList;
private ProgressBar progressBar;
public EventFragment() {
}
public static EventFragment newInstance(int sectionNumber) {
EventFragment fragment = new EventFragment();
Bundle args = new Bundle();
args.putInt(ARG_SECTION_NUMBER, sectionNumber);
fragment.setArguments(args);
return fragment;
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.event_fragment, container, false);
initView(rootView);
db = new UserDataBase(getContext());
checkLocationChanged();
latLonList = db.getLatLon();
latitude = latLonList.get(0);
longitude = latLonList.get(1);
String EVENT_BRITE_URL_PARSE = "MY_URL";
String EVENT_BRITE_TOKEN = "MY_TOKEN";
new EventBriteApi(this, getContext()).execute(EVENT_BRITE_URL_PARSE + EVENT_BRITE_TOKEN);
setupRecyclerView();
setLocationMessage();
return rootView;
}
private void initView(View view) {
eventList = (RecyclerView) view.findViewById(R.id.event_recycler_view);
ifNullEvents = (TextView) view.findViewById(R.id.text_null_location);
progressBar = (ProgressBar) view.findViewById(R.id.progress_bar_event);
}
private void checkLocationChanged() {
if (WePrefs.isLocationChanged) {
eventsData.clear();
ifNullEvents.setText(getResources().getString(R.string.waiting_for_data));
ifNullEvents.setVisibility(View.VISIBLE);
progressBar.setVisibility(View.VISIBLE);
WePrefs.setIsLocationChanged(false);
} else {
progressBar.setVisibility(View.GONE);
ifNullEvents.setVisibility(View.GONE);
}
if (WePrefs.isNullEventLocation) {
ifNullEvents.setText(getResources().getString(R.string.no_events_found));
ifNullEvents.setVisibility(View.VISIBLE);
progressBar.setVisibility(View.INVISIBLE);
WePrefs.setIsNullEventLocation(false);
}
}
private void setupRecyclerView() {
eventList.setHasFixedSize(true);
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(getActivity());
linearLayoutManager.setOrientation(LinearLayoutManager.VERTICAL);
eventList.setLayoutManager(linearLayoutManager);
adapter = new EventAdapter(getActivity(), eventsData);
adapter.setHasStableIds(true);
eventList.setAdapter(adapter);
}
#Override
public void onResume() {
checkLocationChanged();
setLocationMessage();
super.onResume();
}
private void setLocationMessage() {
if (eventsData.isEmpty()) {
ifNullEvents.setVisibility(View.VISIBLE);
progressBar.setVisibility(View.VISIBLE);
} else {
ifNullEvents.setVisibility(View.GONE);
progressBar.setVisibility(View.GONE);
}
progressBar.setVisibility(View.GONE);
}
#Override
public void getArray(ArrayList<EventData> data) {
eventsData.clear();
eventsData.addAll(new ArrayList<>(new LinkedHashSet<>(data)));
}
}
Adapter :
ublic class EventAdapter extends RecyclerView.Adapter<EventAdapter.EventHolder> {
ArrayList<EventData> data;
Context context;
public EventAdapter(Context context, ArrayList<EventData> events) {
this.context = context;
data = events;
}
#Override
public EventHolder onCreateViewHolder(ViewGroup parent, int viewType) {
RelativeLayout layout = (RelativeLayout) LayoutInflater.from(parent.getContext()).inflate(R.layout.single_event_view, parent, false);
return new EventAdapter.EventHolder(layout);
}
#Override
public void onBindViewHolder(EventHolder holder, int position) {
holder.eventName.setText(data.get(position).getEventName());
if (data.get(position).getEventImageUrl() != null) {
Picasso.with(context).load(data.get(position).getEventImageUrl()).into(holder.eventPic);
} else {
holder.eventPic.setImageDrawable(ContextCompat.getDrawable(context, R.drawable.no_image));
}
}
#Override
public int getItemCount() {
return data.size();
}
public class EventHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
TextView eventName;
ImageView eventPic;
RelativeLayout layout;
public EventHolder(View itemView) {
super(itemView);
eventName = (TextView) itemView.findViewById(R.id.event_name);
eventPic = (ImageView) itemView.findViewById(R.id.event_image);
layout = (RelativeLayout) itemView.findViewById(R.id.event_layout);
layout.setOnClickListener(this);
}
#Override
public void onClick(View view) {
//context.startActivity(new Intent(context, WebViewActivity.class));
}
}
}
Those are some of my java classes that I use for this kind of thing.
Anyway, another problem is that, when I change the location ( to receive my events) I must go to another tab and after that to come back to see my events list ( I think it needs to recreate the view ) so , because of that I called onResume, but it does not help.

Calling a Fragment from a main fragment

I have to call a fragment (Page1) from here...
protected void onPostExecute(Void args) {
Intent intentx;
intentx = new Intent(HomeFragment.this.getActivity(),Main.class);
intentx.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intentx);
}
I my program i have Main class which looks like this
public class Main extends FragmentActivity implements
ActionBar.TabListener {
private ViewPager viewPager;
private TabsPagerAdapter mAdapter;
private ActionBar actionBar;
// Tab titles
private String[] tabs = { "Express(1 Day)", "Premium (2 Day)", "Normal (3+ Days)" };
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main_tab);
// Initilization
viewPager = (ViewPager) findViewById(R.id.pager);
actionBar = getActionBar();
mAdapter = new TabsPagerAdapter(getSupportFragmentManager());
viewPager.setAdapter(mAdapter);
//actionBar.setHomeButtonEnabled(false);
actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
// Adding Tabs
for (String tab_name : tabs) {
actionBar.addTab(actionBar.newTab().setText(tab_name)
.setTabListener(this));
}
/**
* on swiping the viewpager make respective tab selected
* */
viewPager.setOnPageChangeListener(new ViewPager.OnPageChangeListener() {
#Override
public void onPageSelected(int position) {
// on changing the page
// make respected tab selected
actionBar.setSelectedNavigationItem(position);
}
#Override
public void onPageScrolled(int arg0, float arg1, int arg2) {
}
#Override
public void onPageScrollStateChanged(int arg0) {
}
});
}
#Override
public void onTabReselected(Tab tab, FragmentTransaction ft) {
}
#Override
public void onTabSelected(Tab tab, FragmentTransaction ft) {
// on tab selected
// show respected fragment view
viewPager.setCurrentItem(tab.getPosition());
}
#Override
public void onTabUnselected(Tab tab, FragmentTransaction ft) {
}
This class will invoke Page1,Page2,Page3
Inside Page 1 the code is this
public class Page1 extends Fragment {
public static ArrayList<String> strArr;
public static ArrayList<ArrayList<String>> content;
public static ArrayAdapter<String> adapter;
LinearLayout ll;
View format;
float days_to_del;
int[] no_of_count= new int[20];
int count;
int x;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.page1, container, false);
// super.onResume();
//View rootView = inflater.inflate(R.layout.page1, container, false);
for(int j=0;j<10;j++)
{
days_to_del=Float.parseFloat(""+Lib.result[j][0].toString());
if(days_to_del==2.0)
{
no_of_count[x]=j;
x++;
count++;
}
}
for(int m=0;m<count;m++)
{
ll = (LinearLayout) rootView.findViewById(R.id.parent);
LayoutInflater vi = (LayoutInflater) Page1.this.getActivity().getApplicationContext().getSystemService(Page1.this.getActivity().LAYOUT_INFLATER_SERVICE);
format = inflater.inflate(R.layout.page1, null);
ll.addView(format);
//Lib.ShowAlertMessage(Page1.this.getActivity().getApplicationContext(), "", ""+format.getId());
if(Lib.result[no_of_count[m]][2].toString().equals("First Flight Couriers"))
{
ImageView imageView1=(ImageView)rootView.findViewById(R.id.imageView1);
String uri = "#drawable/first_flight";
int imageResource = getResources().getIdentifier(uri, null, Page1.this.getActivity().getApplicationContext().getPackageName());
Drawable res = getResources().getDrawable(imageResource);
imageView1.setImageDrawable(res);
}
else if(Lib.result[no_of_count[m]][2].toString().equals("SkyNet WorldWide Express"))
{
ImageView imageView1=(ImageView)rootView.findViewById(R.id.imageView1);
String uri = "#drawable/skynet";
int imageResource = getResources().getIdentifier(uri, null, Page1.this.getActivity().getApplicationContext().getPackageName());
Drawable res = getResources().getDrawable(imageResource);
imageView1.setImageDrawable(res);
}
else if(Lib.result[no_of_count[m]][2].toString().equals("The Professional Couriers"))
{
ImageView imageView1=(ImageView)rootView.findViewById(R.id.imageView1);
String uri = "#drawable/professional";
int imageResource = getResources().getIdentifier(uri, null, Page1.this.getActivity().getApplicationContext().getPackageName());
Drawable res = getResources().getDrawable(imageResource);
imageView1.setImageDrawable(res);
}
else if(Lib.result[no_of_count[m]][2].toString().equals("The Professional Couriers"))
{
ImageView imageView1=(ImageView)rootView.findViewById(R.id.imageView1);
String uri = "#drawable/professional";
int imageResource = getResources().getIdentifier(uri, null, Page1.this.getActivity().getApplicationContext().getPackageName());
Drawable res = getResources().getDrawable(imageResource);
imageView1.setImageDrawable(res);
}
TextView textView2=(TextView)rootView.findViewById(R.id.textView2);
textView2.setText("Rupees");
}
if(format.getId()==1)
{
ll.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View arg0) {
Intent intentx;
intentx = new Intent(Page1.this.getActivity(), From.class); //mContext is a Context variable.
intentx.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
}
});
}
if(format.getId()==2)
{
ll.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View arg0) {
Intent intentx;
intentx = new Intent(Page1.this.getActivity(), To.class);
intentx.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
}
});
}
return rootView;
}
public void onResume(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState){
}
}
My Issue
1. I use these variables(Lib.results[][]) in the PostExecute They are available ( I dont require here)
2. In the fragment Page1 i am not able access the Lib.results[][] , as soon as it enters the Page1 the value of result[][] is null as the value is not updated(this is what I guessed would have hapened)
3. The results based on the values will go to respective fragments (Page1,Page2,Page3)
Question
Am i calling the fragment activity the rightway?? does intent work this way or is there any other method.
I figured that I had used the array as String but changing it to strArray made it work

Reset TouchImageView zoom in ViewPager

I have activity for fullscreen browsing of images (something like gallery). In this activity I have ViewPager with offscreen limit 6. I use TouchImageView for my images.
The problem is, that when I first zoom image and swipe to another photo, I want to see not zoomed photo when I return to it. TouchImageView has resetZoom() function, but how can I get offscreen page view from the FragmentStatePageAdapter or from ViewPager?
Here's code of my activity:
public class ImageSlidesActivity extends FragmentActivity implements ViewPager.OnPageChangeListener {
final int PAGE_LIMIT = 6;
final int PAGE_MARGIN = 8;
long userID;
long deviceID;
String key;
String[] mAttachments;
ImageSlidesAdapter mAdaper;
ViewPager mPager;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_ACTION_BAR_OVERLAY);
setContentView(R.layout.activity_image_slides);
ActionBar actionBar = getActionBar();
actionBar.setDisplayHomeAsUpEnabled(true);
//actionBar.setBackgroundDrawable(new ColorDrawable(Color.parseColor("#33ffffff")));
Intent intent = getIntent();
mAttachments = intent.getStringArrayExtra("attachments");
int position = intent.getIntExtra("position", 0);
SharedPreferences pref = getApplicationContext().getSharedPreferences("authData", 0);
key = pref.getString("key", null);
userID = pref.getLong("userID", 0);
deviceID = pref.getLong("deviceID", 0);
setPageIndicator(position);
mAdaper = new ImageSlidesAdapter(getSupportFragmentManager(), mAttachments);
final View container = findViewById(R.id.container);
container.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
getActionBar().hide();
container.setSystemUiVisibility(View.SYSTEM_UI_FLAG_HIDE_NAVIGATION);
}
});
mPager = (ViewPager) findViewById(R.id.pager);
mPager.setAdapter(mAdaper);
mPager.setOnPageChangeListener(this);
mPager.setOffscreenPageLimit(PAGE_LIMIT);
mPager.setCurrentItem(position-1);
/* cause bug with the white strip
final float density = getResources().getDisplayMetrics().density;
mPager.setPageMargin((int) (PAGE_MARGIN * density + 0.5f));
mPager.setPageMarginDrawable(android.R.color.black);
*/
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
//getMenuInflater().inflate(R.menu.image_slides, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
if (id == android.R.id.home) {
onBackPressed();
}
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
#Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
#Override
public void onPageSelected(int position) {
setPageIndicator(position+1);
}
#Override
public void onPageScrollStateChanged(int state) {
}
private void setPageIndicator(int page) {
setTitle(Integer.toString(page) + "/" + Integer.toString(mAttachments.length));
}
/**
* A fragment containing zoomable image.
*/
public static class ShowImageFragment extends Fragment {
String mAlias;
long mUserId;
long mDeviceId;
String mKey;
TouchImageView mImage;
static ShowImageFragment newInstance(String alias, long userId, long deviceId,
String key) {
ShowImageFragment f = new ShowImageFragment();
Bundle args = new Bundle();
args.putString("alias", alias);
args.putLong("userID", userId);
args.putLong("deviceID", deviceId);
args.putString("key", key);
f.setArguments(args);
return f;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Bundle bundle = getArguments();
mAlias = bundle.getString("alias");
mUserId = bundle.getLong("userID");
mDeviceId = bundle.getLong("deviceID");
mKey = bundle.getString("key");
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_image_slides, container, false);
mImage = (TouchImageView) rootView.findViewById(R.id.imageView);
final ProgressBar prBar = (ProgressBar) rootView.findViewById(R.id.progressBar);
new AsyncTask<Void, Void, Bitmap>() {
#Override
protected Bitmap doInBackground(Void... voids) {
try {
String[] links = API.getImageLinkByAlias(mAlias, mUserId,
mDeviceId, mKey);
return ImageLoader.getInstance().loadImageSync(links[1]);
} catch (Exception e) {
// TODO: handle exceptions
e.printStackTrace();
cancel(true);
return null;
}
}
#Override
protected void onPostExecute(Bitmap bitmap) {
prBar.setVisibility(View.GONE);
if (bitmap == null) { return; }
mImage.setImageBitmap(bitmap);
mImage.setVisibility(View.VISIBLE);
mImage.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
if (getActivity().getActionBar().isShowing()) {
getActivity().getActionBar().hide();
} else {
getActivity().getActionBar().show();
}
}
});
}
}.execute();
return rootView;
}
}
public class ImageSlidesAdapter extends FragmentStatePagerAdapter {
private String[] mAliases;
public ImageSlidesAdapter(android.support.v4.app.FragmentManager fm, String[] aliases) {
super(fm);
mAliases = aliases;
}
#Override
public android.support.v4.app.Fragment getItem(int position) {
return ShowImageFragment.newInstance(mAliases[position], userID, deviceID, key);
}
#Override
public int getCount() {
return mAliases.length;
}
}
}
I overrided onPageSelected method and I get views by calling getChildAt().
#Override
public void onPageSelected(int position) {
setPageIndicator(position+1);
if (position > 0) {
View view = mPager.getChildAt(position -1);
if (view != null) {
TouchImageView img = (TouchImageView) view.findViewById(R.id.image);
img.resetZoom();
}
}
if (position < mPager.getChildCount() - 1) {
View view = mPager.getChildAt(position + 1);
if (view != null) {
TouchImageView img = (TouchImageView) view.findViewById(R.id.image);
img.resetZoom();
}
}
}
It can also be achieved by setting a normal page transformer in the view pager
binding.viewPager.setPageTransformer { page, position ->
// Reset zoom on previous/next item
if (position == -1f || position == 1f) {
(page as PhotoView).apply {
scale = 1f
}
}
}

Android: Best Approach to pass data between viewpager fragments

I have 3 fragments in a ViewPager Activity. All 3 fragments have input fields. Here I am trying to pass first two fragments data to third fragment. I read few posts here and most of them suggested to use interfaces(i.e. to pass data through parent activity)
I have also gone through this link
http://developer.android.com/training/basics/fragments/communicating.html
Interface: using interfaces is good approach when we are sending data through some user event. Here I am trying to send data without any user event. Hence I thought of onPause() since onPause() is always called. But ViewPager functions differently. When a fragment is loaded,the adjacent fragments are also loaded. I would be successful to pass data between 1st fragment to 3rd fragment. But 2nd fragment's onPause() wont be called unless I am navigating to some fragment that is not adjacent to it(which in my case is not there)
Setter/Getters:I have read in few posts people saying not to use setter/getters(I still havent understood the reason yet) Are getters and setters poor design? Contradictory advice seen
Bundle: I havent considered this yet. Since I am again confused here how would I pass data using bundle.(inside which method should I send data? and how?)
Sorry if my question sounds dumb.I am trying to understand fragments and i would like to know best way to pass data between fragments in viewpager.
Thank You in advance.
TabPAgerAdapter -- >
package com.jbandroid.model;
import com.jbandroid.fragment.LocationInfoFragment;
import com.jbandroid.fragment.PersonalInfoFragment;
import com.jbandroid.fragment.PostInfoFragment;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentPagerAdapter;
public class TabsPagerAdapter extends FragmentPagerAdapter {
public TabsPagerAdapter(FragmentManager fm){
super(fm);
}
#Override
public Fragment getItem(int index) {
switch(index) {
case 0 : //PostInfoFragment
return new PostInfoFragment();
case 1 : //LocationInfoFragment
return new LocationInfoFragment();
case 2 : //PersonalInfoFragment
return new PersonalInfoFragment();
}
return null;
}
#Override
public int getCount() {
// get item count - equal to number of tabs
return 3;
}
}
ViewPagerActivity -- >
package com.jbandroid;
public class SubmitPostActivity extends FragmentActivity implements ActionBar.TabListener,PostInfoFragment.setPostInfo,LocationInfoFragment.setLocationInfo{
private ViewPager viewpager;
private ActionBar actionBar;
private TabsPagerAdapter mAdapter;
FragmentManager manager;
PersonalInfoFragment frag;
List<String> location;
/*private MenuItem myActionMenuItem;
private Button myActionButton;*/
//Tab titles
private String[] tabs = {"Post Info" , "Location Info" , "Personal Info" };
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.action_submit_post);
viewpager = (ViewPager) findViewById(R.id.pager);
actionBar = getActionBar();
manager = getSupportFragmentManager();
mAdapter = new TabsPagerAdapter(getSupportFragmentManager());
//viewpager.setOffscreenPageLimit(2);
viewpager.setAdapter(mAdapter);
//actionBar.setHomeButtonEnabled(false);
actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
for (String tab : tabs){
actionBar.addTab(actionBar.newTab().setText(tab).setTabListener(this));
}
if(savedInstanceState != null){
actionBar.setSelectedNavigationItem( savedInstanceState.getInt("tab",0));
}
/**
* on swiping the viewpager make respective tab selected
* */
viewpager.setOnPageChangeListener(new OnPageChangeListener() {
#Override
public void onPageSelected(int position) {
// on changing the page
// make respected tab selected
actionBar.setSelectedNavigationItem(position);
}
#Override
public void onPageScrolled(int arg0, float arg1, int arg2) {
}
#Override
public void onPageScrollStateChanged(int arg0) {
}
});
}
#Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putInt("tab", getActionBar().getSelectedNavigationIndex());
}
#Override
public void onTabReselected(Tab tab, FragmentTransaction ft) {
}
#Override
public void onTabSelected(Tab tab, FragmentTransaction ft) {
// on tab selected
// show respected fragment view
viewpager.setCurrentItem(tab.getPosition());
}
#Override
public void onTabUnselected(Tab tab, FragmentTransaction ft) {
}
#Override
public void pass_location_details(List<String> location) {
frag = (PersonalInfoFragment) manager.findFragmentByTag("android:switcher:" + viewpager.getId() + ":" + 2);
frag.get_post_location_details(location);
Log.d("submitarea", location.get(0));
}
#Override
public void pass_post_details(List<String> post_details,ArrayList<CustomGallery> selected) {
frag = (PersonalInfoFragment) manager.findFragmentByTag("android:switcher:" + viewpager.getId() + ":" + 2);
frag.get_post_details(post_details,selected);
Log.d("submitpostinfo","hello"+ post_details.get(5));
}
}
1st Fragment(Here I am trying to pass data using interface in onPause()-->
package com.jbandroid.fragment;
public class PostInfoFragment extends Fragment {
private MenuItem myActionMenuItem;
private Button myActionButton;
private ActionBar actionBar;
private String post_title, post_desc,post_status;
private EditText submit_post_title, submit_post_desc;
private Resources res;
setPostInfo info;
List<String> post_details;
//RelativeLayout rel_submit_post_start_date,rel_submit_post_end_date;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_post_info,
container, false);
/*if(!imageLoader.isInited()){*/
initImageLoader();
/*}*/
//handler = new Handler();
submit_post_title = (EditText) rootView
.findViewById(R.id.submit_post_title);
submit_post_desc = (EditText) rootView
.findViewById(R.id.submit_post_description);
actionBar = getActivity().getActionBar();
setHasOptionsMenu(true);
post_details = new ArrayList<String>();
res = getResources();
setListeners();
Log.d("postinfo_oncreate view", "postinfo_oncreate view");
return rootView;
}
//interface to pass data to activity and then to PersonalInfoFragment
public interface setPostInfo {
//public void pass_post_details(List<String> post_details);
public void pass_post_details(List<String> post_details,ArrayList<CustomGallery> selected);
}
//making sure if the parent activity has implemented interface
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
// This makes sure that the container activity has implemented
// the callback interface. If not, it throws an exception
try {
info = (setPostInfo) activity;
} catch (ClassCastException e) {
throw new ClassCastException(activity.toString()
+ "must implemet setPostInfo");
}
Log.d("postinfo_onattach", "postinfo_onattach");
}
//passing form inputs to personalinfofragments
#Override
public void onPause() {
super.onPause();
// setFormInputs();
passFormInputs(); ---> passing in onPause() This executes successfully
Log.d("postinfo_onPAuse", "postinfo_onPause");
}
//method to pass data to personalinfofragment
private void passFormInputs() {
try {
post_title = submit_post_title.getText().toString();
post_desc = submit_post_desc.getText().toString();
post_status = "1";
if(post_title != null && post_title.length() > 0
&& post_desc != null && post_desc.length() > 0
&& post_status != null && post_status.length() > 0
){
post_details.add(post_title);
post_details.add(post_desc);
post_details.add(post_status);
info.pass_post_details(post_details,dataT); -->here I am passing values via
}else{ activity to 3rd fragment
Log.d("post_info", "values are null");
}
} catch (Exception e) {
e.printStackTrace();
}
}
//setting next button on actionbar
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
super.onCreateOptionsMenu(menu, inflater);
// Inflate the menu items for use in the action bar
inflater.inflate(R.menu.mymenu, menu);
// Here we get the action view we defined
myActionMenuItem = menu.findItem(R.id.my_action);
View actionView = myActionMenuItem.getActionView();
// We then get the button view that is part of the action view
if (actionView != null) {
myActionButton = (Button) actionView.findViewById(R.id.action_btn);
myActionButton.setText(R.string.txt_next);
if (myActionButton != null) {
// We set a listener that will be called when the return/enter
// key is pressed
myActionButton.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
actionBar.setSelectedNavigationItem(1);
}
});
}
}
}
}
2nd Fragment-->
package com.jbandroid.fragment;
public class LocationInfoFragment extends Fragment implements OnClickListener {
private MenuItem myActionMenuItem;
private Button myActionButton;
private ActionBar actionBar;
Dialog dialog;
private EditText submit_post_exact_location;
private TextView selected_country, selected_city,
submit_post_exact_time;
String country, city, exact_location, exact_time;
setLocationInfo info;
List<String> location;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_location_info,
container, false);
actionBar = getActivity().getActionBar();
setHasOptionsMenu(true);
submit_post_exact_location = (EditText) rootView
.findViewById(R.id.submit_post_exact_location);
submit_post_exact_time = (TextView) rootView
.findViewById(R.id.submit_post_exact_time);
selected_country = (TextView) rootView
.findViewById(R.id.selected_country);
selected_city = (TextView) rootView.findViewById(R.id.selected_city);
location = new ArrayList<String>();
setListeners();
return rootView;
}
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
super.onCreateOptionsMenu(menu, inflater);
// Inflate the menu items for use in the action bar
inflater.inflate(R.menu.mymenu, menu);
// Here we get the action view we defined
myActionMenuItem = menu.findItem(R.id.my_action);
View actionView = myActionMenuItem.getActionView();
// We then get the button view that is part of the action view
if (actionView != null) {
myActionButton = (Button) actionView.findViewById(R.id.action_btn);
myActionButton.setText(R.string.txt_next);
if (myActionButton != null) {
// We set a listener that will be called when the return/enter
// key is pressed
myActionButton.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
actionBar.setSelectedNavigationItem(2);
}
});
}
}
}
public interface setLocationInfo {
public void pass_location_details(List<String> location);
}
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
// This makes sure that the container activity has implemented
// the callback interface. If not, it throws an exception
try {
info = (setLocationInfo) activity;
} catch (ClassCastException e) {
throw new ClassCastException(activity.toString()
+ "must implement setLocationInfo");
}
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
//setLocationDetails();
}
#Override
public void onPause() {
super.onPause();
setLocationDetails(); ----> doesnt executes since onPause isnt called when I navigate to 3rd fragment as it is an adjacent fragment of this fragment
// Log.d("location : onPause", area);
}
private void setLocationDetails() {
try {
exact_location = submit_post_exact_location.getText().toString();
exact_time = submit_post_exact_time.getText().toString();
country = selected_country.getText().toString();
city = selected_city.getText().toString();
if (country != null && country.length() > 0
&& !country.equalsIgnoreCase("select") && city != null
&& city.length() > 0 && !city.equalsIgnoreCase("select")
&& exact_location != null && exact_location.length() > 0
&& exact_time != null && exact_time.length() > 0) {
location.add(country);
location.add(city);
location.add(exact_location);
location.add(exact_time);
info.pass_location_details(location);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
In my 3rd Fragment I am trying to get this values
public class PersonalInfoFragment extends Fragment {
List<String> post_details;
List<String> location;
Button submit;
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_personal_info,
container, false);
submit = (Button)rootView.findViewById(R.id.submitBtn);
submit.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
//performing operations with the values obtained
setPostItems();
insertintodb();
}
});
return rootView;
}
public void get_post_details(List<String> post_details,
ArrayList<CustomGallery> selected) { -->receiving values from
this.post_details = post_details; 1st fragment
this.selected = selected;
Log.d("personalfrag(postinfo)", "hello" + post_details.get(5));
}
//receiving values from 2nd fragment
public void get_post_location_details(List<String> location) {
this.location = location;
Log.d("personalfrag(locationinfo)", "hello" + location.get(0));
}
}
Okay, I Had same issue to pass data(not just string) between two tabs in a ViewPager. So here is what i did.
I Use interfaces to communicate between the different components.
The data passes this way:
Tab 1 -> Activity -> VewPageAdapter -> Tab 2
In Tab 1
create an interface.
OnCartsDataListener mOncarOnCartsDataListener;
public interface OnCartsDataListener {
public void onCartsDataReceived(ArrayList<CartsViewModel> cartsViewModels);
}
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
try {
mOncarOnCartsDataListener = (OnCartsDataListener)activity;
}catch (ClassCastException e){
}
}
// now call mOncarOnCartsDataListener.onCartsDataReceived(data) when you have the data
In Activity
Implement the interface and override the method
ViewPagerAdapter adapter;
adapter = new ViewPagerAdapter(getSupportFragmentManager(), Titles, Numboftabs);
#Override
public void onCartsDataReceived(ArrayList<CartsViewModel> cartsViewModels) {
Log.d(TAG, "data received to Activity... send to view pager");
adapter.onCartsDataReceived(cartsViewModels);
}
3.IN ViewPagerAdapter
Also implements the interface and override the method
#Override
public void onCartsDataReceived(ArrayList<CartsViewModel> cartsViewModels) {
Log.d(TAG, "data received to view pager... sending to tab 2");
if(tab2!=null){
tab2.onCartsDataReceived(cartsViewModels);
}else{
Log.d(TAG, "tab2 is null");
}
}
Finally tab 2
Also implements the interface and override the method
#Override
public void onCartsDataReceived(ArrayList<CartsViewModel> cartsViewModels) {
Log.d(TAG, "Finally ! received data to tab 2");
if(cartsViewModels!=null){
for(CartsViewModel cart : cartsViewModels){
Log.d(TAG,"got it :"+cart.getCartName());
}
}
}
Since AndroidX, you can create a ViewModel and share data between Activity and all fragments within ViewPager
Read here how to
Can you do something like this? First create any data structure like Arraylist in your main activity. Then send a reference of that data model to your fragments. Now update that data when, on change your text fields. By doing this all the fragment can see updated values. So fragments can update this data itself and we don't need to send that data since it is already shared. I'll explain this using your example. Try to improve this. You can maintain fragment specific data model then each fragment can access data with the knowledge of that data owner.
TabsPagerAdapter.java
public class TabsPagerAdapter extends FragmentPagerAdapter {
public TabsPagerAdapter(FragmentManager fm,SubmitPostActivity activity){
super(fm);
}
#Override
public Fragment getItem(int index) {
switch(index) {
case 0 : //PostInfoFragment
return new PostInfoFragment(0,activity);
case 1 : //LocationInfoFragment
return new LocationInfoFragment(1,activity);
case 2 : //PersonalInfoFragment
return new PersonalInfoFragment(2,activity);
}
return null;
}
#Override
public int getCount() {
return 3;
}
}
ViewPagerActivity -- >
package com.jbandroid;
public class SubmitPostActivity extends FragmentActivity implements ActionBar.TabListener,LocationInfoFragment.setLocationInfo{
private ViewPager viewpager;
private ActionBar actionBar;
private TabsPagerAdapter mAdapter;
FragmentManager manager;
PersonalInfoFragment frag;
List<String> location;
/*private MenuItem myActionMenuItem;
private Button myActionButton;*/
//Tab titles
private String[] tabs = {"Post Info" , "Location Info" , "Personal Info" };
public List<String> dataModel = new ArrayList<String>();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.action_submit_post);
viewpager = (ViewPager) findViewById(R.id.pager);
actionBar = getActionBar();
manager = getSupportFragmentManager();
mAdapter = new TabsPagerAdapter(getSupportFragmentManager(),this);
//viewpager.setOffscreenPageLimit(2);
viewpager.setAdapter(mAdapter);
//actionBar.setHomeButtonEnabled(false);
actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
for (String tab : tabs){
actionBar.addTab(actionBar.newTab().setText(tab).setTabListener(this));
}
if(savedInstanceState != null){
actionBar.setSelectedNavigationItem( savedInstanceState.getInt("tab",0));
}
}
}
1st Fragment =>
public class PostInfoFragment extends Fragment {
private MenuItem myActionMenuItem;
private Button myActionButton;
private ActionBar actionBar;
private String post_title, post_desc,post_status;
private EditText submit_post_title, submit_post_desc;
private int position;
private Resources res;
SubmitPostActivity callingActivity;
List<String> post_details;
public PostInfoFragment(int position,SubmitPostActivity callingActivity )
{
this.callingActivity = callingActivity;
this.position = position;
}
//RelativeLayout rel_submit_post_start_date,rel_submit_post_end_date;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_post_info,
container, false);
/*if(!imageLoader.isInited()){*/
initImageLoader();
/*}*/
//handler = new Handler();
submit_post_title = (EditText) rootView
.findViewById(R.id.submit_post_title);
submit_post_desc = (EditText) rootView
.findViewById(R.id.submit_post_description);
actionBar = getActivity().getActionBar();
setHasOptionsMenu(true);
post_details = new ArrayList<String>();
res = getResources();
setListeners();
Log.d("postinfo_oncreate view", "postinfo_oncreate view");
//this is editText onchange listner do the same for submit_post_desc as well
submit_post_title.addTextChangedListener( new TextWatcher()
{
#Override
public void onTextChanged( CharSequence s, int start, int before, int count )
{
}
#Override
public void beforeTextChanged( CharSequence s, int start, int count, int after )
{
}
#Override
public void afterTextChanged( Editable s )
{
if( callingActivity != null )
{
//use this.position in order to update relevant data
List<String> post_details = callingActivity.dataModel;
if( post_details == null )
{
post_details = new ArrayList<String>();
}
post_details.add(s.toString());
}
}
} );
return rootView;
}
//making sure if the parent activity has implemented interface
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
// This makes sure that the container activity has implemented
// the callback interface. If not, it throws an exception
try {
callingActivity = (SubmitPostActivity) activity;
} catch (ClassCastException e) {
throw new ClassCastException(activity.toString()
+ "must implemet setPostInfo");
}
Log.d("postinfo_onattach", "postinfo_onattach");
}
}
Please not that this may not compile as it is. Try to get the concept.

How to Remove Fragment from FragmentPagerAdapter?

I know there are some topics about this here already but I could not find a solution which I could get to work for my case.
I have a working sliding gallery using a custom FragmentActivity and FragmentPagerAdapter which holds a list of Fragments.
Within the FragmentActivity is a ImageView "delete". If clicked, the function deleteMedia() is called which then should remove the current Fragment and the following Fragment should be displayed.
How would I have to do that in my example?
FragmentActivity:
public class GalleryPagerActivity extends FragmentActivity implements OnClickListener {
private Intent intent;
private SharedPreferences settings;
private PagerAdapter mPagerAdapter;
private ViewPager mPager;
private List<Fragment> fragments;
private List<WhiteboardMedia> wiList;
private int selectedPosition;
private LinearLayout llTop;
private TextView tvTop;
private ImageView delete;
private ImageView share;
private TextView tvCounter;
private TextView tvFilename;
private TextView tvFilesize;
private TextView tvDate;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
try {
super.setContentView(R.layout.gallery_pager);
intent = getIntent();
Type collectionType = new TypeToken<List<WhiteboardMedia>>(){}.getType();
wiList = gson.fromJson(intent.getStringExtra("wiList"), collectionType);
selectedPosition = intent.getIntExtra("position", 1);
llTop = (LinearLayout) findViewById(R.id.llTop);
llTop.setOnClickListener(this);
tvTop = (TextView) findViewById(R.id.tvTop);
tvTop.setOnClickListener(this);
delete = (ImageView) findViewById(R.id.imgDelete);
delete.setOnClickListener(this);
share = (ImageView) findViewById(R.id.imgShare);
share.setOnClickListener(this);
tvCounter = (TextView) findViewById(R.id.tvCounter);
tvFilename = (TextView) findViewById(R.id.tvFilename);
tvFilesize = (TextView) findViewById(R.id.tvFilesize);
tvDate = (TextView) findViewById(R.id.tvDate);
createContextMenu();
initDropbox();
} catch (Exception e) {
Log.e("GalleryPagerActivity", e.getLocalizedMessage());
}
}
/**
* Initialise the pager
*/
private void initialisePager() {
mPager = (ViewPager) super.findViewById(R.id.viewpager);
mPager.setAdapter(this.mPagerAdapter);
mPager.setOnPageChangeListener(new GalleryPageListener(tvCounter, tvFilename, tvFilesize, tvDate, wiList));
mPager.setCurrentItem(selectedPosition, true);
updatePage(selectedPosition);
}
public void updatePage(int position)
{
int focusedPage = position + 1;
Log.i("onPageSelected", "page selected " + position);
WhiteboardMedia wiImage = wiList.get(position);
String imageDate = "N/A";
try {
Date dateTaken= new Date(); //wiImage.getDate();
SimpleDateFormat sdf = new SimpleDateFormat("yy/MM/dd");
imageDate = sdf.format(dateTaken);
} catch (Exception e) {
}
try {
tvCounter.setText(focusedPage + "/" + wiList.size());
tvFilename.setText(wiImage.getFilename());
tvFilesize.setText(wiImage.getSize() + "a");
tvDate.setText(imageDate);
} catch (Exception e) {
}
}
#Override
protected void onResume() {
super.onResume();
}
#Override
public void onDestroy() {
super.onDestroy();
}
private WhiteboardMedia getActiveWhiteboardImage() {
return wiList.get(mPager.getCurrentItem());
}
private final int DELETE = 1;
#Override
public boolean onCreateOptionsMenu(Menu menu) {
menu.add(1, DELETE, 2, R.string.delete).setIcon(R.drawable.menu_btn_trash);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case DELETE:
deleteMedia();
return true;
}
return super.onContextItemSelected(item);
}
#Override
public void onClick(View v) {
if (v == delete) {
deleteMedia();
}
}
private void deleteMedia() {
// TODO delete the active Fragment and display the next Fragment in the list
}
/******************************************************************************
* Context Menu
*****************************************************************************/
private void createContextMenu() {
// context menu stuff
}
#Override
protected Dialog onCreateDialog(int id) {
// stuff
}
}
FragmentPagerAdapter:
public class GalleryPagerAdapter extends FragmentPagerAdapter {
private final List<Fragment> fragments;
public GalleryPagerAdapter(FragmentManager fm, List<Fragment> fragments) {
super(fm);
this.fragments = fragments;
}
#Override
public Fragment getItem(int position) {
return this.fragments.get(position);
}
#Override
public int getCount() {
return this.fragments.size();
}
}
Thanks for help!
that is the solution I'm using:
mViewPager : is the view you are using to set you Fragment
mViewPager = (YourViewPager) findViewById(R.id.myPager);
TABLE : is just a Integer list of the position of all my Fragments
public void destroyAllItem() {
int mPosition = mViewPager.getCurrentItem();
int mPositionMax = mViewPager.getCurrentItem()+1;
if (TABLE.size() > 0 && mPosition < TABLE.size()) {
if (mPosition > 0) {
mPosition--;
}
for (int i = mPosition; i < mPositionMax; i++) {
try {
Object objectobject = this.instantiateItem(mViewPager, TABLE.get(i).intValue());
if (objectobject != null)
destroyItem(mViewPager, TABLE.get(i).intValue(), objectobject);
} catch (Exception e) {
Log.i(TAG, "no more Fragment in FragmentPagerAdapter");
}
}
}
}
#Override
public void destroyItem(ViewGroup container, int position, Object object) {
super.destroyItem(container, position, object);
if (position <= getCount()) {
FragmentManager manager = ((Fragment) object).getFragmentManager();
FragmentTransaction trans = manager.beginTransaction();
trans.remove((Fragment) object);
trans.commit();
}
}
First, I suggest that you consider altering your FragmentPagerAdapter, to look more like the sample. You normally do not hold a list of fragments, any more than an ArrayAdapter normally holds a list of Views for the rows. Normally, you create the fragments on demand, and somebody else holds the list.
Then, to delete something, delete it from your model data (what the FragmentPagerAdapter normally wraps). Make sure that getCount() will then return the right number of items. Then, call notifyDataSetChanged() on the FragmentPagerAdapter, which should trigger a redraw of the ViewPager.
I found a solution ovverriding the method "onPostResume()" of the activity and calling the notifyDataSetChanged inside that.
#Override
protected void onPostResume() {
super.onPostResume();
if(this.mCustomPagerAdapter!=null){
this.mCustomPagerAdapter.notifyDataSetChanged();
}
}
If you are using FragmentPagerAdapter for adding and removing fragments at random position(not always at the end) dynamically, there is a method you need to taken more attention which is getItemId. By default, FragmentPagerAdapter uses position combines viewId as the tag name for fragments, however the position changes if you add or remove fragments. As a result, you may get an empty page because the position you are adding is occupied by an existing fragment. To solved this problem, override getItemId.
#Override
public long getItemId(int position) {
long itemId = ...; //Provide your unique ID here according to you logic
return itemId;
}
In my case, when i try to remove one item from the adapter, i will do as follow:
// get the position of item to remove
int position = getBinding().vp.getCurrentItem();
// remove the item from adapter
adapter.removeItem(position);
adapter.notifyDataSetChanged();
// minus one from the count
totalInvoice--;
updateTitle(getBinding().vp.getCurrentItem());
if (totalInvoice == 0) {
finish();
}
// set the adapter to view pager again
getBinding().vp.setAdapter(adapter);
// smooth scroll to given position
getBinding().vp.setCurrentItem(position);
The reason that i did above is that i find that even though you removed one from the data list, but the view of fragment still exist. So you have to let the view pager instantiate the view of given position. The answer above which trying to remove all fragments doesn't work for me. So, I find out the poor way of setting adapter to view pager again.

Categories

Resources