Store un-submitted data using Shared Preferences - java

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.

Related

How can I access methods from my Main Activity in my Settings activity?

I am currently developing a Voice Recorder app for Android. I am trying to access a few methods in my MainActivity from my Settings activity, in order to change some settings for my MediaRecorder.
I have the method below, which sets up the Audio Settings for the recording, in my MainActivity.
// set up all audio settings
private void setAudioSettings() {
mediaRecorder.setAudioSource(MediaRecorder.AudioSource.DEFAULT);
mediaRecorder.setAudioSamplingRate(44100);
mediaRecorder.setAudioEncodingBitRate(96000);
mediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
mediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.HE_AAC);
}
In my Settings activity, I have a standard preferences screen that I would like to show options to change the audio codec, sampling rate, etc. of the media recorder in MainActivity.
How can I access the setAudioSettings method from MainActivity here in order to do so?
If you need to see more code or screenshots, please let me know.
Make that method as static so you can call without creating the class object
public static void yourMethod(){
//Write your code here
}
And call your method like this way:
MainActivity.yourMethod();
The short answer is you should not use the functions of your one activity into another activity.
For your case, I would suggest you to have a singleton object or shared preference to store your data of settings screen. Then in onStart of MainActivity, read the singleton object or shared preference and call #setAudioSettings method accordingly.
save setting i.e values in shared preferences and then get from preferences in Main Activity.
You can make your method static by:
public static void setAudioSettings() {
mediaRecorder.setAudioSource(MediaRecorder.AudioSource.DEFAULT);
mediaRecorder.setAudioSamplingRate(44100);
mediaRecorder.setAudioEncodingBitRate(96000);
mediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
mediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.HE_AAC);
}
But to do that mediaRecorder needs to be static also.
Later you can call this method from any activity by:
MainActivity.setAudioSettings();
You can learn more about static keyword for example here.
But, I am not sure that use of static method is the best solution for exactly your problem, maybe will be better to set SharedPreferences in your SettingActivity and later in onResume() of your MainActivity call setAudioSettings() method and get there values from SharedPreferences?

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

How to check/access a different activity's lifecycle from the current activity?

I want to access the activity lifecycle method of a different activity from the present one... Can i do that? for example i have 2 activities A and B. I want to access the onStop method of activity A from activity B. can i do that? i'm trying to check the online of a user in my app which has multiple activities so i want to write code which is like = If onStop/onDestroy method of both the activities are called show that the user is offline... The code im using is
#Override
public void onStart(){
super.onStart();
mDatabaseReference.child("Online").setValue(true);
}
#Override
public void onStop(){
super.onStop();
mDatabaseReference.child("Online").setValue(false);
}
Can someone please help me out
Use Application.ActivityLifecycleCallbacks in your Application class. This way you just need to register your activities to the callbacks and from the application class only you can track down wheather any activity is present or not.
For more info please refer to this answer
To set the value You can use SharedPreferences. Declare the instance of sharedpreference at application level.
In Activity A and B you can set the value in onStop(), onDestroy() and onStart() block.

Send Object created from MainActivity to Fragments TabbedView [duplicate]

