Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android How to handle multiple instances data/identities and JNI

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?
like image 940
Jan Bergström Avatar asked Dec 16 '15 05:12

Jan Bergström


People also ask

How do I run multiple instances of an app?

Open Two Instances Of An App Using 2Accounts On Android Enter 2Accounts, that lets you do the exact same thing as the Parallel Space app. Grab the app from the official Google Play Store and install it on your device. Open the app, choose the app you'd like to run multiple instances of, and tap on Enable at the bottom.

Can I run two instances of Android studio?

Go to: File -> Settings -> Appearance & Behavior -> System Settings -> Project Opening. Check [x] "Confirm window to open project in". Now open the other (2nd) project with File -> Open... etc. You will now be asked if you want to open a new window or replace what you already have.

How does JNI work on Android?

It defines a way for the bytecode that Android compiles from managed code (written in the Java or Kotlin programming languages) to interact with native code (written in C/C++). JNI is vendor-neutral, has support for loading code from dynamic shared libraries, and while cumbersome at times is reasonably efficient.


2 Answers

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.

like image 186
Arsen Vartbaronov Avatar answered Oct 09 '22 09:10

Arsen Vartbaronov


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?

like image 44
Jan Bergström Avatar answered Oct 09 '22 09:10

Jan Bergström