Is it possible to save Stack<Stack<View>> in onSaveInstanceState - java

Is it possible to save Stack<Stack<View>> in onSaveInstanceState.
May some another way how to save some specific data to manage Activity state?

You can't save views to bundle. And you shouldn't do it anyway. If activity is recreated it will reinflate layout again (or even inflate another one if configuration has changed) and create a new view hierarchy.
You should separate business data from your UI and store it onSaveInstanceState. After activity recreation you should get that data and update new views hierarchy accordingly.
For example, if you have a TextView, that displays some text that is stored in a field mSuperText, and your activity is going down, you should save it into a bundle in onSaveInstanceState:
#Override
protected void onSaveInstanceState(final Bundle outState) {
outState.putString("supertext", mSuperText);
}
And when your activity is recreated, in your method onCreate you get an argument onCreate(final Bundle savedInstanceState) which will be the bundle you stored previously. So you can get values you need:
#Override
protected void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (savedInstanceState != null) {
mSuperText = savedInstanceState.getString("superText");
}
}

Is it possible to save Stack> in onSaveInstanceState.
No, because Stack and View doesn't have the Parcelable / Serializable interface, which is necessary to put an Object in a Bundle. A Bundle only takes Arrays/ArrayList, String, primitives and so on.
May some another way how to save some specific data to manage Activity
state?
Which data you wanna save? If you wanna save a whole View/ViewGroup you are probably on the wrong way.
E.g to indicate that a TextView was visible set a boolean to true and put it in the Bundle. Check the boolean in onCreate() and set the View to visible. If the TextView had some text too, save it as String and set the text to the TextView, which you made visible.

Related

Store un-submitted data using Shared Preferences

I need to store data which hasn't been saved yet using Shared Preferences. To give a quick example, in my application I want that if the user filled the sign-up form and closed the application, his information will still be filled up when he re-enters the application. Would you suggest any tutorials?
You can save that data in Bundle using onSaveInstanceState
e.g.
#Override
public void onRestoreInstanceState(Bundle savedInstanceState) {
textView.setText(savedInstanceState.getString(TEXT_VIEW_KEY));
}
// invoked when the activity may be temporarily destroyed, save the instance state here
#Override
public void onSaveInstanceState(Bundle outState) {
outState.putString(GAME_STATE_KEY, gameState);
outState.putString(TEXT_VIEW_KEY, textView.getText());
// call superclass to save any view hierarchy
super.onSaveInstanceState(outState);
}
How about creating a ViewModel for your activity , your signup activity for instance.
This ViewModel will be your handler for your SharedPreferences and for keeping track of your data , say the values of the username and password text fields.
now you can override the method onCleared() and add there the implementation of writing to SharedPreferences.
in your activity you will need :
listen to your text fields using TextWatcher and probably override void afterTextChanged(Editable s) (since the user might just close the app) and inside update your ViewModel with the current value.
load data from your ViewModel in order to init your UI inside OnCreate() in case you have any data saved in your SharedPreferences.
onCleared()
This method will be called when this ViewModel is no longer used and will be destroyed.

How can I use the same XML layout for different activities?

I am making a quiz app which includes 50 different quizzes. I have a basic quiz layout with buttons and text views, and I want to use this layout with all my activities. For example, if the player choose the first quiz, the layout should come automatically and my Java code should provide the corresponding answers/questions. How can I do this?
Put layout id in setContentView(layout id) in your activity's onCreate() method.
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.your_layout);
}
in your other activities just changue your setContentView id like this :-
old contentViewId:-
setContentView(R.layout.yourCurrentView);
change id:-
setContentView(R.layout.yourNewView);

What is the best way to maintain the backstack of my Activity after Activity.Recreate() is called?