This question is mostly to solicit opinions on the best way to handle my app. I have three fragments being handled by one activity. Fragment A has one clickable element the photo and Fragment B has 4 clickable elements the buttons. The other fragment just displays details when the photo is clicked. I am using ActionBarSherlock.
The forward and back buttons need to change the photo to the next or previous poses, respectively. I could keep the photo and the buttons in the same fragment, but wanted to keep them separate in case I wanted to rearrange them in a tablet.
I need some advice - should I combine Fragments A and B? If not, I will need to figure out how to implement an interface for 3 clickable items.
I considered using Roboguice, but I am already extending using SherlockFragmentActivity so that's a no go. I saw mention of Otto, but I didn't see good tutorials on how to include in a project. What do you think best design practice should be?
I also need help figuring out how to communicate between a fragment and an activity. I'd like to keep some data "global" in the application, like the pose id. Is there some example code I can see besides the stock android developer's information? That is not all that helpful.
BTW, I'm already storing all the information about each pose in a SQLite database. That's the easy part.
The easiest way to communicate between your activity and fragments is using interfaces. The idea is basically to define an interface inside a given fragment A and let the activity implement that interface.
Once it has implemented that interface, you could do anything you want in the method it overrides.
The other important part of the interface is that you have to call the abstract method from your fragment and remember to cast it to your activity. It should catch a ClassCastException if not done correctly.
There is a good tutorial on Simple Developer Blog on how to do exactly this kind of thing.
I hope this was helpful to you!
The suggested method for communicating between fragments is to use callbacks\listeners that are managed by your main Activity.
I think the code on this page is pretty clear:
http://developer.android.com/training/basics/fragments/communicating.html
You can also reference the IO 2012 Schedule app, which is designed to be a de-facto reference app. It can be found here:
http://code.google.com/p/iosched/
Also, here is a SO question with good info:
How to pass data between fragments
It is implemented by a Callback interface:
First of all, we have to make an interface:
public interface UpdateFrag {
void updatefrag();
}
In the Activity do the following code:
UpdateFrag updatfrag ;
public void updateApi(UpdateFrag listener) {
updatfrag = listener;
}
from the event from where the callback has to fire in the Activity:
updatfrag.updatefrag();
In the Fragment implement the interface in CreateView do the
following code:
((Home)getActivity()).updateApi(new UpdateFrag() {
#Override
public void updatefrag() {
.....your stuff......
}
});
To communicate between an Activity and Fragments, there are several options, but after lots of reading and many experiences, I found out that it could be resumed this way:
Activity wants to communicate with child Fragment => Simply write public methods in your Fragment class, and let the Activity call them
Fragment wants to communicate with the parent Activity => This requires a bit more of work, as the official Android link https://developer.android.com/training/basics/fragments/communicating suggests, it would be a great idea to define an interface that will be implemented by the Activity, and which will establish a contract for any Activity that wants to communicate with that Fragment. For example, if you have FragmentA, which wants to communicate with any activity that includes it, then define the FragmentAInterface which will define what method can the FragmentA call for the activities that decide to use it.
A Fragment wants to communicate with other Fragment => This is the case where you get the most 'complicated' situation. Since you could potentially need to pass data from FragmentA to FragmentB and viceversa, that could lead us to defining 2 interfaces, FragmentAInterface which will be implemented by FragmentB and FragmentAInterface which will be implemented by FragmentA. That will start making things messy. And imagine if you have a few more Fragments on place, and even the parent activity wants to communicate with them. Well, this case is a perfect moment to establish a shared ViewModel for the activity and it's fragments. More info here https://developer.android.com/topic/libraries/architecture/viewmodel . Basically, you need to define a SharedViewModel class, that has all the data you want to share between the activity and the fragments that will be in need of communicating data among them.
The ViewModel case, makes things pretty simpler at the end, since you don't have to add extra logic that makes things dirty in the code and messy. Plus it will allow you to separate the gathering (through calls to an SQLite Database or an API) of data from the Controller (activities and fragments).
I made a annotation library that can do the cast for you. check this out.
https://github.com/zeroarst/callbackfragment/
#CallbackFragment
public class MyFragment extends Fragment {
#Callback
interface FragmentCallback {
void onClickButton(MyFragment fragment);
}
private FragmentCallback mCallback;
#Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.bt1
mCallback.onClickButton(this);
break;
case R.id.bt2
// Because we give mandatory = false so this might be null if not implemented by the host.
if (mCallbackNotForce != null)
mCallbackNotForce.onClickButton(this);
break;
}
}
}
It then generates a subclass of your fragment. And just add it to FragmentManager.
public class MainActivity extends AppCompatActivity implements MyFragment.FragmentCallback {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
getSupportFragmentManager().beginTransaction()
.add(R.id.lo_fragm_container, MyFragmentCallbackable.create(), "MY_FRAGM")
.commit();
}
Toast mToast;
#Override
public void onClickButton(MyFragment fragment) {
if (mToast != null)
mToast.cancel();
mToast = Toast.makeText(this, "Callback from " + fragment.getTag(), Toast.LENGTH_SHORT);
mToast.show();
}
}
Google Recommended Method
If you take a look at this page you can see that Google suggests you use the ViewModel to share data between Fragment and Activity.
Add this dependency:
implementation "androidx.activity:activity-ktx:$activity_version"
First, define the ViewModel you are going to use to pass data.
class ItemViewModel : ViewModel() {
private val mutableSelectedItem = MutableLiveData<Item>()
val selectedItem: LiveData<Item> get() = mutableSelectedItem
fun selectItem(item: Item) {
mutableSelectedItem.value = item
}
}
Second, instantiate the ViewModel inside the Activity.
class MainActivity : AppCompatActivity() {
// Using the viewModels() Kotlin property delegate from the activity-ktx
// artifact to retrieve the ViewModel in the activity scope
private val viewModel: ItemViewModel by viewModels()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
viewModel.selectedItem.observe(this, Observer { item ->
// Perform an action with the latest item data
})
}
}
Third, instantiate the ViewModel inside the Fragment.
class ListFragment : Fragment() {
// Using the activityViewModels() Kotlin property delegate from the
// fragment-ktx artifact to retrieve the ViewModel in the activity scope
private val viewModel: ItemViewModel by activityViewModels()
// Called when the item is clicked
fun onItemClicked(item: Item) {
// Set a new item
viewModel.selectItem(item)
}
}
You can now edit this code creating new observers or settings methods.
There are severals ways to communicate between activities, fragments, services etc. The obvious one is to communicate using interfaces. However, it is not a productive way to communicate. You have to implement the listeners etc.
My suggestion is to use an event bus. Event bus is a publish/subscribe pattern implementation.
You can subscribe to events in your activity and then you can post that events in your fragments etc.
Here on my blog post you can find more detail about this pattern and also an example project to show the usage.
I'm not sure I really understood what you want to do, but the suggested way to communicate between fragments is to use callbacks with the Activity, never directly between fragments. See here http://developer.android.com/training/basics/fragments/communicating.html
You can create declare a public interface with a function declaration in the fragment and implement the interface in the activity. Then you can call the function from the fragment.
I am using Intents to communicate actions back to the main activity. The main activity is listening to these by overriding onNewIntent(Intent intent). The main activity translates these actions to the corresponding fragments for example.
So you can do something like this:
public class MainActivity extends Activity {
public static final String INTENT_ACTION_SHOW_FOO = "show_foo";
public static final String INTENT_ACTION_SHOW_BAR = "show_bar";
#Override
protected void onNewIntent(Intent intent) {
routeIntent(intent);
}
private void routeIntent(Intent intent) {
String action = intent.getAction();
if (action != null) {
switch (action) {
case INTENT_ACTION_SHOW_FOO:
// for example show the corresponding fragment
loadFragment(FooFragment);
break;
case INTENT_ACTION_SHOW_BAR:
loadFragment(BarFragment);
break;
}
}
}
Then inside any fragment to show the foo fragment:
Intent intent = new Intent(context, MainActivity.class);
intent.setAction(INTENT_ACTION_SHOW_FOO);
// Prevent activity to be re-instantiated if it is already running.
// Instead, the onNewEvent() is triggered
intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_CLEAR_TOP);
getContext().startActivity(intent);
There is the latest techniques to communicate fragment to activity without any interface follow the steps
Step 1- Add the dependency in gradle
implementation 'androidx.fragment:fragment:1.3.0-rc01'

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

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.

Categories

Resources