iOS controllers data sharing vs Android activities data sharing - android

I'm developing a native app for iOS and Android and i noticed something different that intrigued me. This is not an issue or a bug, maybe only a different behaviour on different platforms, but i'd like to understand why and if i'm missing something.
Let's suppose there are 2 Android activities:
Activity1 starts Activity2 and using intents bundle assign its model to Activity2 model
The same for iOS controllers:
Controller1 starts Controller2 and using segues assign its model to Controller2 model
When i modify the model in Activity2 and go back to activity1, the model is not updated so i have to notify this change (using broadcast, delegates or other..). The same is not for iOS because when i go back to Controller1 the model is already updated.
Why this happen? Are iOS controllers working on the same model instance while Android activities make a clone?

On iOS you pass the object by reference to the new VC. So if you change a property of that object in the second VC, that change is visible to the first VC because it is the same object.
On Android when you pass objects via a Bundle they are serialized and deserialized which can create a new object, thus the change is not visible in the original Activity. When passing Parcelable data between fragments they can be passed by reference and the change is visible in the original Fragment.
EDIT:
In Java/Android objects are passed by value, not by reference, thus when you assign a new object into a variable the old one is not changed in the original fragment. But if you change its internal state (e.g. property/field), then this is reflected in the original fragment.

Check your IOS code, you will find one method with name "viewWillAppear" on first controller, so this method will update changes which you have made on previous screen.
Same thing you can apply in Android by using method "onResume()", so implement this method and write your update task from "onCreate()" method to "onResume()" method.
In both IOS and Android, the main method "ViewDidLoad()" and "onCreate()" calls only once when activity or controller starts, then they will notify by "viewWillAppear" and "onResume" method.
Check this will help you.

The difference you notice is due to the two differents programming language used.
In Android you are using Java, and in Java nothing is passed by reference, everything is passed by value. Object references are passed by value.
Additionally Strings are immutable in Java, so if you are passing a String to Activity2 using intents bundle, and you modify it in Activity 2, the system allocate a new String in a different memory address.
See this answer about Java parameter passing.
Hope this helps

Related

How do you pass the MethodChannel Result to a new Activity?

fellow Flutter enthusiasts, pros, and future friends. I've been really banging my head from trying to pass the MethodChannel.Result from the MainActivity to a new activity (to handle the result handler after performing some work there).
In iOS, I've stuffed the FlutterResult into a struct with other pertinent values and passed that into a new ViewController, and have been successfully running the result handler from there.
How do I go about doing so in Android? Since the result isn't serializable I can't add it as an extra in an intent.
In my MainActivity, I'm running 'setMethodCallHandler', and in the proper call.method case, I'm creating a new intent and starting it. I'm successful adding in and pulling out String values in the new activity but it's that Flutter Result that I'm needing to pass over.
What is the recommended way to achieve this? Am I going about it the wrong way?
I ask if I'm doing it incorrectly because when I finish() this new activity, there is a half-second black screen that takes over the screen when the activity is dismissed.
Not sure if it matters, but I'm writing in Kotlin. I would be happy to hear any Java recommendations though.
Thank you all in advance.
Without a little bit more context about what exactly you're doing in the new activity, it's a little bit hard to tell why you'd be getting a black screen. Theoretically, the flutter activity should still be running and should show up when you finish the new activity - unless you're doing something blocking on the UI thread.
However, for passing the result - what you want to be doing is to keep a reference to the result handler wherever you're receiving the message from flutter, and making use of android's startActivityForResult method. See the android docs on getting a result from an activity. Your 'worker' activity should do whatever it needs to do, then pass the result back by calling setResult before finish. The data you pass back must be serializable.
There is a slight added wrinkle - you're not necessarily working with your own activity here (if you're writing a plugin anyways). If that's the case, you'll need to implement ActivityResultListener and call registrar.addActivityResultListener in your plugin's registerWith function. If you're just doing this in an app, you can simply override onActivityResult - just make sure to call super or you might break other flutter plugins.
There is another possible solution to this, with various levels of hacky-ness depending on how in-depth you want to be. The solution is to simply use a Singleton or Global to store what you need between activities. For anyone out there who's reading this - I don't endorse doing this, I'm just providing an alternative. There are caveats to go with this - among them is that globals and to a lesser extent singletons are seen to be a bad idea for many reasons, among them code maintainability. If you absolutely must go down this route, I suggest using a Registry pattern rather than a simple singleton - i.e. you create a key that is serializable and store the Result in essentially a global/singleton map using the key, pass the key to the new activity, then in the new activity retrieve the value with that key (and make sure to remove the object from the map).
Note that the global/singleton/registry option won't work properly if the app is stopped by android as the activity could be recreated from its intent, but the object in memory may not persist. Then again - the flutter callback won't persist anyways so that point might be moot anyways.
If you're still seeing the black screen after finishing the new activity, that sounds more like a bug or something to do with the implementation of your new activity than a flutter problem.

