I have one Activity having 5 buttons: button1, button2, button3, button4, button5.
button1 clicks----open fragment1
button2 clicks----openf ragment2
button3 clicks----open fragment3
button4 clicks----open fragment4
button5 clicks----open fragment5
In fragment1 I am downloading data and displaying in a customized listview. In fragment2 I am downloading data and displaying in edittexts, textviews..etc.
But if I click the button1 again data is downloading again. I want to show the same view where the user comes back from fragment1 to fragment2 by clicking buttons.
How can I reach this logic? Please help me in this. If you want any information I will provide.
Thank you in advance!
EDIT : I need google chrome tab functionality in android fragments.here tabs are fragments.if you open one website in google search and open onother page in anothe tab.if you can navigate to first tab you can see the opened one only.in my case i am starting from the scratch of the fragment.how to reach chrome tab functionality in android fragments.
There are many ways to go around it. whatever data you have download you can store it either temporarily or permanently. if you want to store it temporarily you can:
use an ArrayList<HashMap<String,String>> object to store it.
or permanently using either
SQLiteDatabase or
SharedPrefrences
depending on the data type.
Now whenever you open your fragment you can check if the data already exists if not you hit the Service and get the data otherwise you can read directly from the source you have chosen.
I would use the Model-view-controller architecture on this app.
This means create a class to store this data. Use the singleton pattern when designing the class. First time the user press Button 1, upon creation of the fragment, call a method from the Model class to check if the data is downloaded or not. If it's not downloaded then fetch it, store it in the class and display it. If data is downloaded then use an method from the Model class to get the data and display it.
If you have small a amount of data to display you can use bundles or intents to store it.
UPDATE:
Below is a simple example of a singleton class that can be used to store your data and find out if your class contains initialized data or not. In my example I used as data an int value but you are free to use whatever type you want, even a class.
public class SingletonExample {
private static SingletonExample mSingleton = null;
private int mMyData;
private boolean mDataInitialized;
private SingletonExample() {
mDataInitialized = false;
}
public static SingletonExample getInstance() {
if (mSingleton == null) {
mSingleton = new SingletonExample();
}
}
return mSingleton;
}
public boolean isDataInitialized() {
return mDataInitialized;
}
public void setMyData(int myData) {
mMyData = myData;
mDataInitialized = true;
}
public int getMyData() {
return mMyData;
}
}
The singleton call you call like this:
SingletonExample mDataBank = SingletonExample.getInstance( );
mDataBank.setMyData(0);
Related
In my app , at a particular screen there is Arraylist which is a source of recycler view . There are many buttons on that screen which takes you to next screen , next screen may be a single plain activity or activity with view pager and tablayout and that fragment may contain buttons which takes you to next screen .In some screen i can edit the Song class field too . My problem is that i am confused whether the send the list to next screen and further next fragment or next screens through intent or should i make that static and access it anywhere . Again and again i have to parcel wrap and then unwrap then send it to fragment then wrap for the fragment then unwarp it then send it to adpater attached to fragment , this is long process and i am afraid that anyone can change that list in any screen and secondly this whole process is cumbersome every time sending intent and receiving intent .
Passing the Values from Intent have chances of data loss so do not pass the multiple Values with the Intent. So it will be better to access the values from a Static class if the values are not changing. If sometimes values are changing then pass these with Intent.
You can also go with the SharedPreferences, it will be more feasible in your case.
You can shift to flux architecture. Redux store kind of state management.
Who ever needs data queries to store. And data changes automatically dispatched to listeners.
SharedPreferences are NOT made to pass data between Activities/Fragments. They are here to store data that need to persist when the app is closed.
An option could be to use some kind of "cache" class that will store your data. So let's say you display the list of whatever data you want on the first screen, then the user selects one of the items to see the details/modify it. So you give the position of this data (in the array stored in the cache) to your next fragment and this next fragment asks the cache to give to it the data, based on the position it has received.
Example
Cache class
public class Cache{
List<Object> data;
// ... Implementation
public List<Object> getData(){
return this.data;
}
public setData(List<Object> data){
this.data = data;
}
public Object getObject(int position){
return data.get(position);
}
}
List Activity
public class ListDataActivity extends ListActivity{
public void onCreate(...){
// get the data
...
// Set the data to the cache
Cache.getInstance().setData(data);
// Display the list
...
}
public void onItemClicked(...){
Intent intent =....
intent.put(ITEM_POSITION, pos);
startActivity(intent);
}
}
Details Activity
public class DetailsActivity extends Activity{
public void onCreate(...){
//...
// get data from the cache
int pos = getIntent.getInt(ITEM_POSITION);
Object obj = Cache.getInstance().getObject(pos);
// Display the details
...
}
}
I have a fragment X which indeed has a RecyclerView, X has a search view, I use the search view to search something and filter the RecyclerView into few rows. After the filtering, if user clicks on some row, it goes to another fragment say Y. From there if the user clicks back it comes back to X. My task is that X should persist the search results after this coming back. What is the best approach to achieve this?
You can use a the singleton pattern to store the data!
E.g.
// DataManager.java
public class DataManager {
private static DataManager thisInstance;
// Declare instance variables
List<String> searchResultItems;
public static DataManager getSharedInstance() {
if (thisInstance == null) {
thisInstance = new DataManager();
}
return thisInstance;
}
private DataManager() {
searchResultItems = new ArrayList<>();
}
public List<String> getSearchResultItems() {
return searchResultItems;
}
public void setSearchResultItems(List<String> searchResultItems) {
this.searchResultItems = searchResultItems;
}
}
Now you can store and retrive data from everywhere:
// Setter
DataManager.getSharedInstance().setSearchResultItems(items);
// Getter
List<String> items= DataManager.getSharedInstance().getSearchResultItems();
Propertly override onSaveInstanceState in Fragment so that it will store search input - filter. Also override onCreate in such way it will apply saved filter on your RecyclerView.
Before navigating to another fragment, obtain Fragment.SavedState via FragmentManager and save it temporary in Activity which hosts your fragments. Note, this state can be lost if you do not properly save Activity state due of configuration changes (rotate) = you have to override also onSaveInstanceStatein Activity. Or simply save Fragment.SavedState in global scope (some static field, or in Application).
When navigating back to previous fragment, re-create fragment from Fragment.SavedState i. e. invoke Fragment#setInitialSavedState(Fragment.SavedState).
For more details see my research on similar topic.
I have a main activity which has 2 fragments. The main activity has a SearchView in the action bar. Both the fragments have a list of large number of strings, List<String>.
The flow is:
User enters Fragment I --> Selects a string (lets say Selection1) --> Based on Selection1 a list of strings is populated in the second fragment --> Here the user selects a second String ---> Processing based on these two strings.
Now since both the fragments contain a large number of strings, the user enters a query in the SearchView, which filters the list and reduces it to a smaller list displayed in the SearchableActivity.
Now the problem is how does the SearchableActivity get access to these two List<String> to filter them based on the query and display a reduced list to the user.
Currently what I have done is overridden onSearchRequested and pass the data as
#Override
public boolean onSearchRequested()
{
Bundle appData = new Bundle();
appData.putString(FRAGMENT_ID, "Fragment_A");
appData.putStringArrayList(SEARCH_LIST, searchList);
startSearch(null, false, appData, false);
return true;
}
Is there a better way or standard way by which this problem can be handled i.e. an implementation that allows data to be based from my MainActivity to SearchableActivity?
Edit: Adding code. Showing how data is set in the Fragment. onDataReceived is called from the HttpManager which receives the data.
#Override
public void onDataReceived(String type,final Object object)
{
switch(type)
{
case PopItConstants.UPDATE_LIST:
getActivity().runOnUiThread(new Runnable() {
#Override
public void run()
{
updateCinemaList((List<String>) object);
}
});
break;
}
}
public void updateDataList(List<String> data)
{
this.dataList = data;
spinner.setVisibility(View.GONE);
mAdapter.updateList(dataList);
}
I just answered a similar question a few minutes ago, at how can I send a List into another activity in Android Studio
I encourage you to rethink your pattern of simply passing data around among Activities and Fragments. Consider creating one or more data models (non-Android classes) for your application, and making these models available to the Android classes (Activities, Fragments, etc.) that need them.
Remove all of the data storage and manipulation code from your Activities and Fragments, and put it into the model(s).
Okay... So this is how I did it.
Basically, the data received in the two fragments was not simply List<String> but they were models viz. Cinema and Region which contained details other than names including location, rating etc.
So, firstly, I made an interface ISearchable
public Interface ISearchable
{
// This contains the Search Text. An ISearchable item is included
// in search results if query is contained in the String returned by this method
public String getSearchText();
//This is meant to return the String that must be displayed if this item is in search results
public String getDisplayText();
//This is meant to handle onClick of this searchableItem
public void handleOnClick();
}
Both the Cinema and Region models implemented ISearchable.
After this, I used a singleton class DataManager in which I maintained a List<ISearchable> currentSearchList.
public class DataManager
{
.....<singleton implementation>....
List<ISearchable> currentSearchList;
public void setSearchList(List<ISearchable> searchList)
{
this.currentSearchList = searchList;
}
public List<ISearchable> getSearchList()
{
return this.currentSearchList;
}
}
So whenever a fragment (either Fragment_A or Fragment_B) is loaded, it updates this currentSearchList, so that when the SearchableActivity performs search all it has to do is DataManager.getInstance().getSearchList() and then use this list for filtering out a list of matching items.
This is how I handled the problem of having Lists in Activity other than the SearchableActivity using which search needs to be performed.
I understand this might not be the best solution, so, I look forward to suggestions and criticisms, and using that to be arrive at a better solution.
I have seen few question on SOF, but neither of them helped.
In my application I have a List of users which can be accessed by clicking friends of a user. The flow is:
Go to my profile
Click on my friends to go to an Activity which has list of users(my friends)
Click on any of the listView Item takes to that user's profile
From that profile I can see that user's friends list the same way as mine.
The problem is all these listView items have a button to add as friend which makes me and that user as friend in that list(like follow changes to following in twitter) now I come back through the backstack, and somewhere in one of the previous listViews that user is present for whom the button is still add as friend.
How to change the button(a flag in my adapter data) for that user in all the ListViews?
Use Interface to send events back to the activity and update the list or database when the event is received.
Interfaces are ways of passing messages to "the outer world". Just look at a simple button onClickListener. You basically call a setOnClickListener(this) on the button and implement onClickListener, which is an interface here. Whenever the button is clicked, you get an event in onClick. It is the safest way to pass messages between activities without the need of intents ( which according to me is a huge pain in the ... ) Here is an example:
Example:
class A extends Activity implements EventInterface{
public A(){
//set a listener. (Do not forget it!!!)
//You can call it wherever you want;
//just make sure that it is called before you need something out of it.
//safest place is onCreate.
setEventInterfaceListener( A.this );
}
//this method will be automatically added once you implement EventInterface.
void eventFromClassB(int event){
//you receive events here.
//Check the "event" variable to see which event it is.
}
}
class B{
//Interface logic
public interface EventInterface{
public static int BUTTON_CLICKED = 1;
void eventFromClassB(int event);
}
static EventInterface events;
public static void setEventInterfaceListener(EventInterface listener) {
events = listener;
}
private void dispatchEvent(int trigger) {
if (events != null) {
events.eventFromClassB(trigger);
}
}
//Interface ends
void yourMethod(){
//Call this whenever you want to send an event.
dispatchEvent( BUTTON_CLICKED );
}
}
My application works this way:
ListView---->onListItemClick---->detailspage---->backpressed---->goes
back to the list---->click the same item again---->same detailspage
loads again.
The details page gets a lot of data from a server and populate its views.
So, it takes 2-4 secs every time an item is clicked in the listview. I have seen apps where they wont load any data if the same page is called 2nd time.
How can I do that?
Currently in my app its like this:
onCreate call AsyncTask to get data and populate the view
nothing in onResume, onPause, onStart, onStop, onDestroyed
You can keep the data for that domain object in a singleton and then when you enter your details page there are two ways to go.
If for instance you had a list of Person class.
public class Person {
private String name;
private Image img;
...
}
Then you could have a PersonCache that was a singleton caching the data for the last Person selected in your list:
public class PersonCache {
private Person cachedPerson;
private static PersonCache instance;
private PersonCache(){
...
}
public PersonCache getInstance(){
if(instance == null){
instance = new PersonCache();
}
return instance;
}
public Person getCachedPerson(){
return cachedPerson;
}
public void setCachedPerson(Person p){
cachedPerson = p;
}
}
So in onCreate when you finish fetching your JSON data you create a Person object and call setCachedPerson.
If you know that the data in the details page won't have been updated:
In onCreate in details page you check if the object that has been selected is the same as the one cached in your singleton (if the objects have unique ids in your database you can look at those to check if it's the same).
If you don't know whether there's new data:
You can use the If-Modified-Since technique when making your GET request in your AsyncTask.
Basically what you do is add a header parameter
key: If-Modified-Since
value: Sat, 29 Oct 1994 19:43:31 GMT
If the server has no new data it can respond with 304 and send no response body but if it has new data it will respond with 200 and send the data just like normal.
Implementing this would require some implementation on the server side as well.
Here's some more info on the technique:
http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html (section 14.25)