I have an Activity that handles many Fragments, and, for backstack management, I have a custom stack, where I manage show / hide for Fragments. My code and navigation work perfectly.
Right now, I am implementing the application theme change by a Button in the Configuration Fragment. For this I am using the method Activity.Recreate (); for the change of the theme and, the data of the Configuration Fragment is retained with the same data and the theme of the application changes perfectly, but the BackStack of Fragments disappears, reason why, when pressing the back button, it leaves the application, instead of sending me back to the Fragment or Previous Activity, from where I accessed the Configuration Fragment.
What is the best way to maintain the backstack of my Activity? This is possible?
Important: only when Activity.Recreate(); is called, because if the Activity is destroyed by any other way, I do not want the BackStack back, I want my Activity clean.
Additional:
The orientation setting of my application is in portrait mode.
The launchMode of my Activity is singleTask, it must be so for the type of application I am doing.
From onCreate documentation and this answer.
Add the following logic to your code:
public void onCreate(Bundle savedInstanceState) {
if (savedInstanceState == null) {
// savedInstanceState will be null only when creating the activity for the first time
backstack = new BackStack(); //init your backstack
} else {
// there is a chance that your backstack will be already exists at this point
// if not:
// retrieve the backstack with savedInstanceState.getSerializable("stack")
}
}
And just clear the stack when changing theme, before calling recreate()
// changing theme detected
bacstack.clear();
backstack = null;
recreate();
To save the stack between destruction (onDestroy) and recreation (onCreate) of your activity, Use this method:
#Override
protected void onSaveInstanceState(#NonNull Bundle outState) {
super.onSaveInstanceState(outState);
if (backstack != null) // the check isn't necessary, you can just put a null in the bundle
outState.putSerializable("stack", backstack);
}
the official guide
for saving UI state
The onSaveInstanceState method helps your activity to Survive
Configuration change and System-initiated process death.
link

Clarification regarding findViewById(int id) method in Android

I am going through Head First Android Development and I am a bit confused with
this method --> findViewById(int id)
I have the below button in the file "activity_find_beer.xml" :
<Button
android:id="#+id/find_beer"
android:text="#string/find_beer"
android:onClick="onClickFindBeer" />
and the following code from the class FindBeerActivity.java which is taking the user selected beer and displaying the same in a textview.
public class FindBeerActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_find_beer);
}
//Call when the button gets clicked
public void onClickFindBeer(View view) {
//Get a reference to the TextView
TextView brands = (TextView) findViewById(R.id.brands);
//Get a reference to the Spinner
Spinner color = (Spinner) findViewById(R.id.color);
//Get the selected item in the Spinner
String beerType = String.valueOf(color.getSelectedItem());
//Display the selected item
brands.setText(beerType);
}
}
My Question is the method onClickFindBeer(View view) takes a View type of
object as a parameter , but in the xml i have just mentioned
android:onClick="onClickFindBeer" and when the user clicks the
button , the method onClickFindBeer gets invoked...Who is passing the object of
type View to the onClickFindBeer(View view) ...is it something
implicit ?
Second,on developer.android.com I see that the method
findViewById(int id) is both in the Activity class (
https://developer.android.com/reference/android/app/Activity.html
) and also in the View class
https://developer.android.com/reference/android/view/View.html
... It's not clear to me which class (Activity or View)
findViewById(int id) method is invoked when i call findViewById()
from onClickFindBeer(View view){}.
Would be highly obliged if someone could throw light on this.
Regards.
The method takes a View parameter as that is how it is implemented in a superclass of the Button class (It is public class Button extends TextView.). The views you add to XML are actually java classes. When you set a property to such an XML item, that constructs the object from the particular java class accordingly. The onClick method of the View class goes as onClick(View v). By setting an XML you just asked the Button class to look for the entered method but its signature is always with a View as a paramenter, which refers to the view clicked.
findViewById has to be called on a View group. But the Actyvity class implements it to search an item in view assigned to it by the setContentView() method.
It is done somewhat implicitly. When building your app, the XML file is actually converted into Java file. When you click the view, the view is passed into the onClickFindBeer(View view) function.
The findViewById() is being called here by the activity. You can see the method declaration by clicking on findViewByID while pressing Ctrl. For a view, you would have to call it using the view. For example,
view.findViewById();
Its called JAVA Reflection which is used by android
2.
As I know, main difference is that when you used OnClickListener from activity it is connected with partivular object such as Textview,Button
find_beer.setOnClickListener and below code is excuted when someButton is pressed.
While android:onClick = "onClickFindBeer" is used handle click directly in the view's activity without need to implement any interface
You have assigned the method onClickBeer to your button. When the button gets clicked, the object, in this case the button, is passed to the method you assigned to it. A Button is a type of View object, so you have a more generic View object as the parameter, but you are perfectly ok to caste it to a button object.
findViewById is called through a "context", which is a way of getting at system resources. You are asking the system to return to you a specific object, which you can then use. It is worth reading up on contexts.
Hope that answers some of your query.
Base on your sample above the android:onClick method is the one being invoked because when invoking a onclick method in java class, it need to call a onClickListener.
cause on the other question. as far as I know it belong to the view class because it always to reference an object on your design.

