Populating ListFragment from JSON - android

I've an Activity that extends ActionBarActivity and implements ActionBar.Listener.
It's acting like a View Pager. Inside that I have 3 ListFragment (organized in 3 tabs).
Now, I need to populate fragments with data from a back end.
Could you help me to organize code structure?
Should I use AsyncTask or a Loader? Is it better to put them in a separate public class?
Is it a good idea using retained fragments to preserve data through tabs swipe and
configuration changes?
The result I've in mind is a big loader image, placed in the center of the fragment waiting
for data. After a while it disappears and shows records inside ListFragment rows. Where should I put
the call to the AsyncTask (assuming use of this class)? In activity? Inside each fragment?
Which is the correct way to communicate to fragment that activity is calling onPostExecute and data are ready for use?
I'm quite confused about that, I just need a good way to start, it seems that everyone is approching
this in a different way and I don't know which is the best...

I've used json to populate a listfragment like this:
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
View view = inflater.inflate(R.layout.activity_lista_ordens, null);
context = inflater.getContext();
ordemServicoLista = new ArrayList<HashMap<String, String>>();
}
Here i execute the method to call webService and put all information in a listAdapter:
new CarregaOrdens().execute();
setListAdapter(adapterListaOrdens);

Related

Load data to a list fragment tab on the creation of the MainActivity

I am absolutely in love with these new components Android is introducing. So, I am building a standard mobile application with solely one activity using the Navigation components and Architecture components such as a View Model as I am performing a lot of communication with my data that I stored in room.
In one of my bottom navigation tabs, I have a list that is loaded from all my data in room. So far, I have set up my RecyclerView and my adapter in the OnCreateView() (only function used in this fragment) of this list fragment and every thing shows successfully.
The problem is that every time (especially more at first view) the fragment takes a solid 10 seconds to display all the data (which is normal considering there is a lot of it).
My question: Is there a way the adapter and and RecylcerView of this specific fragment could be setup (and load all my data) in the OnCreate() of my sole activity? So that when I view the fragment for the first time, everything pops up right away.
Also, how would I go about using OnPause() of the list fragment so that when I am on another tab, the list fragment doesn't get destroyed and when we go back on it, it displays right away?
Fetch all data from room inside onCreate() method of fragment. The onDestroyView() method calls everytime you moves away from the fragment.
To prevent recreation of views inside fragment store view in a variable.
Example:
class YourFragment extends Fragment{
View rootView;
#Override
public void onCreate(#Nullable Bundle savedInstanceState) {
//fetch data from room
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState){
if(rootView == null)
rootView = inflater.inflate(R.layout.your_fragment_layout, container, false);
return rootView;
}
}

Fragments: Replacing a fragment causes it to reinstantiate on back pressed

