Loading same data from API on different Tab Fragments - android

I have 3 tab fragments in my app, each meant to show different data from the same API URL (one call of 10 records).
This is the final result im trying to achieve:
Tab 1: Show records 1-5 from my API URL
Tab 2: Show records 6-10 from my API URL
Tab 3: Show different values from records 1-10
My goal is to load all this data in the first tab (Tab1) and show different results from the the JSON data returned in each tab as explained above.
Progress so far: Coded Tab1 to show records 1-10.
Need your help with:
Make Tab1 show records 1-5 and not all 10. Since I want to load all 10 results in the same run and wont call the API multiple times, I don't wish to limit the number of results.
Code Tab2 show records 6-10 from the JSON DATA received in Tab1. Means I need to communicate from Tab2 to my Tab1
Hope to get direction for this, Thanks!
What I've been thinking about:
Setting 3 static JSONOAdapters and set it with the json result and use it for each tab. but..
Does static JSON Adapters will be a good solution or may cause memory problems?
Another problem: When I use this:
public void updateData(JSONArray jsonArray) {
// update the adapter's dataset
mJsonArray = jsonArray;
notifyDataSetChanged();
}
I get results 1-10, I have no idea how to limit it to the first 5 or results 6-10.

Load data from 1 to 10 in your activity or fragment contains 2 fragments
After that add function setData for each fragment which data you want.
Last, go to your fragment and load data you set before.

Load Data in your activity.
Initiate ViewPager Adapter and send Array of Items in the Constructor.
public class MyPagerAdapter extends FragmentPagerAdapter {
private static int NUM_ITEMS = 3;
ArrayList<Item> arr;
public MyPagerAdapter(FragmentManager fragmentManager,ArrayList<Item> arr) {
super(fragmentManager);
this.arr=arr;
}
// Returns total number of pages
#Override
public int getCount() {
return NUM_ITEMS;
}
// Returns the fragment to display for that page
#Override
public Fragment getItem(int position) {
switch (position) {
case 0: // Fragment # 0 - This will show FirstFragment
return FirstFragment.newInstance(arr.subList(0,5));
case 1: // Fragment # 1
return FirstFragment.newInstance(arr.subList(6,10));
case 2: // Fragment # 2
//Change your values according to you need then pass the arr in Frag 3
return SecondFragment.newInstance(arr);
default:
return null;
}
}
// Returns the page title for the top indicator
#Override
public CharSequence getPageTitle(int position) {
return "Page " + position;
}
}
Make static method in your Fragment to receive the array of items.

Related

How can I use (one fragment + one activity + viewpager) to display multiple strings

I am basically doing a reading app with 18 subjects.
I need to shrink my project because I got one activity and 18 fragments that contains two Text views: one of them represent a normal String from strings.xml, and the other one represent a string from strings.xml with HTML attributes with images. I tried to build a setting for the users to control the font size and color and I failed because I ended up with 18 text views for titles and 18 text views for the threads.
I planned to do my project in just one fragment that contains just two text views; one for titles and the other one for the threads.
Here is an image explaining my thought
I figure out how to do the title because it just one string with out html attributes but when it came to doing both i failed
from the activity:
public static Thread0_Fragment create(String mThreadTitle){
Thread0_Fragment fragment = new Thread0_Fragment();
Bundle arg = new Bundle();
arg.putString(ARG_PAGE, mThreadTitle);
fragment.setArguments(arg);
return fragment;
}
from the fragment view pager adapter:
#Override
public Fragment getItem(int position) {
switch (position) {
case 0:
return Thread0_Fragment.create(getString(R.string.thread_18));
default:
return null;
}
}

I can´t execute code in the last fragment of a TabLayout

My problem: I am following this link " https://guides.codepath.com/android/google-play-style-tabs-using-tablayout " to develop a sliding tab layout and get something like this:
Image
I followed the guide and the SlideTabLayout seems to work pretty good, BUT. I´ve realize that if i try to make some code it works perfect in all the tabs but in the last one. I have to say i always use the same Fragment class, so the code should work on all the tabs.
For example, I´ve put a Log.e message in the fragment and i see the message in all the tabs but the last one.
After all i´ve tried following another guide using PagerTabStrip instead of TabLayout and I am having the same problem.
The fun part is the last page shows correctly the TextView with the page number.
Fragment pager adapter:
public static class MyPagerAdapter extends FragmentPagerAdapter {
private static int NUM_ITEMS = 3;
public MyPagerAdapter(FragmentManager fragmentManager) {
super(fragmentManager);
}
// Returns total number of pages
#Override
public int getCount() {
return NUM_ITEMS;
}
// Returns the fragment to display for that page
#Override
public Fragment getItem(int position) {
switch (position) {
case 0: // Fragment # 0 - This will show FirstFragment
return PageFragment.newInstance(0, "Page # 1");
case 1: // Fragment # 0 - This will show FirstFragment different title
return PageFragment.newInstance(1, "Page # 2");
case 2: // Fragment # 1 - This will show SecondFragment
return PageFragment.newInstance(2, "Page # 3");
default:
return null;
}
}
// Returns the page title for the top indicator
#Override
public CharSequence getPageTitle(int position) {
return "Page " + position;
}
}
You see two fragments created because that is how FragmentPagerAdapter works to provide you a smooth transition between 2 tabs (2 fragments). I guess that your code may run for the first time, then it will not run if the fragment is already in memory. This is how Android says about FragmentPagerAdapter
"This version of the pager is best for use when there are a handful of typically more static fragments to be paged through, such as a set of tabs. The fragment of each page the user visits will be kept in memory, though its view hierarchy may be destroyed when not visible. This can result in using a significant amount of memory since fragment instances can hold on to an arbitrary amount of state"