How can I pass a specific instance (i.e. not serialized/deserialized) of an object to the new activity I'm starting?

Title pretty much says it all. I need to pass a listener object defined in one activity to the new activity I'm starting. You can't use serialization for obvious reasons (you'd be notifying the clone, not the original) but I'm not sure how to either send over the object to the new activity, or get the new activity from the old one.
Only solution I've seen so far is to set a static on the new activity, then when the new activity starts up, grab it from the static. It just feels 'icky' to me, although if you simply set the static, then launch the new activity, you shouldn't run into stateful bugs.
The other is to use local notifications, passing along a notification key, which can be serialized since it's just a key, then set up listeners for it, but that seems to be like driving an 18-wheel semi to the store just to get some milk.
I just keep thinking there has to be a better way. Is there?
Store it in a singleton or via some injection method like Dagger. You cannot pass an instance via Intent- since an Activity could thoeretically be started by any other process, there's no way to pass instances between two activities in the Intent.

Pass data to activity android

Good day.I have an question to which i could not find an answer.I want to pass an data to an activity but i must say that i do not want to use intents as it is not aplicable to my situation.The situation is the next.Imagine an builder class which builds ui colors by specified beforehand colors.As soon as 3rd party developer done building the builder,i must start an activity with the values that the developer input in the builder.The issue is that i have lets say 10 activities,and all the activities must access that single color variable.For that purpose,the intents is hard to get done as it is not better idea to pas single variable over and over and over to each activity,i have though about inheritance,like have an base class for all activities and all of them will inherit from single class,but the issue part is that whenever i have an setter and getter inside the base class,and as soon as the developer set the according color,and i have called the setter method from the base class and started according activity,the activity will just never get the variable,it always 0,which means the variable is not set..But how it can be?
Is there any way to achieve what i want?

Better way to retain/pass data between activities

I am making an Android app using the Parse SDK. What I am struggling with is the flow of creating a post. Currently, in my main activity, a user selects the type of post (photo, video, etc.) takes a photo/video and goes to the next activity called NewActivity. In this activity, a user can review the photo/video and edit the privacy or place of the post. to change the privacy or place launches a new activity for each.
The main problem I'm having is retaining and passing this Post object between the activities.
My first (bad) solution was just to pass the data with the intent in a Bundle, but this soon got very messy as I really needed to pass a Post object between the activities. I switched from that solution to using a Singleton class called, DataHolder.
In each activity, I call DataHolder.getInstance() and when the create post button is clicked, I create a new Post object by executing: DataHolder.getInstance().setPost(new Post()). In the following activities, as the user enters more information about a post, I set the Post's properties.
This was all working well until I ran into this issue. When I would return to my app (presumably it had been killed) I would get a NullPointerException because the Post object was null. I was looking through the Android docs on passing data between activites/services and needed a little help.
Should I be using the Singleton class pattern here? What would be the most efficient and easiest way to pass this Post object between the activities? Should I use an application singleton? I would use Parcelable or Serializable, but the Postobject is a ParseObject so this is not an option. Should I avoid passing the data altogether by using Fragments for the privacy and place activities (though they have different screens and different action bars)? Should I use startActivityForResult for the privacy and place activities?
You should consider that the app could be killed at any moment for any reason and be prepared for this. You could use something like a session object to communicate between activities. You can save it / load it as often as needed so you will not run the risk of loosing data. If you cannot serialize the actual object (eg the ParseObject) you could serialize the parts needed in order to reconstruct it (ie save the image in a temp folder and load it on demand).

Pass parameter by reference using intent

Using itent.putExtra makes a copy of my object. So changes make on this object on the activity that recive this itent does no reflect on others activity.
In my case will be good have reference to this object instead a copy, this is possible ?
ps: I know i can use onActivityResult to retrive the changes make on the object, but in my case the changes make on the object need to be done before the end of the activity.
Other way is: set a reference to a common property from activity1 (I am using MyApplication). The activity2 knows where to find that reference via a getter and it will use it. Decide if you want to modify the properties in activity2, when finished / every time you can have the reference in activity1.
This way is not needed to serialize / deserialize the object either. ( performance improvement too)
You can just store a reference to the object in a static member variable, like this:
public class Globals {
public static MyObject myObject;
}
Now, in the code that has the object, you just do:
Globals.myObject = object;
and in the new activity, you can get it like this:
doSomethingWith(Globals.myObject);
Now, having said that, you need to be aware of the following:
Android can kill your process if your application is in the background pretty much any time it wants to. When the user then returns to your application, Android will create a new process for your application and then it will recreate only the activity that was on the top of the activity stack (ie: the one that was showing). In that case, the newly created activity will not be able to get the iobject by accesing Globals.myObject because the process has been newly created and that member variable is null.
You should use an Application class, which you can get a reference to using the getApplicationContext() method.
Bottom line, create an Application class, which you will be able to reference from any class in your App, then you can reference a variable that is local to that class.
Here is a good SO question about this:
Using the Android Application class to persist data

Categories

Resources