I am using one activity all fragment approach. Now I have a fragment A and when I go to fragment B I replace A in container with B with
.replace(R.id.master_fragment_container_above_toolbar, fragment)
.addToBackStack("")
.commit();
As you can see, I have added fragment to backStack. But now when I press back on device, it re-instantiates the fragment A and thus takes time to go back.
Is there another way to do it? I don't want to use add(), if I add multiple fragments to container, it will take up a lot of memory.
The short answer - there's no silver bullet in your case. You'll have to use replace() and it will re-create fragment's View on going back. That's "by design".
The good news is that there're a few tricks you can do to make it less dramatic for UX.
Cache whatever you can. If you load content from web - write it into the local SQLite db. And fill the screen from Local Storage while refreshing the data from the server.
In onCreateView() avoid re-creating Adapters once they are already exist. If user is getting back to FragmentA from the FragmentB, FragmentA will recreate its View. But it doesn't mean, that local variables are null at this point. So I do it like this:
public class FeedFragment extends Fragment {
private FeedAdapter adapter;
......
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View rootView = initialize(inflater, container, R.layout.fragment_with_recyclerview);
....
if (adapter == null) {
adapter = new FeedAdapter();
}
RecyclerView recyclerView = (RecyclerView)rootView.findViewById(R.id.recyclerView)
recyclerView.setAdapter(adapter);
recyclerView.setLayoutManager(new StaggeredGridLayoutManager(2, StaggeredGridLayoutManager.VERTICAL));
return rootView;
}
}
It matters, because filling TextViews, etc. are so fast operations, that you don't really care about it, while huge ListView or RecyclerView can be much more expensive;
Use image-caching and good image-loading tool. I'd recommend Picasso from Square. It has automatic memory and disk caching;
Try to logically decouple your app. Let's take a Gmail-style application, as an example:
It has NavigationDrawer, which is switching user through the root fragments (i.e. no need to keep navigation stack). Once you open mail-thread - it replaces the root fragment with MailThread fragment. There you can consume the content.
But once you click on "Compose email" - you are redirecting to a separate Activity - as you move from consuming content to composing content state (I.e. significant change in user's behaviour: new user scenario == new activity).
Many top developers go even further and having Activities for pretty much everything. Twitter (and it's satellite products) as an example. But personally, I prefer to keep it in balance (as opening new activity is an expensive operation from perf. point of view).

Fragment vs. Custom View in Android

The Fragment and Custom View can achieve the similar function, I know that fragment is more re-usable comparing with custom view, any other benefits/enhancements for using Fragment? Is fragment supposed to replace Custom View, or just a enhancement for some specific purpose?
For instance, the code below is fragment:
public class TestFragment extends Fragment {
private TextView tv_name;
private Button btn_play;
private Button btn_delete;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.testfragment, container, false);
}
#Override
public void onStart() {
super.onStart();
tv_name = (TextView)getView().findViewById(R.id.tv_name);
btn_play = (Button)getView().findViewById(R.id.btn_play);
btn_delete = (Button)getView().findViewById(R.id.btn_delete);
}
}
The code for custom view:
public class TestCustomView extends LinearLayout {
private TextView tv_name;
private Button btn_play;
private Button btn_delete;
public TestCustomView(Context context, AttributeSet attrs){
super(context, attrs);
setOrientation(LinearLayout.HORIZONTAL);
setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
tv_name = new TextView(context);
addView(tv_name);
btn_play = new Button(context);
addView(btn_play);
btn_delete = new Button(context);
addView(btn_delete);
}
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.testfragment, container, false);
}
}
Both TestFragment and TestCustomView can create a view consisting of TextView and Buttons, and use tags of Framelayout/fragment and com.packagename.TestCustomView to declare in the activity's xml layout file, but what's the advantages to use Fragment?
Fragment can be used in different scenarios but most used are:
wrapper around a view
headless fragment - i.e. no view => not very helpful in general but can be used
retainable fragment - can be any of above. By using Fragment.setRetainInstance(true) you can bypass Fragment.onDestroy(), i.e. can keep fragment data on configuration changes but fragment view structure is still destroyed/recreated
can be added to activity back stack, i.e. easy Back button previous state restore
There are cases where fragment are complete pain in the neck, then there are cases where they can achieve results quicker.
For some custom and more flexible situations fragments can get cluttered and managing them would be difficult. So dealing with views directly can be really handy and more helpful for some cases. But everything is based on requirements.
Note View has its own life cycle too and can store/recreate saved instance state. A little bit more work but it has the option too.
Custom Views have the advantage of simplicity and their primary purpose is to display a piece of data on the screen. They must rely on other components in order to do more.
Think of Fragments as a functional unit, a way to display a portion of UI that has a specific purpose, using one or more Views. Fragments are connected to the Activity lifecycle and they can include and control Loaders to populate the Views with data. They can also include sub-fragments. Finally, they can also be added to a synthetic back stack. They can do many things and are somewhat complex to learn.
As you can see, Fragments have much more in common with Activities than they have with custom views.
As a side note, Fragments can also be headless (with no UI). Headless fragments provide a way to encapsulate non-visual functionality relying on the Activity lifecycle in a separate component.
Fragments come with their own lifecycle, which can be a hinderance or a bonus, depending on what you need.
Fragments get lifecycle methods like onResume or onSavedInstanceState, which can help you deal with state transitions in your application. If you're using custom views, you need to handle that kind of things on your own.
There are people who advocate against using fragments, I suggest reading https://developer.squareup.com/blog/advocating-against-android-fragments/
The most useful functionality of using Fragments over Custom Views is that they have their own Lifecycle Callbacks, i.e. we can register our own FragmentLifecycleCallbacks to do some operations before/after Fragment creation/destruction.
We can create our own FragmentLifecycleCallbacks and register it with Activity to inject dependencies in Fragment through Dagger.
There are some workarounds to inject dependencies in Custom Views too, but doing it through FragmentLifecycleCallbacks is much cleaner and easier to do.