I've got a weird bug when using a ViewPager inside a Fragment

Okay i'll try and make this as clear as possible. I have a Fragment called CheckerManager which contains a ViewPager. This ViewPager will allow the user to swipe between 3 Fragments all of which are an instance of another Fragment called CheckerFragment. I'm using a FragmentPagerAdapter to handle paging. Here's how it looks
private class PagerAdapter extends FragmentPagerAdapter {
CharSequence mTabTitles[];
public PagerAdapter(FragmentManager fm, CharSequence tabTitles[]) {
super(fm);
mTabTitles = tabTitles;
}
#Override
public Fragment getItem(int position) {
switch(position) {
case 0:
return CheckerFragment.newInstance(MainFragment.DRAW_TITLE_LOTTO);
case 1:
return CheckerFragment.newInstance(MainFragment.DRAW_TITLE_DAILY);
case 2:
return CheckerFragment.newInstance(MainFragment.DRAW_TITLE_EURO);
default:
return null;
}
}
#Override
public CharSequence getPageTitle(int position) {
return mTabTitles[position];
}
#Override
public int getCount() {
return 3;
}
}
I know that the ViewPager will always create the Fragment either side of the current Fragment. So say my 3 CheckerFragments are called A, B and C and the current Fragment is A. B has already been created. But my problem is that even though I am still looking at Fragment A, Fragment B is the 'active' Fragment. Every input I make is actually corresponding to Fragment B and not A. The active Fragment is always the one which has been created last by the ViewPager.
I've looked at quite a few things to see if anyone has had the same problem but i'm finding it difficult to even describe what's wrong. I think it's something to with the fact that all of the ViewPagers fragments are of the same type ie - CheckerFragment. I have a working implementation of a ViewPager inside a fragment elsewhere in the application and the only difference I can tell is that each page is a different type of Fragment.
Any help would be appreciated!
*EDIT
PagerAdapter adapter = new PagerAdapter(getChildFragmentManager(), tabTitles);
ViewPager viewPager = (ViewPager)view.findViewById(R.id.viewPagerChecker);
viewPager.setAdapter(adapter);
I feel pretty stupid but I found out what the issue was. In my CheckerFragment I would call getArguments() to retrieve a String extra and I would use this to determine how to layout the fragment. Problem was I made this extra a static member of CheckerFragment. So every time a new Fragment was created it was using the most recent extra.
Moral of the story - Don't make your fragments extra a static member if you plan on making multiple instances of that fragment.

Android - Add item to listview in fragment update

