Android: static variables and moving complex data - java

If I have a class that contains a static variable, say x:
class MyClass {
static boolean x = false;
// Other methods
}
Now let us say that, hypothetically, I set x = true; from my first activity. Is there any point through the rest of my app's life cycle (including various activities and threads) where this value will simple be 'reset' back to false due to how the 'Google JVM' or the android environment works? I have heard that static variables have a 'lifetime', that dies when the program dies. Do Activities count as separate 'programs'? What about services? Or even Widgets?
I am asking this because it is often difficult to share complex data structures that rely on other complex processing (like syncing data from an online database) in android due to how 'separated' activities are, and static variables are often a very quick and dirty solution to the problem. Other things I have tried include serialisation, but that doesn't really seem like a practical solution either (constantly serialising and decoding objects when the user navigates from one activity to the next seems like it would be very resource intensive).
If I am an evil person for doing this, please tell me what I am doing wrong, or even better, give me some links or examples of better ways to solve this problem.

Yes. There are times where that will reset. Primarily if the user leaves the app and starts fiddling around with other apps or if the user lets the phone go to sleep for a long period of time. The Android process could kill the actual app. Then the "state" of the app will be restored when the user comes back, however static variables will be at their defaults because the actual process was rebuilt.
Generally passing small objects between Activities and Services is done by overriding the Parcelable interface. This will allow you to save and restore objects using setOnInstanceState methods of both Activities, Views, and some adapters. They will likewise, have a restore method in which you can rebuild the object. Parcelable is preferable over Serializable.
Larger data may require a shared file or database depending on the data that you want to have synced. There is a 1 MB size limit for parcelables being passed between Activities. One common tactic is to save the information to a file and send a URI to the location of where the information can be retrieved.

Answering your question - yes, there is a situation when you set x = true and value will be 'reset' back to false. Well, not exactly reset but consider this scenario: you have an activity and a service. Service is using separate process (you can define that in AndroidManifest when you declare your service). Then those two processes (main app and service) won't share memory and setting x to true in your activity won't affect the value of MyClass.x in your service. In all other cases changing value in one place will be visible everywhere else. Hope it helps!

No, a static variable will not be changed unless you change it or the app ends, it is safe (but generally unclean) to use it. Closing the activity the variable lives in won't hurt it.
You suggest you just need to keep track of a value as you move around activities. In that case you can add the value in your Intents as what is called an 'extra'. If you need to also pass back the value after, android also has the startActivityForResult feature
Intent extras example:
x below could be any type of value including any object which implements Parcelable
Intent intent = new Intent(...);
intent.putExtra("myKey", x);
startActivity(intent);
in receiving class:
x = getIntent().getBooleanExtra("myKey");
Edit:
Given your additional comment - "lists of objects that contain yet more lists of objects" you may get a Parcel too large exception when trying to use extras, but this is an indication you have a bigger architectural problem and that there may be a better approach

Use Gson.
Gson is a Java library that can be used to convert Java Objects into their JSON representation. It can also be used to convert a JSON string to an equivalent Java object. Gson can work with arbitrary Java objects including pre-existing objects that you do not have source-code of.
You have two options. Convert to string , then put data in an intent then pass to activity. Or Convert to string with gson, save to a preference, then in the other activity, check if the preference is alive and read from it.
If you wish to be bold, you can persist to database preferably using Realm for Android or ObjectBox is a new mobile object database optimized for performance. With ObjectBox, we are bringing technology from NoSQL server databases to mobile.

Related

How to pass a serializableExtra from different android applications?

I'm trying to send a SerializableExtra from an application to another one.
I use
resultIntent.putExtra("thing", fc);
and in the receive application :
Thing theThing = (Thing) data.getSerializableExtra("thing");
But since the applications doesn't have the same names I got the following error:
Java.lang.RuntimeException: Parcelable encountered ClassNotFoundException reading a Serializable object (name = com.test.senderapp.Thing)
And I can't modify the sender application , I need to find a way to make it works only controlling the application that receive the intent.
Thank you
Use Content Providers to achieve this.
https://developer.android.com/guide/topics/providers/content-providers.
We were discussing this issue into something pretty similar; we wanted that a keyboard could share data with another app and use it with a combination of other features.
The goal is that you define which data to expose and other apps can use that similar to what the Contact's app does; which you can access a CursorLoader to fetch all of the user's contacts.
On the other hand, as a second solution, you can make your second app receive a String and send the object as a JSON; but I'd rather prefer the first one if you're going to keep adding more objects or summing up other applications.

Accessing an Array/Collection of Custom Objects from All Activities, Android