Refreshing visible text of a TextView in a Fragment without recreating entire Activity?

While developing my App i ran into some issues while "bugfixing"
In my onCreate() method of my MainActivity 1 service and 1 activity are being started.
They collect data (3 strings in the service, 1 string in the other activity) and i use the onAvitivityResult method to do the job. Because i use an activity instead of a single service it seems like a window is popping in and out quickly (Service and Activity both run AsyncTasks) and i dont really like that too much.
I have recoded basically everything to fit everything inside one service and pass the result on to another class that delivers the strings back to the MainActivity. I am using a default preset (swipeViews) and as it is right now the fragment only displays the string i assigned to it, well great, however that string is being updated by my service, yet the textView itself not.
How do i make my textView ("textView1") refresh and display the new string ("ClassC.datumh") without having to recreate the entire MainActivity?
This right here is only a snippet of the output method
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_main, container, false);
TextView textView1 = (TextView) rootView.findViewById(R.id.section_label);
textView1.setText(ClassC.datumh); //some random string that comes out of the service
rootView.invalidate();
return rootView;
}
earlier on i used to recreate the MainActivity simply, but as mentioned, i dont really like the "popping" effect created by this..
onCreateView is only called when the view is created. You don't want to recreate the TextView, just update its text.
make textView1 an instance variable in the MainActivity. When the MainActivity receives the string from the Service, have it run
textView1.setText(newStringReceivedFromYourService);
Reinitializing the entire ViewPager did the job. It recreated the TextViews just fine and i was able to see the new Values
ClassC.mViewPager.setAdapter(MainActivity.mMyFragmentPagerAdapter);
For this to work in my service that retrieved the Strings i had to make the ViewPager static in another class (ClassC) and thus i can access it at any given time.

More instances of fragment at one time - resources referencing to wrong views in android

this is a though one for me. I have a MainActiviy which extends FragmentAnctivity. There I have 1 FrameLayout and buttons below to change frame's content. I do so by switching show/hide for created fragments which I added to FrameLayout before in OnCreate.
I'm also nesting more fragments in 1 fragment (As I have 1 fragment for 1 type of content and inside of it there is listFragment which is changed to DetailFragment after OnItemClick... again with show/hide approach).
Problem is that in 2 different contents I have 2 different instances of 1 Fragment class, so those 2 instances use 1 same layout file. And although the first of those fragment is hidden and 2nd is shown, when I change some view through 2nd instance then layout of 1st instance is changed and 2nd remains same as before. (Hope it is understandable)
I guess it's totally a mistake in managing and understanding of fragments' lifecycle, so can please someone help me to solve this?
Thanks very much :)
I suppose you get main point of fragments using practices. Your problem is simple. I almost sure you use getActivity().findViewById(...) calls to access views in your Fragment (or nested Fragment whatever). I this case Activity would return you fist view with defined id from whole your views hierarchy.
Solution is pretty simple - you just must avoid getActivity().findViewById(...) construction and get all links to views in onCreateView() callback and use exact this link with all future operations. Than everything will be ok. Here is simple example:
private TextView mDummyText;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.layout_name, container, false);
initMembersViews(v);
return v;
}
private void initMembersViews(View v) {
mDummyText = (TextView) v.findViewById(R.id.fr_houses_list_text);
}
Hope it would helps you! Good luck!

Categories

Resources