Been stuck on this for a while.
I currently have 3 fragments each containing lists - A | B | C (Favorites)
A and B retrieve data from online, C is an offline favorite list.
When a user favorites something in A it shows up in the favorite list straight away as the ViewPageAdapter loads 1 extra page off the screen. So A | B are already loaded, which means when I go to favorites (C) it has to reload.
My problem is - When I favorite something in B, the app refuses to reload favorites (C) as C was already loaded when I clicked on B and the only way to see what I have added is refresh the app.
I have tried:
Changing setOffscreenPageLimit(); to 0 so it has to reload each fragment every time - even if clunky just to see it working, and it still refuses to.
NotifyDataSetChanged also hasn't worked or I don't understand it properly.
InstatiateItem in the ViewPageAdapter, but couldn't get that working, couldn't find a good example of it to understand
Creating a new listadapter in the favorite code just to try to get it load the new data - which I can see in the logs it is adding to the favourite list but it just isn't being reloaded by the ViewPageAdapter
Lots of Googling
What happens is, regardless of what I do, when the user goes from B to C, no new code runs as C's code all ran once I clicked on B and it just goes straight to C's list.
I'm using Google's SlidingTabLayout and SlidingTabStrip for the fragments which all works fine, nothing changed in it. found here - https://developer.android.com/samples/SlidingTabsBasic/src/com.example.android.common/view/SlidingTabLayout.html
Code:
public void favourite()
{
//if the user wants to favourite
ParseQuery<ParseObject> query = ParseQuery.getQuery("Favourite");
//queries the id from the local data store in-case they have already favourited
query.whereEqualTo("id",id);
query.fromLocalDatastore();
query.getFirstInBackground(new GetCallback<ParseObject>() {
public void done(ParseObject object, ParseException e)
{
if(object!=null)
{
Toast.makeText(getApplicationContext(),"You have already pinned this",Toast.LENGTH_SHORT).show();
}
else
{
//otherwise create a new ParseObject and save the id,title and backdrop to
//the local datastore
final ParseObject favouriteShow = new ParseObject("FavouriteShow");
favouriteShow.put("id", id);
favouriteShow.put("title", title);
favouriteShow.put("backdrop", backdropPath);
favouriteShow.pinInBackground();
Toast.makeText(getApplicationContext(),"Pinned - "+ title,Toast.LENGTH_SHORT).show();
//need to set favourite as null for it to redraw with the favourited icon
mFavourite.setImageDrawable(null);
mFavourite.setImageResource(R.drawable.favourited_already);
}
}
});
}
ViewPagerAdapter:
public class ViewPagerAdapter extends FragmentStatePagerAdapter {
CharSequence Titles[];
int tabNumber;
public ViewPagerAdapter(FragmentManager fm, CharSequence[] mTitles, int mTabNumber) {
super(fm);
this.Titles = mTitles;
this.tabNumber = mTabNumber;
}
#Override
public Fragment getItem(final int position) {
Fragment fragment = null;
switch (position) {
case 0:
fragment = new FragmentA();
break;
case 1:
fragment = new FragmentB();
break;
case 2:
fragment = new FavouritesFragmentC();
break;
}
return fragment;
}
#Override
public CharSequence getPageTitle(int position) {
return Titles[position];
}
#Override
public int getCount() {
return tabNumber;
}
}
Thanks very much for your help.
Adam
Use ViewPager.OnPageChangeListener and update the corresponding
fragment in onPageSelected(position) method using callback pattern.
I've personally had a similar problem.
The solution to this problem depends on the whether the data shown in each tab is contextually related.
If not, the best way to fix this is actually changing the navigational structure of the application. So instead of having tabs, you should use a navigation drawer. Therefore every time the user enters the screen through the drawer, the fragment is created anew. By doing this it will solve the problem you have and improve the user experience.
If so, you may need to create as base fragment for all of the tabs to inherit, with a function called refresh, then you can ask the Adapter to refresh all your tabs. This method is quite hacky mostly because a favourites section doesn't belong in tabs.

FragmentPageAdapter works in a strange way

Since in Android L the the Action bar navigation modes are deprecated I'm searching an other way to have the tab and I found that is possible to use the PagerTabStrip (android.support.v4.view.PagerTabStrip), so I created a FragmentPageAdapter in this way:
public class TitleAdapter extends FragmentPagerAdapter {
private final String titles[] = new String[] { "Home", "Events", "People", "Books"};
private final Fragment frags[] = new Fragment[titles.length];
Context context;
public TitleAdapter(FragmentManager fm) {
super(fm);
}
#Override
public CharSequence getPageTitle(int position) {
Log.v("TitleAdapter - getPageTitle=", titles[position]);
return titles[position];
}
#Override
public Fragment getItem(int position) {
Log.v("TitleAdapter - getItem=", String.valueOf(position));
//return frags[position];
switch (position) {
case 0:
return Home.newInstance(0, "Home");
case 1:
return Events.newInstance(1, "Events");
case 2:
return People.newInstance(2, "People");
case 4:
return Books.newInstance(3, "Books");
}
return null;
}
#Override
public int getCount() {
return frags.length;
}
}
The strange way that i see in LogCat is that the method getItem() is called 4 times when the mainActivity starts so I've to wait a lots because in each Tab there is a quite long list and this list is populated via HTTP request calling a web service.
I wish load only a fragment each times and not all. When i used actionbar.Tablistener it was possible but now the method is deprecated so is there a way to do that?
I set the adapter and the viewPager in the onCreate method in this way:
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.prova_page_tab_stripes);
mViewPager = (ViewPager) findViewById(R.id.viewpager);
titleAdapter = new TitleAdapter(getSupportFragmentManager());
mViewPager.setAdapter(titleAdapter);
mViewPager.setOffscreenPageLimit(1);
}
The number of pages initialized depends on setOffscreenPageLimit function of ViewPager. As per android doc in http://developer.android.com/reference/android/support/v4/view/ViewPager.html#setOffscreenPageLimit(int),
public void setOffscreenPageLimit (int limit)
Set the number of pages that should be retained to either side of the current page in the view hierarchy in an idle state. Pages beyond this limit will be recreated from the adapter when needed.
This is offered as an optimization. If you know in advance the number of pages you will need to support or have lazy-loading mechanisms in place on your pages, tweaking this setting can have benefits in perceived smoothness of paging animations and interaction. If you have a small number of pages (3-4) that you can keep active all at once, less time will be spent in layout for newly created view subtrees as the user pages back and forth.
You should keep this limit low, especially if your pages have complex layouts. This setting defaults to 1.
Parameters
limit How many pages will be kept offscreen in an idle state.
Set it to 1 or keep it to default if you wan to limit pages to be retained.
But if you want to load the data only in one page at a time, you can determine when fragment becomes visible and then load the data (insted of loading in onCreateView.)
Refer this question: How to determine when Fragment becomes visible in ViewPager

Categories

Resources