I'm a just diving head first into Android Studio and am working on my first app which is a sort of surfing log application. Basically it is to keep track of various weather conditions each time the user goes out surfing.
I have created a Java class "Session" with the following fields:
Date (Date)
Location (String)
Tide height (float)
Surf size (float)
more to come, keeping it simple for now.
My application will flow as follows:
There will be a Main home screen activity, with buttons, and also a small tableview that displays your 3 most recent sessions.
Buttons including:
New Session: this takes you to a new activity with various text inputs for each of the above fields, a date selector... and a save button.
My Sessions: this will take you to a tableview where you can view all of your past sessions. You can organize them by location, date, surf size...
Thus my question:
What is the best practice to pass all this data between the various activities?
To me the most obvious way to go about this is to have a central ArrayList that gets loaded in the main activity and then this gets somehow passed around to all of the subsequent activities. It contains all the sessions that you have ever created.
So lets say I tap the "new session" button on the main screen. This takes me to the new Session activity. I enter all the fields and hit save. I would like to take this data, create a new session object and then add this to the array back in Main Activity. So far my research tells me to pass all this data back using a bundle and the intent.putextra() technique. However it seems cumbersome. Is there not a better approach where I could just create a new object of my Session class and then append it to the central array?
Again let's say I tap the 'my sessions' button from the main activity. I would like this to load up a new activity which is a tableview that allows the user to scroll through all of their previously created sessions and tap on one to view the details.
I've done a bit of research and it seems there are various ways of going about this, I've read up a bit on Singletons, I've looked into creating some sort of static class that I could then reference from multiple activities, I've read about parcelable and serializable...
Perhaps though someone with some android experience could shed some light on the most efficient and standard way of accomplishing what I would like to do.
Again I want to reiterate that this Array or collection of "Sessions" is going to be the center of the app. Pretty much every activity I implement down the road is going to be using this data in someway or another. Whether it's displaying it a tableview which can be sorted in different ways, to running statistical analysis on it, to displaying pins on a map of each location...
I think you want to keep your data in a database and use a pub/sub workflow to keep track of it.
For example, you can use Firebase. Everytime a part of your application does an update (even a different user on a different device) any other part of your code can listen to that change and capture it.
Firebase is just an example, RethinkDB, MongoDB all have this option.
It is not a good option to use a data structure that is on your app: it will become really messy if it needs to be shared between different parts of your app, and impossible if you need other users to be aware of the change.
I think you should go for an event-based library like RxJava2. you can easily subscribe to a bus (subject) which emits all data created up till now.to keep other app's components up-to-date.
for you specefic use case. there is sth great in RXjava2 is called Replay Subject
Replay Subject:
It emits all the items of the source Observable, regardless of when the subscriber subscribes
a simple implementation would look like
public class RxReplayBus {
private static ReplaySubject<Object> subject = ReplaySubject.create();
private RxReplayBus() {
// hidden constructor
}
public static Disposable subscribe(#NonNull Consumer<Object> action) {
return subject.subscribe(action);
}
public static void publish(#NonNull Object message) {
subject.onNext(message);
}
}
from your component subscribe :
disposable = RxReplayBus.subscribe(new Consumer<Object>() {
#Override
public void accept(Object o) throws Exception {
}
});
and unsubscribe using :
disposable.dispose();

Send data between activities

I'm new in Java & Android Studio. I need to send data between activities. But
I have 3 activities. A -> B -> C
I want to send a data from A to C directly without write anything in B.
Hope you understood. Have a nice day and thanks.
It depends on what type of data you want to pass.
The first way is to use static global variable. You are able to pass any type you want, but this way is fragile as the object that you are passing is saved in memory (not disk). It can lead to memory leaks.
The second way is to use SharedPreferences. With this, your data will be saved on disk.

Android: Performance when calling Json file data multiple times from different classes

I'm working for my first time with Json files as data for my app, and I have been thinking about how is the best option to save a json file to make it accessible from different classes.
It is easy, I have a JSON file with different rated for currency conversions. I need to convert the data that I show in different currencies in different modules of my app continually.
So I just want to know a good way to store my json data and not load my Json file every time that I need to check a currency rate and find a way to do it more simple, maybe as a hashmap in my BaseActivity which is extended by the rest of my activities and just call it, or a static class with all the methods related with currency rates. I also thought about save it in a sharedPreferences.
It just a question for check the opinion of more people about the best way looking for app performance to continually call data from Json files.
I am not a financial expert but as far as I know currency conversion rates are applied on a daily basis. Also I have not worked on Android but the answer below is more problem-specific rather than technology specific and hence I assume that you would be able to map this to Android primitives.
I would hence design my strategy for maintaining the currency conversion rates as below:
Fetch the currency conversion rates the first time the app starts. Process this data and store it in memory within a HashMap for the lifetime of the app. Also, place this data into a more permanent store (e.g. SharedPreferences).
Refresh this data periodically using a service that runs once every
24 hours fetch the updated data. Process the fetched data in a
manner similar to above.
Notify the app that the currency rates have been refreshed. In case
the app is running it can referesh it's memory caches.
As about the class design - the hash map storing the currency exchange rates should be stored in a separate class say CurrencyConversionRateCache. This class exposes all method required for your activity classes to fetch conversion rates. The class also gets notified from the background service (possibly using Intents in Android) when new currency conversion rates have been downloaded. This way the cache itself is responsible for ensuring the validity of it's data keeping activity classes simple.
Hope this gives you some headstart towards solving your problem.

Since when is the phone charging/discharging

I wanted to learn more about the Android Services / Broadcasts, so I started a simple project, to create a battery monitoring app. It turned out pretty good, I'm using it for a few days now, but I want to add a new function: to show since when is the phone charging/discharging.
First I thought that I would create two static fields in my BoradcastReciever extension class, where I get and publish the data about the battery, one for the actual state (charging/discharging), and one for the time, when the change in state happened. This way, I could just subtract from the current time the last change, and know exactly since when is the phone charging/discharging.
But there is a problem with this solution: It won't show the correct data at first, when a user starts the app. I wouldn't make a big deal of it, but I saw that Android tracks this data somewhere, because inside my phone settings I found this information, so why take the hard way.
So my question is: is there an easy way to get from the Android system the date/time (no matter what format) of the last charging state change?
I looked at the BatteryManager reference but there are no constants named after what I seek, and which I could use, to get the information from the Intent of my receiver.
The Android OS tracks the connect/disconnect of a power source, but does not make this data accessible to apps. You have to record this all yourself, using intent filters.
The two intent filters to use are android.intent.action.ACTION_POWER_CONNECTED and android.intent.action.ACTION_POWER_DISCONNECTED; with these, you can monitor when the power source is connected and disconnected.
You can find information about this process explained incredibly clearly here. Another blog describing the process can be found here.

Categories

Resources