I am a newbie to android. My question is not about how to do something, but more on the idea I have in mind is optimized or not.
I am creating a Chat App. The biggest issue I was facing was storing Non persistent data, coz whenever the activity closed, all data was lost. The biggest problem was when user moved from Chat Screen (Chat Activity) to Peoples List (Peoples Activity) all data was lost again, and if user reinitited chat, he couldnt see the history.
As a workaround, I am creating a few data classes, and a service. The service stores data in the classes, whenever it receives an update from activity or the server. After that on each new activity I will just pass around this object from one activity to another and service.
I would like some recommendations in this, Is this a good way to go around? Thanks for your precious time.
If I've understood properly, you need a way to store data of variables or the content of one data structure or whatever and don't lose this data when your app change across severals activities, right? You need save state across several Activities.
First solution: in Java, one solution for this problem could be to use "static" variables. You can do it but using Android, we can use a more elegant solution.
Second and recommended solution: Associate the state with the Application Context (easy)
You should create your own subclass of android.app.Application. It will work like a singleton.
One subclass of Application inherit the properties of Application and you can access to this class wherever you want using the command "Context.getApplicationContext()". Normally you will use this class to have everthing that need a global access. Example:
class YourName_App extends Application {
private ArrayList<String> chatConversation;
public String getChatConversation(){
return this.chatConversation;
}
public void setChatConversation(ArrayList<String> chat){
this.chatConversation = chat;
}
}
And now your Chat Activity:
class Chat extends Activity {
ArrayList<String> conversation;
#Override
public void onCreate(Bundle b)
{
...
YourName_App appState = ((YourName_App) getApplicationContext());
conversation = appState.getChatConversation();
...
}
}
It is done! This is the best way to do it.
Sorry for my poor english.
Related
Many times we use intents to send data to a Fragment or get data back from a child. Can't we just put data in a public variable?
For example imagine if we want to get data from user from a dialog box.
I'm just talking about the "possibility". Undoubtedly, It is superior to use intents for code cleanness or safety...
you don't send intent's to fragments, if you want to use objects you need to have your object implement Parcelable then you can just send the object in the intent bundle
public class MyActivity extends Activity {
public int someValue = 1;
}
And in any fragment which has MyActivity as a host you can access ((MyActivity) getActivity()).someValue.
I think what he means is sending (local)broadcast... which is by the way the proper way of doing it according to my understanding.
Of course it is possible to have public (or even protected) fields and access them from a child-fragment with something like this:
assuming your parent activity is named "MainActivity"
((MainActivity) getActivity()).mMyPublicField
or:
((MainActivity) getActivity()).getPublicMethod()
- but I would never recommend doing this!
especially when you also start manipulating the public field you can run into ugly trouble when different threads are in play.
If something needs so be shared across the whole application, use SharedPreferences (if you want to store it for the next app session too) or as I mentioned first LocalBroadCastManager.
I have created an Android application that uses a singleton to hold its state. The class is instantiated when the application starts.
The application does make extensive use of fragments but is not a single Activity application.
The problem occurs when an activity crashes for some (any) reason.
Normally, Android closes the activity bringing to the foreground the previous one that was active. Since the previous activity also used the singleton somehow, it needs data from it to resume (for example). The thing is that the singleton is no longer available while the previous activity is running in a new Application Context forcing the Singleton to re-instantiate itself with no data of course.
One way to surpass this problem seems to be storing the state (serialized or not) in a file or the database but that means too many read writes on pretty much every other user activity which should be avoided. Apart from UX, this solution might lead to inconsistent or erroneous data from faulty or untimely synchronisations.
I would like to hear your input on the matter.
Cheers!
Here is the Singleton instantiation method.
final public class Data {
private static Data INSTANCE = new Data();
private Data() {}
public static Data getInstance() {
return INSTANCE;
}
}
If you declare your singleton as static on a root activity it should be saved. We used static varaibles linked to a baseline activty from which every activity dereives.
Antoher solution might be to use sharedpreferences.
It is nice to worry about performance but if you have many fragments and few activities, it would be the fragment that will cause the lion share of teh workload
1) You can use an Application class. It's gonna be destroyed at the very last stage.
2) If your data is not structured - you can keep it in SharedPreferences (as a String mapped with JSON for example)
3) If your data is structured - you should store it in DB (or better ContentProvider)
My problem seemed simple to me, but apparently it isn't.
I got a core class that is able to calculate a complex result depending on parameters entered by a user. Up to now I showed the result as a ListView and for the detail view, I used a sliding panel - so everything is neat within one activity A.
But now, I wanted to get rid of the sliding design and "simply" use a master/detail flow so I could show two fragments next to each other on tablets and separately on a mobile phone.
Well, I did not want to redesign the whole app for that, but basically: how do I get the detail information to my different activity B???
I know that through an Intent I can only send Parcelable (or serializable) data, but that is far to complex for essentially int-array-type of data! All the converting to and re-constructing from the Intent - that is just a pain!
Of course, I also do not need a database or similar complicated stuff - no SharedPrefs, please, that is all at least as complex as implementing the Parcelable!
Basically, I thought of two approaches, but they all ... stink ... kind of:
a) store the calculated data within the application class - problem: the app might get destroyed and restarted just for re-displaying activity B. Then there wouldn't be anything left in the app object!
b) implement a content provider that does the calculation and caching the result there. Hmm. The cursor again is way to complex to transfer the simple result. And: for how long should I cache the result in the ContentProvider?
I feel this is all a mess. :-(
Any ideas?
The Intent approach is by far the simplest one.
Talking about a Master/Detail flow, usually that means passing one id, this is few information and easily reconstructed from A to B (activity).
Don't use A for exactly the reason you mentioned, and B wow! too much work =)
I really think either use an Intent or use shared Prefs they are by far the least code demanding options.
Have you been able to create the behavior of the app getting destroyed and everything being deleted? I've been developing an app doing some things along the same lines and I have just been using public static variables to store things in the activity that they are created in. That way they are accessible from other activities. Not necessarily the most elegant way of doing things but it's working for me just fine.
oh man its not mess:)
did you aware of Design patterns if yes then you can use singleton pattern where you can store data for your next activity
public class mySingleton
{
mySingleton instance;
yourvariable1;
yourvariable2;
yourvariable3;
yourobject1;
yourobject2;
public static mySingleton getSingletonInstance()
{
if(instance==null)
{
instance=new mySingleton();
}
return instance;
}
}
by this you can save your data till your any activity is running or you may say untill your application is in system memory
but if you want to close application and persist data then make a background service there you can save data your applications activities will destroy but the service will contain the variables and data
hope it will solve your problem
I'm working on a fairly complex Android application that requires a somewhat large amount of data about the application (I'd say a total of about 500KB -- is this large for a mobile device?). From what I can tell, any orientation change in the application (in the activity, to be more precise) causes a complete destruction and recreation of the activity. Based on my findings, the Application class does not have the same life-cycle (i.e. it is, for all intents and purposes, always instantiated). Does it make sense to store the state information inside of the application class and then reference it from the Activity, or is that generally not the "acceptable" method due to memory constraints on mobile devices? I really appreciate any advice on this topic. Thanks!
I don't think 500kb will be that big of a deal.
What you described is exactly how I tackled my problem of losing data in an activity. I created a global singleton in the Application class and was able to access it from the activities I used.
You can pass data around in a Global Singleton if it is going to be used a lot.
public class YourApplication extends Application
{
public SomeDataClass data = new SomeDataClass();
}
Then call it in any activity by:
YourApplication appState = ((YourApplication)this.getApplication());
appState.data.UseAGetterOrSetterHere(); // Do whatever you need to with the data here.
I discuss it here in my blog post, under the section "Global Singleton."
Those who count on Application instance are wrong. At first, it may seem as though the Application exists for as long as the whole app process exists but this is an incorrect assumption.
The OS may kill processes as necessary. All processes are divided into 5 levels of "killability" specified in the doc.
So, for instance, if your app goes in the background due to the user answering to an incoming call, then depending on the state of the RAM, the OS may (or may not) kill your process (destroying the Application instance in the process).
I think a better approach would be to persist your data to internal storage file and then read it when your activity resumes.
UPDATE:
I got many negative feedbacks, so it is time to add a clarification. :) Well, initially I realy used a wrong assumption that the state is really important for the app. However if your app is OK that sometimes the state is lost (it could be some images that will be just reread/redownloaded), then it is fully OK to keep it as a member of Application.
If you want to access the "Global Singleton" outside of an activity and you don't want to pass the Context through all the involved objects to obtain the singleton, you can just define a static attribute in your application class, which holds the reference to itself. Just initialize the attribute in the onCreate() method.
For example:
public class ApplicationController extends Application {
private static ApplicationController _appCtrl;
public static ApplicationController getAppCtrl()
{
return _appCtrl;
}
}
Because subclasses of Application also can obtain the Resources, you could access them simply when you define a static method, which returns them, like:
public static Resources getAppResources()
{
return _appCtrl.getResources();
}
But be very careful when passing around Context references to avoid memory leaks.
Dave, what kind of data is it? If it's general data that pertains to the application as a whole (example: user data), then extend the Application class and store it there. If the data pertains to the Activity, you should use the onSaveInstanceState and onRestoreInstanceState handlers to persist the data on screen rotation.
You can actually override the orientation functionality to make sure that your activity isn't destroyed and recreated. Look here.
You can create Application class and save your all data on that calss for use that anywhere in your application.
I know this is the very old question but using the ViewModel from the jetpack components is the best way to preserve the data between Activity rotation.
The ViewModel class is designed to store and manage UI-related data in a lifecycle conscious way. The ViewModel class allows data to survive configuration changes such as screen rotations.
I am working on an Application that require some interaction between two activities, and I am not sure of what is the best way to achieve it:
One of the Activities is a "Logbook" (Just a ListView that displays a bunch of events).
The other Activity allows the user to create the events, that will be sent (and displayed in the Logbook).
How do I notify my Logbook Activity when a new Event is ready to be added?
Also, where should I add the event to the database? From the Logbook Activity, when I add it to the ListView, or from the NewEvents Activity, as soon as it's ready?
Thanks!
Ok, I found how to do it, using a BroadcastReceiver:
In my Logbook activity, I just set up a new custom receiver onCreate():
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_logbook);
registerReceiver(new EventReceiver(this), new IntentFilter("SEND_NEW_EVENT"));
Now, I can make the calls in my newEventActivity:
public void sendToLogbook(int eventId){
Intent i = new Intent("SEND_NEW_EVENT");
i.putExtra("newEvent", this.newEvents[eventId]);
sendBroadcast(i);
}
Of course, I had to create my CustomReceiver Class, and override the onReceive() method to do what I want:
public class EventReceiver extends BroadcastReceiver {
private ActivityLogbook activity;
public EventReceiver(ActivityLogbook activity) {
this.activity = activity;
}
public void onReceive(Context context, Intent i) {
this.activity.addToReport((Event)i.getParcelableExtra("newEvent"));
}
}
It works great so far, but if you do have comments/concerns about this, please tell me!
Thank you!
If I recall cporrectly the Notepad project which is included in the android sdk and is also part of the tutorials online is a good examaple which should satisfy your needs.
To borrow from MV-* (Model-View-something or other) patterns, separate your idea of the Model (in this case, your Event objects) and what is displaying them (the View, or in your case an Activity) and it'll become more clear.
If you have your events somewhere global where all activities can interact with them, then you can work with the model and display the model from wherever and however you choose.
One simple suggestion is have a class (EventController or something like that) that allows you to interact with the Events collection, and make it available through a derived Application class. I can explain further if that doesn't make sense. I have a pattern I use in my Android apps whereby all Activity classes have access to a custom global Application instance, so my model is a model and can be accessed by whatever Activities I want to have access.
This is merely one approach, and as always, there are many that may suit your needs.
One possibility would be:
The ListActivity gets all the data each time it is resumed and updates the ListView accordingly
The NewEventActivity does all the job of storing the Event and simply finishes
You can improve it a bit more:
The ListActivity gets all the data when it starts
The ListActivity starts the NewEventActivity expecting a OK/CANCELLED result
The NewEventActivity does all the job of storing the Event and returns a result saying OK or CANCELLED
Depending on the result it gets from the NewEventActivity, ListActivity reloads its data or not