Right Approach to Call Web Service(API) from Fragment class

I need to know, In which fragment callback method, we should call a web service by which after come back to fragment web service should not call again.
For example.
I have a fragment class MyFragment.java
public class MyFragment extends Fragment {
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
}
#Override
public void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_layout, container,
false);
return rootView;
}
}
I need to know which callback method I have to call webservice to update the UI of fragment. Right Now I am calling web services from onCreateView method. but I need to know what should be best way to call web service from fragment.
If I understand your problem correctly, you want to fetch some data from the server and then inform the fragment that data is prepared and redraw the fragment, is that correct? According to the documentation here:
onCreate() -
The system calls this when creating the fragment. Within your implementation, you should initialize essential components of the fragment that you want to retain when the fragment is paused or stopped, then resumed.
onCreateView()
The system calls this when it's time for the fragment to draw its user interface for the first time. To draw a UI for your fragment, you must return a View from this method that is the root of your fragment's layout. You can return null if the fragment does not provide a UI.
When you create a Fragment somewhere else in your application, onCreate() method is called. When fragment has to be drawn for the first time, onCreateView() is called and this method returns a created View. In your case, you could probably go with something like:
Declare an instance variable (container) for this data and adapter (if you use any).
In onCreate, initialize all this data (empty container), initialize adapter and then execute the AsyncTask.
In onCreateView, prepare the view to return - adapter etc. So now, once AsyncTask will finish, in onPostExecute it calls your_adapter.notifyDataSetChanged(). This will redraw the fragment, since adapter will be informed that data has changed (fetched from the server).
Depends on when you want to fetch the data.
Do you want it every time the app comes to the foreground?
Use onResume()
Do you want it only when the app starts for the first time?
Use onViewCreated(), which gets called after onCreateView is finished.
onCreate() is tricky.
Put everything that you want to call just once in onCreate() method.
For example your API call, list, adapter initialization.
So ideally I would do like this
public void onCreate(Bundle sis) {
getImagesFromServer(); // API Call
initialzeLists()
initializeAdapters()
}
public View onCreateView(LayoutInflater i, ViewGroup c,Bundle sis) {
recyclerView = findViewById()
setUpAdapters()
return rootView;
}
TRICKY PART
But if you really want onCreate() to be called once then reuse Fragment. (Don't create a new instance every time).
How to reuse a Fragment?
While Adding for first time use add it to backStack with a KEY like this
currentFragment = FirstFragment.getInstance();
getSupportFragmentManager()
.beginTransaction()
.replace(R.id.fragmentHolder, currentFragment, "FIRST_KEY")
.addToBackStack("FIRST_KEY")
.commit();
And when you want to add it again get the old instance with the KEY like this
currentFragment = getSupportFragmentManager().findFragmentByTag("FIRST_KEY");
getSupportFragmentManager()
.beginTransaction()
.replace(R.id.fragmentHolder, currentFragment, "FIRST_KEY")
.addToBackStack("FIRST_KEY")
.commit();
Demo project:
Here is the link to a demo project which loads a list of images using the Volley library. It has a similar implementation.
Woof - Use fragments the right way

Categories

Resources