This is a question of good practice and a smart solution, I need an advice.
I have an app that (and as far as I can read here in Stackoverflow and by Google search):
The app handles kind of documents and I like it possible to
handle more than one document at the same time. (I am used to Win32 where there is a program segment and one segment of data for each instance but that is obviously not the case in Android/Java.)
I see one instance starting the app from the app storage (the tablet) another opening a Gmail or email with an appended document file, a third instance by opening a file from a File handling app like ES file explorer. And I like them all be possible to be flipped in between. The user might like to read more than one document at a time. (correct me if I use the word instance wrong in the Android/Java environment)
The app is built in a JNI section that contains all the data and logics and a Java Android user interface. (The JNI section is designed to be OS independent for implementations in different OS, has a glue c-file.)
The Android section recreates every time the screen is flipped or instances are flipped between
There is only one JNI instance and that is kept even when the Android Java part is recreated and all Java data is wiped out, right now it shows the last read file in all cases flipping in-between pushing the running app button
There are no problems making different instances within the JNI section as long as it is possible to bind them to each Java instance, with an identity or something that I can use as a parameter in the interchange with the JNI section, but how?
I can't save for instance the FilePathName in each instance to identify the instance in the Java section because it will be wiped when the Java section is recreated.
First question is if I am right in my observations reading Stackoverflow and Googled articles?
Second question, any good suggestions in solving the issue? I need an advice
Is there a possibility to identify the instance in all situations as long it is alive?
Any other possible paths, both to the general issue of separating data for each instance or identifying the instances for the JNI to handle the data for each instance?
Jan
We have similar problems with JNI objects in our application. The problem is that JNI link isn't work as ordinary Java object and has to be relesed explicitly. At the same time we have activity that can be destroyed at any moment by Android.
Our current solution is to store JNI objects on Application level with posibility to manage refereces and drop objects as soon as reference is zero. And also destroyed JNI reference if activity is going to be destroyed forever. So this is similar like you did in previous post.
However if you would like to have your application scalable after some time you might understand that this solution isn't ideal.
The first thing that Android system sometimes temprorary destroys activity to save memory. In your case all JNI objects with documents will still consume memory. So the best solution here is to be able documents on JNI level saves its state to bundle. This is especually important if your documents can be changed by user. In that case by saving state of JNI object in onSaveInstanceState you can destroy your JNI object and recreate in onCreate. However here it is important to analize how much time is required to destroy/create JNI object with saved to bundle document as we have to support quickly activity recreation in some case (portrait/landscape mode for example) with some limited bundle (not more 1Mb). In case of long process this solution might be not good.
Also as you would like to have one task - one document system. You should consider case when you have several activities in one task.
The second item that Android isn't call onDestroy() always. And if you do some save operation here data might be lost sometimes.
Hope this information helps you.
I made something working but I don't know if it is good practice?
I am getting an int-instance-tag from JNI and tagging it on the intent by
public void onCreate(Bundle savedInstanceState) {
....
if (savedInstanceState == null) {
// Creating the JNI task and get the JNI task ID
int iInstance = initProgram(...);
// and store the JNI task ID in the intent
getIntent().putExtra(Intent.EXTRA_TEXT, iInstance);
...
}
...
public void onResume() {
super.onResume();
if (JniManagement.resumeInstance(iTask)) {
...
public void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
// Restore state members from saved instance
iTask =
savedInstanceState.getInt(AndroidApp.STATE_TASK_ID);
}
Then we are talking about the lifespan of a task, the user is flip/flopping between windows/tasks with the home button. The issue is to synchronise the JNI data with the task of Java.
Re-appearing in th else section of if (savedInstanceState == null) { we get the JNI task ID from the intent and synchronise the JNI task with it.
And onDestroy() with if(isFinishing()) freeing the instance set of memory in the JNI.
#Override
public void onDestroy() {
super.onDestroy(); // Always call the superclass
if(isFinishing())
Commands.destroyInstance(getIntent().getExtras().getInt(Intent.EXTRA_TEXT, 0));
// Extinguishing the JNI task started during onCreate()
}
The JNI-side
In the JNI-side all memory used by an instance will be put together in a structure. This structure could be pointed at, in an array of pointers to get the right set of data for the right instance integer. The pointer array is realloced when new instances are created and can go on as long there is memory left for a new instance.
This works actually pretty good, always getting the right data to the right activity/instance. And using a File Manager app starting one activity after another by calling work data files, there will be a stack of activities/instances. When the user is leaving them with the end button are pealed off one by one and its memory is extinguished real smooth. Open a file in a Gmail works fine too the same way, however appears as a different activity by the activity button.
As an old Win32 C-fox I love my pointers and set them in all the methods/functions this feels a bit clumsy (only handle the active window screen data). But the Android OS do not have active overlapping windows.
So just synchronising the JNI this way to the right Java activity/instance is simply working real smooth.
But is it good practice? Are there any other smooth and good looking solutions?
Related
I am mostly a beginner to android development, and I find myself using a lot of global variables to share data between functions within the same activity, Intra-activity communication . This is mostly because no one calls onCreate () from within the activity, so I can't return UI elements and data that might be edited latter in the activity.
In addition for inter-activity communication I find myself using Intent extras for small data and external classes with static variables to pass large data, image strings, around when an activity dies. I read here that the application context can also be used to maintain global variables,so this might be a solution, however this keeps the variable for Intra-activity communication alive even after it dies, which is unnecessary. In addition some of that data passed may not be needed all the time for all the activities.
That seems like poor practice, so my questions :
1)For inter-activity communication is a constant use of intent extras and static variables to pass data ok?
2) For Intra-activity communication what can I use instead of global variables to pass data between different functions that don't call each other but share some value and the value dies with the activity ? Is there a danger to such use of global variables ?
If this is too opinionated or abstract I'll close it.
1) Usage of intent is ok. As for global variables I do not think so. The values can be lost when your application would be recreated after android system decides to free some memory. Why not persist data in SharedPreferences or SQLite?
2) Fields (and classes) variable is a normal way to use (and pretty good practice for the cases like not using findViewById all the time). If you want to persist data between activity recreation why not to use provided by android framework (https://developer.android.com/training/basics/activity-lifecycle/recreating.html)?
Save the needed data (like item ids, values, etc) in bundle and restore them afterwards.
public void onSaveInstanceState(Bundle savedInstanceState) {
savedInstance.putInt(some_key,value);
}
and restore in onCreate or onRestoreInstanceState.
So, I'm trying to make something like an rpg for the android to practice programming. I have a hero object which I'm trying to pass using parcelable as recommended by others, but I'm not sure how to pass it back.
In one activity, I'll have
myIntent.putExtra("heroData", hero);
And then, in myIntent, the activity started in the original activity, I'll have
hero = (Protag) getIntent().getParcelableExtra("heroData");
note: Protag is the class of the hero object
So, the first activity does successfully pass the object to the second activity, but such that the second activity doesn't affect the object in the first activity. Like, if something happens to the object in the first activity, it'll preserve to the second activity, but if something happens to the object in the second activity, the object in the first activity is still the same.
How would I make an object that can be changed by any activity such that the changes are preserved through other activities?
you are now dealing with concurrency. Since you have 2 'activities' possibly acting upon a single 'data'. However, Parcelable is a serialization technique, which means that you will lose reference once you pass a parcelable object(via parcelable). which means that you can't use a parcelable object as a central point of synchronization (both updating it with data).
If you will ONLY EVER plan on having a single object of your class, then you can make the object have static values. Otherwise this is the wrong mechanism to do this.
An AIDL one-way ascync service that notifies each thread of changes to a 'registered' object's values, is viable. (AIDL one-way is actually not hard to write, just takes some practice) Here is a project I wrote that makes use of it, to show both sync and async service usage. (My PhD Adviser's REPO for the MOOC he teaches)
Update to explain why I say this is 'concurrency'.
First of all I take a 'wide breadth' approach to what is 'concurrent' vs what you might be thinking. Your working definition of 'concurrent' is a valid one. However, it is somewhat limited in scope compared to what I'm thinking about. (usually doesn't matter, but the nuance of Android's lifecycle actually makes it important)
Android Activities have 6 life-cycle states they could possibly be in.
Created
Started (Visible)
Resumed (Visible)
Paused (partially visible)
Stopped (hidden)
Destroyed
Now here is where the issue of concurrency comes up.... When you have 2 or more Activities that are not in the 'Destroyed' state.
Plus there are a lot of things that add unpredictability to your logic that you have to think out very carefully...
Android's non-deterministic behavior.. User could press power/home/back or some other button, a phone call comes in/AMBER Alert takes priority over the phone, and/or the Garbage Collector "magic divine/unholy ritualistically" decides who lives or dies (exaggerating, but you get the point).
But lets assume that A doesn't get killed (which is actually the 'problem' scenario here).
So A makes an X object (hero or whatever) and passes by value (parcelable+intent) to B the value of X. At this time, the value(and reference) of X is in A. but the value of X is in B. Therefore, we are already in concurrency. Because the life-cycles of A and B overlap. Not just the "visible" portions of the life-cycles. So this means... where do you put the logic on "when to pass back the value of X"? Do you pass it back on onPause()? (but how? an intent wouldn't work if the User presses the back button)
Short answer: There isn't a 'great' way to do this. (at least with only Activities and Intents/Parcelables.)
You need some concurrency mechanism in place that allows the changes to X in A to propagate to change the values of X in B. (And this needs to be done reliably, correctly, and efficiently.)
The base goals of concurrent programming include correctness, performance and robustness. (from WIKI:Concurrency(CS) )
Ideally you wouldn't pass the data by value, but instead by reference, and when one class updated X (be it A or B) there only ever existed one value of X. That way when A or B was re-started it would have a 'valid' value of X. But you can't do this 'nicely' through parcelable data.
Therefore I would use a service to be the authoritative keeper of the 'value of X', any time A or B wants to update X, then they have to go through synchronized methods to get/set X. (I've never really ran into this scenario where two activities want to have the same 'live data' like this, so perhaps there is a better solution, possibly making use of handlers(but I can't think of it offhand)) With a service you will have slight time delays from when A is telling Service that X is updated to when B can get that info. but its the best I can think of off the top of my head right now.
Also the SQLite DB is designed to promote data storage like this, and has built in support for monitors to block access to the DB when another thread is accessing it. (there is nuance here I won't get into, such as 'setLockingEnabled(boolean)')
Make it static on the top class
All the activity can call it. Like
MyObject hero = topActivity.Hero
but but but
I'm not sure at all it is the correct way or the best way to do it. So maybe wait for other response
Sincerely
A possibility is:
From Activity1 launch the Activity2 using the method startActivityForResult(). In the Activity2 you will do all the modification needed to the object "hero" and then you can put it in an intent and send it back using setResult (int resultCode, Intent data). This way, when Activity1 is resumed, using onActivityResult(int requestCode, int resultCode, Intent data), you will be able to catch the object "hero" modified.
Here you can find more information on this mechanism.
http://developer.android.com/training/basics/intents/result.html
You could write object data in shared prefs. That way there is no need for a service. You need to save the progress of the game anyway. I think changes like that should be saved in memory once the app closes the progress is back to where it was.
Edit:
Or you could save in Internal Storage. Save the Protag object as a file.
It all depends how often the object changes.
Tip: You should not be writing every time you make a change to the object. Save the data in some data structure and then when everything is finalized such as the level ends or something then you write in storage or shared prefs. That way you keep it efficient otherwise all that writing in storage will slow the app down.
For quite some time I've had troubles passing variables from one Activity to another, and I've usually had to resolve to some pretty ugly Static-class-hacks to make it work.
Generally something along the lines of a static method that I call with the type of the Activity, along with the variables the Activity requires. These gets stored in a static variable, and retrieved in the constructor of said activity.
Like I said, pretty ugly. And there's no such thing as "myActivity.StartActivity(new Activity);". All of the overloads for StartActivity takes either an Intent, or a typeof(MyOtherActivity).
So my question is, have I completely misunderstood the concept of Activities, or am I simply missing a completely obvious way to pass arguments to them?
#Edit: The reason I want to pass an actual reference to an object, instead of simply a copy of the object, is because I'm trying to pass a View Model from an overlying Activity, down to the new Activity. And of course any changes made to this view model, should be reflected on the parent activity, which will only be possible if the the two activy's viewmodels points to the same instance.
I'm writing the app using Xamarin.Android, but the code is nearly identical between C# and Java, so answers in either those languages is fine.
The problem is that Android can kill the process hosting your app at any time (if it is in the background). When the user then returns to your app, Android will create a new process to host your app and will recreate the Activity at the top of the stack. In order to do this, Android keeps a "serialized" version of the Intent so that it can recreate the Intent to pass it to the Activity. This is why all "extras" in an Intent need to be Parcelable or Serializable.
This is also why you cannot pass a reference to an object. When Android recreates the process, none of these objects will exist anymore.
Another point to consider is that different activities may run in different processes. Even activities from the same application may be in different processes (if the manifest specifies this). Since object references don't work across process boundaries, this is another reason why you cannot pass a reference to an object in an Intent.
You can also use The Application class to store objects globally and retrieve them:
using Android.Runtime;
namespace SomeName
{
[Application]
public class App : Application
{
public string Name { get; set;}
public App (IntPtr javaReference, JniHandleOwnership transfer) : base(javaReference, transfer)
{
}
public override void OnCreate ()
{
base.OnCreate ();
Name = "";
}
}
}
And you can access the data with:
App application = (App)Application.Context;
application.Name = "something";
I choose to do this on the Application calss because this class is called on the App startup so you don't have to initiate it manually.
Keep in mind that variables which are scoped to the Application have their lifetime scoped to the application by extension.
This class will be Garbage Collected if the Android feels it is necessary so you have to modify the code to include this case also.
You can use SharedPreferences or a Database to save your variables in case they get deleted and retrieve them from the App class for faster results.
Don't be overly wasteful in how you use this approach though, as attaching too much information on this class it can lead to a degradation in performance. Only add information that you know will be needed by different parts of the application, and where the cost of retrieving that information exceeds the cost of storing it as an application variable.
Investigate which information you need to hold as application wide state, and what information can simply be retrieved straight from your database. There are cost implications for both and you need to ensure you get the balance right.
And don't forget to release resources as needed on OnStop and OnDestroy
I rarely use intents, i find this way better.
I'm falling into a bit of a dilemma. As I learn more and more about Android and Java, the more confused I am about the state of the building blocks of Android apps. (i.e. Activity, Service, Broadcast Recievers, Content Providers)
Since all of those building blocks are just Java classes, it's tough for me to wrap my head around them because there can be multiple instances of them. As of late the biggest challenge is with tracking which instance of the Activity is actually being created, started, resumed, etc;. I started playing around with Intent flags, and that just threw another wrench (or ten) into the equation.
Being able to tell their state would be indispensable and even better would be to see the current task stack/process id that the activity is associated with. At this point I'm just guessing whether or not FLAG_ACTIVITY_NEW_TASK, FLAG_ACTIVITY_CLEAR_TOP and FLAG_ACTIVITY_SINGLE_TOP are working properly.
Surely there is a solution. Is there any debugging tool that I can use to get an inside view of my app/process to see which components (specifically Activities) are in existence?
Some notes/thoughts I've had:
Should I create a unique static auto-increment int for each class to try and track it myself?
Is this what I want Get current visible activity to user?
Does this application manually keep track or is it really peaking inside of the process? https://play.google.com/store/apps/details?id=com.novoda.demos.activitylaunchmode
There has to be a debugging tool for this... -__-
Not sure if this will solve your understanding of the topic completely, but these guys did a nice app to try and visually see the main launch modes available for Activities > https://play.google.com/store/apps/details?id=com.novoda.demos.activitylaunchmode&hl=en_GB
Hope this helps in some way to explain things! :-)
I have an android application and in one of my activities I am making a call to get say "Customers", this call is made to an external API, when I get the response I get it as a JSON object. The problem i am having is that I have a ListView in the activity and when you click on of its items it shows you the details but then when you hit the back button I have to make the call again to populate it. In Samsung Galaxy 4S it seems to keep the data of the list view but in the HTC android incredible it's blank. So what I did is, make it rebind OnResume(), this fixed the issues for both BUT the consequence is making another call to that server. When its 10 or 100 customers it doesnt matter but I know that there are some accounts that have up to 5000 and I am sure it will crash.
What are my options to improve performance on this issue with Android?, I tried a static variable but at some point that object got cleared too.
How do Android applications usually handle this cases where the data is retrieved from API's and they need to be stored through out the application and there is no need to make another call for the same information?, I was thinking on static object but i want to make sure I do this the right way.
You have a couple of options.
1) You can cache the data in memory. For example you can make a static cache or cache the data within the Activity or the App object. If you are doing this in only one view and if it is not a lot of data, this might be an ok solution. However, if you have to do this for many activities and there is a lot of data that has to be cached, you might want to go for option 2. Also storing data in memory in android, does not mean it won't be garbage collected (in some cases, even if you have a reference to it.)
2) You can cache the data in the internal storage and refresh it from time to time.
You can find more info about the internal storage and how to use it here: http://developer.android.com/guide/topics/data/data-storage.html#filesInternal
Basically, you store the response within the internal storage under a specific identifier. The next time you open the activity, you check if the storage has data for that identifier and if yes, you read it and display it. If no, you make the API call.
Keep in mind, that you will have to refresh the cache from time to time.
I had the problem with ListViews on my application too. What I did is that I wrote a custom adapter and that solved the issue..
However the thing you can do is to make a global variable and save the returned results to it. When your application wants to call the server, check the variable, if it's null make the call, if it's not then just draw the ListView with the already fetched data..
Keep in my mind, to implement a refresh button, you need to skip the check.