I am trying to save the tags for all fragments in an activity that are currently visible.
So I defined these:
// Fragment TAGS
private final static String EDIT_COLLECTIONS_TAG = "edit collection";
public final static String EDIT_IMAGE_TAG = "edit image";
public final static String ADD_IMAGE_TAG = "add image";
// Collection of Frag Tags
private final static String[] FRAG_TAGS = {EDIT_COLLECTIONS_TAG, EDIT_IMAGE_TAG, ADD_IMAGE_TAG};
And in onSaveInstanceState(Bundle outState) I did:
for(String tag : FRAG_TAGS){
if(getFragmentManager().findFragmentByTag(tag).isVisible()){
outState.putString(tag, tag);
}
}
...but LogCat informed me that the if line was throwing the null pointer exception.
So not knowing why I tried:
if(getFragmentManager().findFragmentByTag(FRAG_TAGS[1]).isVisible()){
outState.putString(EDIT_IMAGE_TAG, EDIT_IMAGE_TAG);
}
...and that worked.
So it seems there isn't a problem with accessing the array. On a lark I changed the array's contents to actually strings: {"EDIT_COLLECTIONS_TAG", "EDIT_IMAGE_TAG", "ADD_IMAGE_TAG"} but that didn't change the outcome.
So what's going on here?
Given the input by Marko Lazic I discovered two errors:
Not all added fragments were given tags, this resulted in nulls. This has been rectified.
Cannot use a static list of all fragment tags because, obviously, some will not have been added yet and as Marko indicated, can't find a fragment that isn't there yet, so this was also throwing null.
Solution:
I needed to find a way to create a dynamic list of tags for added fragments. This was accomplished with:
#TargetApi(Build.VERSION_CODES.HONEYCOMB_MR2)
#Override
public void onAttachFragment(Fragment fragment) {
super.onAttachFragment(fragment);
// add attached fragment's tag to set of tags for attached fragments
AddedFragmentTagsSet.add(fragment.getTag());
// if when adding the fragment another fragment has become detached, remove its tag from the set
for(String tag : AddedFragmentTagsSet){
if(getFragmentManager().findFragmentByTag(tag).isDetached()){ // or isVisible() probably
AddedFragmentTagsSet.remove(tag);
}
Log.d(TAG, SCOPE +"contents of AddedFragmentTagsSet: " +tag);
}
}
Thank your for the help, folks.
Related
I just curious what makes a value inside of some variable become empty again or back to its initial value in the android life cycle.
First lets take a look at how i create a variable :
public class myData {
public static String myCode = "";
public static String getData(String Choice) {
String theData = "";
if ("Code".equals(Choice) {
theData = myCode;
}
return myCode;
}
public static void setData(String setData,String Choice) {
if ("Code".equals(Choice) {
myData.myCode = setData;
}
}
}
If I want to fill the variable, i usually do this :
myData.setData("value of variable","Code");
And if I want to get the value of the variable, I usually do this :
myData.getData("Code");
I just want to know what makes my variable gone inside of android lifecycle, of course excluding when the application is closed.
I have to try to Log and show the value in onstart , oncreate, onresume and onrestart. And all of them is still have the value inside of my variable intact without any problem.
My client always tells me that my application sometimes gets crash when they open some activity. I also ask if they did something while using my application,
some of them answer that the application get crashed after they got a phone call and when the phone call is ended, the application is started with a crash.
some of them also said that when they open the application and then idle the phone withouth closing the application until the phone become black screen, and when they open it again the application get crashed.
After I check the log, the problem was the variable become empty. which is why I want to know is there another possibilites that makes the value inside of the variable become empty?
As John Lord saying, on low-end device variables might back to its initial value again if there is not enough memory.
So for future reference, I use a shared preference to counter it, here is my structure for fetching the data :
public class myActivity extends AppCompatActivity {
String myCode = "";
protected void onCreate(Bundle savedInstanceState) {
....
SharedPreferences sharedPreferences = getApplicationContext().getSharedPreferences("myData", Context.MODE_PRIVATE);
myCode = sharedPreferences.getString("Code",null);
....
}
#Override
protected void onResume() {
super.onResume();
SharedPreferences sharedPreferences = getApplicationContext().getSharedPreferences("myData", Context.MODE_PRIVATE);
myCode = sharedPreferences.getString("Code",null);
}
}
And here is how i set the data :
SharedPreferences sharedPreferences = getApplicationContext().getSharedPreferences("myData",Context.MODE_PRIVATE);
sharedPreferences.edit().putString("Code","Hello World").apply();
I hope it will be helpful for those who want to search the same thing
I tried reading a number of solutions on Stack Overflow and have found they either don't work for my scenario or I simply don't understand their explanation (I am very new to Java and Android.
I have strings set up under res/values/strings.xml that I wish to use in the class:-
public class AttractionFragment extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.word_list, container, false);
// create an array list of details
final ArrayList<Details> details = new ArrayList<>();
// Details details
details.add(new Details(getActivity().getString(R.string.fun_bigsplash_name), getString(R.string.fun_bigsplash_addr), R.string.fun_bigsplash_num, R.drawable.bigsplash));
I've tried a number of variants (the reason they are different is just to show what I tried) but can't work it out. The R.drawable.bigsplash works fine (when I'm using literal strings for the others).
The error message states an int, which I assume means it's getting the reference and not the actual string.
How do I get the string from within the fragment?
Thanks.
You can use:
getResources().getString(R.string.my_string);
or just:
getString(R.string.my_string);
Read String value or String Array In Java Code.
Define a string array in strings.xml use string-array xml element.
Show Selection
<string name="auto_complete_text_view_car">Input Favorite Car Name</string>
<string-array name="car_array">
<item>Audi</item>
<item>BMW</item>
<item>Benz</item>
<item>Ford</item>
<item>Toyota</item>
<item>Tesla</item>
<item>Honda</item>
<item>Hyundai</item>
</string-array>
Read String Value In Java Code. Only string name
Inside Activity::
String defaultInputText = getResources().getString(R.string.auto_complete_text_view_car);
Inside Fragment::
String defaultInputText = getActivity().getResources().getString(R.string.auto_complete_text_view_car);
Read the string array in java source code. Please note car_array is just the string array name defined in strings.xml.
Inside Activity::
String carArr[] = getResources().getStringArray(R.array.car_array);
Inside Fragment::
String carArr[] = getActivity().getResources().getStringArray(R.array.car_array);
Simplest way to get string from resource in any part of your code is to override Application class and create static method to obtain "Application context".
For example, check out the application class for my app AB Music.
https://github.com/amit-bhandari/AB-Music-Player/blob/master/app/src/main/java/com/music/player/bhandari/m/MyApp.java
Refer method
public static Context getContext(){
return instance;
}
Now you can get string from resource anywhere in your code by simply calling.
MyApp.getContext().getString(R.string.mystring)
Hope it helps!
try this one
getActivity().getResources().getString(R.string.app_name)
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'm working with Steppers. So currently i have one Activity with 3 Fragments in which the user must complete with some information, like a Form.
There are a lot of information so i made 4 classes to separate that information.
In addition, some information is got it automatically so in fragments i ask for permissions...
For Example:
public class UserIds {
#Nullable
#Expose String phone;
#Expose String Email;
#Expose String phone2;
#Expose String ModCel;
#Expose String Doc;
//Setters, getters and another simple method
public class UserLocation {
#Nullable
#Expose String street;
#Expose int number;
....
//Setters, getters and another simple method
...
And so on with 2 classes more.
So, as you can see i'm working with retrofit too.
How can I correctly handle something like that?
I read about Parceler , Interfaces, EventBus...
Should I declare all objects instances in the Activity and then modify in each fragment ( Some objects are modified by differents fragments) or maybe create instances in each fragment, store the information and in when the Complete button is pressed, obtain the information? How should i save this objects in case of OnDestroy() call?
Another things to take into account is that finally, when the form is end. Other activity may have all the information and ask for more (yeah, a LOT OF INFORMATION IS NEEDED).
Finally, every time the user complete the form (with the complete button and then when the other activity ask for more, this data is sended to the server)
I chose the Parceler way and work perfectly. Maybe help somebody, i put #Parcel in each POJO class, then as i am handling with fragments with StepperAdapter (because of stepstone library) in the fragment which i want to save data i did this:
// Obtaing all the fragments
List<Fragment> steps = getFragmentManager().getFragments();
// save states
Bundle bundle = new Bundle();
Parcelable wrapped = Parcels.wrap(obj1);
Parcelable wrapped2 = Parcels.wrap(obj2);
bundle.putParcelable("OBJ1", wrapped);
bundle.putParcelable("OBJ2", wrapped2);
steps.get(fragment2reference).getArguments().putAll(bundle);
Then in the fragment that receive, you have to create a constructor and then you can receive the data (because of fragment was already created, so the bundle throw error)
//Constructor
public fragment2(){
super();
setArguments(new Bundle());
}
When fragment2 shows :
OBJ1 a = Parcels.unwrap(getArguments().getParcelable("OBJ1"));
OBJ2 b = Parcels.unwrap(getArguments().getParcelable("OBJ2"));
Hope somebody help!
private String u_id;
private String u_name;
#Override
public void onSuccess(LoginResult loginResult) {
if(Profile.getCurrentProfile() == null) {
mProfileTracker = new ProfileTracker() {
#Override
public void onCurrentProfileChanged(Profile profile, Profile profile2) {
// profile2 is the new profile
u_id = profile2.getId().toString();
u_name = profile2.getName().toString();
mProfileTracker.stopTracking();
}
};
// no need to call startTracking() on mProfileTracker
// because it is called by its constructor, internally.
}
else {
Profile profile = Profile.getCurrentProfile();
u_id = profile.getId().toString();
u_name = profile.getName().toString();
}
/*new CreateNewProduct().execute();*/
/*updateFacebookButtonUI();*/
}
I want get value u_id and u_name to add arraylist, but it return null. I tried log have result. I need way resolve. Thanks :(
List<NameValuePair> params = new ArrayList<NameValuePair>();
params.add(new BasicNameValuePair("u_id", u_id)); // return null
params.add(new BasicNameValuePair("u_name", u_name)); // return null
Yes, adding "" results will not be null, but I want to get the value of the variable inside the onSuccess method to pass to the List below. The list below is in another class in same file with on Success
Variables u_id and u_name can be null only if they were not initialised. You don't set their value when adding the field to the class.
private String u_id; //only type and name set, not the value
I think if you're sure their value have to be set somewhere in the inner methods (doesn't matter in if or else either), it's not so dangerous to leave it like this. Also I would bet you're calling params.add(...)... after the above lines, unless it would cause the variables being null too...
But if you really want to get something back from your variables, you can initialise them as plain empty strings (""),
private String u_id = ""; //the variable's value is set too
and maybe later handle the "empty-string" checking before adding their value to your List<NameValuePair> variable; however it's not necessary. The main thing is: this way you can be 100% sure your variables won't be null...
EDIT #1: I don't know much about the structure of your file which contains onSuccess() method and the class with your list inside of it, but I would say it's another Java class file (MyClass.java or similar). I'm not an expert in Android multithreading, but I would say there is not anything that could block your inner class with your list to access the fields in the outer base class. You can reach fields anytime and anywhere in a class, no matter you want to do it in that very class or in the 10th nested inner class or method.
So unless your code does not look similar to this, I would think my first answer (above the edit) should be the solution. Maybe you should provide the code of your full class(es) to find the best solution, not just parts like you did first time.