Share single instance between classes in Kotlin - android

I'm working with a 3rd party SDK in a Flutter plugin (Kotlin), and need to instantiate a particular class once, so I can share the state with various different instances of Method- and Event Channels.
I have several classes that expose 'features' as event channels, and they all use the same instance of a callback from the SDK.
For visual reference:
com.company.example
-- Feature1StreamHandler
-- Feature2StreamHandler
-- Feature3MethodHandler
-- Featuer4MethodHandler
Each one of these handler implementations, require a scan instance, which needs to be configured once, when the application starts up and then dispose of it, when the application closes.
Coming from C#, I'd implement a contract, create a concrete implementation and initialise the class during the application bootstrap stage, startup, however, a similar 'pattern' in Android does not seem to work, as I kind of expect the bootstrap to be the MainActivity, however, data is then not passed on to the Flutter plugin portion.
I'm hoping my explanation makes sense...
Something like this:
In MainActivity, construct SDKScan object.
In the Flutter plugin, for argument sake, MyPlugin, I want that instance of SDKScan created in MainActivity.

Related

Sending data from an activity to an object on a 3rd party activity

In the course of creating an android library, I've learned I need to be able to open an activity from a generic library object and have the activity pass back data to the the library object. Normally, I would simply use startActivityForResult and call it a day, but in this case the library object will be using the client application's context. As such, any result would be sent to the client application and not to the library object.
So the flow would be something like this: Client instantiates our library object -> the library object determines it needs to present its own activity and does so -> library's activity returns data to the library object which can continue processing
I've tried a couple of different solutions but none seem to produce the desired results.
fragments - the issue I ran into here is that the fragment is tied to an activity which means it would need to somehow be tied to the client's activity in order for our object to get what it needs. So for our purposes this doesn't make sense to use.
Temporary splash screen - this is the route we're currently leaning towards since a basic splash screen would allow us to leverage our object on an activity we owned which could then call the activities it may need along the way and then return a response to the client's app in the activityForResult. The drawback of this design is that we were hoping to leverage a set of events which the client could code to when we fire them off. However this can be worked around if needed.
Also looked into leveraging the sharedPreferences but the issue there would be that when we returned to the client's activity we'd somehow need to "kick" the library to continue working. We don't want our clients to have to make multiple calls into our library. And spinning off a background thread to "poll" feels like very bad practice in this situation.
So what I'm looking for is whether the 2nd approach is really the only way to solve this or if there is another way in android development which I'm currently unaware of?

Grant control of Activity UI in SDK

Currently we're making an Android library that contains an Activity. We want to control the exact flow and the state of the activity, but give the user that implements the library control what the UI looks like. Meanwhile, we want to expose the least amount of internal classes.
The SDK user may decide where views are placed, sizes, colors; we decide on what happens on onClicks and provide the texts of TextViews.
The activity makes use of a Model-View-Intent pattern, so we want to expose the immutable state. Without adjustable UI, the Activity and all its' classes are internal. With adjustable UI, a lot more classes have to made public. This increases the risk of breaking changes on updates and exposes our logic.
To expose the UI, several solution were thought of:
Having a static callback on the activity that calls onCreate(), so setContentView() can be set, and calls render(state: State) on every state change. Our classes are shielded as we like, but using a static for this is questionable.
Make the Activity open, so sdk users can subclass it. This means that every class used by the activity, has to be changed from internal to public.The classes which actually should be internal, will be hidden by obfuscating them with ProGuard.
It would be the nicest to pass a function in the Intent, which to my knowlegde is not possible.
Pass a POJO were we define parameters such as background color, which is the most restricting to the sdk user and is not in consideration.
Which solution is the best? Is there another method than the ones we thought of?
The SDK user may decide where views are placed, sizes, colors; we decide on what happens on onClicks and provide the texts of TextViews.
I picture this like so:
Your consumer receives a State, a ViewGroup, and an Actions object, which I'll explain later.
Based on State the consumer is required to create several views and place them as they wish within supplied ViewGroup.
The consumer is also required to register above views using some Actions.register*Button methods.
The above logic is executed inside one callback method. Once said method finished your SDK will verify correctness (all required actions are assigned a clickable view) and proceed.
Now, how to pass this callback method to sour SDK?
1.
It would be the nicest to pass a function in the Intent
This is actually possible with relative ease (and, IMO, some severe drawbacks).
In your SDK create a static Map<Key, Callback> sCallbacks. When your consumer registers the callback using your API, you'll generate a lookup key for it and store it within the map. You can pass the key around as an Intent extra. Once your SDK activity is opened it can lookup the callback using the key from its intent.
The key can be a String or UUID or whatever fits your needs and can be put inside an intent.
Pros:
It's deceptively easy to implement and use.
The consumer can use your SDK from just one file. All the calling code is in one place.
Cons:
You're not in charge where the callback is created. The consumer may create it as an anonymous class inside an Activity, which results in a memory leak.
You lose the callback map when process dies. If the app is killed while in your SDK activity you need to gracefully handle it when the app is restarted.
Variables are not shared across multiple processes. If your SDK activity and the calling code are not in the same process, your SDK activity will not be able to find the callback. Remember that the consumer is free to change process for their activities and even override your own activity process.
The calling point would look something like startSdk(context) { state, parent, actions -> /* ... */ }.
This is by far the most comfortable method for the consumer, yet the weaknesses start to show once you leave the area of a typical consumer setup.
2.
Make the Activity open, so sdk users can subclass it.
As you explained this is not possible without making compromies on your end.
Pros: ?
Cons:
The consumer needs to register their subclass and unregister your original SDK activity in AndroidManifest.xml. I'm assuming the manifest merger is enabled. This is a pain, as I often forget to look here.
The consumer gets easy access to your activity and is free to break it as they please.
Unless your documentation is pristine, the consumer will have a hard time figuring out what to override in your activity.
The calling point would look something like startSdk<MySdkActivity>(context).
I really don't understand the benefits of this option, as a consumer. I lose the benefits of #1 and gain nothing in return. As a developer I can't sanction this 'let the consumer deal with it' attitude. They will break things, you'll get bug reports and you will have to handle it eventually.
3.
Here I'll try to expand on the idea mentioned first in comments.
The callback would an abstract class defined by your SDK. It would be used as follows:
The consumer extends this class and defines the callback body. The class needs to have an empty constructor and be static. Typically it would be defined in its own file.
The class name is passed in an intent to your SDK activity.
Your SDK activity reflectively creates an instance of the callback.
The callback class could have several methods, one could set up menu, one could setup only view hierarchy, one would get the whole activity as parameter. The consumer would pick the one they need. Again, this needs to be documented well if there are multiple options.
Pros:
You separate the callback from the call site (where your SDK is called from). This is good, because the callback is executed inside your activity, completely separated from calling code.
As a result you can't leak the calling activity.
The consumer doesn't need to touch AndroidManifest.xml. This is great because registering your callback has nothing to do with Android. The manifest is mainly for things that the system interacts with.
The callback is easily recreated after process death. It has no constructor parameters and it's stateless.
It works across multiple processes. If, by any chance, the consumer needs to communicate across processes they're in charge of how they achieve that. Your SDK is not making it impossible as in case #2.
You get to keep your classes internal.
Cons:
You have to bundle a proguard rule to keep the empty constructor of each class extending the abstract callback class. You also need to keep their class names.
I'm assuming you'll hide the intent passing as an implementation detail so the entry point could look something like startSdk<MyCallback>(context).
I like this one because it shifts all possible responsibilities from the consumer to you, the SDK developer. You make it hard for the consumer to use the API wrong. You shield the consumer from potential errors.
Now back to the first paragraph. As long as the consumer can get their hands on a context (ViewGroup.getContext()) they're able to access the activity and the application (in that process). If both the calling activity and your SDK activity live in the same process the consumer could even access their prepared Dagger component. But they don't get to override your activity methods in unexpected ways.

how can I send a List into another activity in Android Studio

I know that I can add a string or an integer by putting putextra() on my Intent but what do I do if I have to send a List?
For example, My main activity contains a list, I have a different activity that adds an item into the list and I have a third activity that needs to show the whole list
Your object can also implement Parcelable interface. Then you can use Bundle.putParcelable() method and pass your object between activities within intent.
Photostream application uses this approach and may be used as a reference http://code.google.com/p/apps-for-android/
Source: google "pass objects between activities android" :)
By making the Activity the central focus of the Android API, both in the API documentation and in most of their examples, Google has encouraged inexperienced developers to treat Activities as the sole constructs in an Android application. And, unfortunately, most of the widely available literature and over-simplified code examples available on the web perpetuate this.
However, good software design, regardless of platform or programming language, would suggest that you use the concept of a data 'model' - a class that contains the data that is important to your application, as well as methods that operate on that data. This class should be independent of any user-interface-related classes.
Activities are essentially a mash-up of Views and Controllers from the point of view of the popular Model-View-Controller (a.k.a. MVC) design pattern.
You should strive to remove the management of your data from the Activities, and put it elsewhere, in a non-Android class. Then make that class available to the Activities that need it, instead of simply passing data from Activity to Activity.
Where to put this model class? There are a number of ways to do it, including, but not limited to:
Make it a member of your Application class (subclass Application if you haven't already) - this is simple and convenient, but only reasonable for very small applications - it quickly gets out of hand
Make it stand-alone, but make all of the data members and methods static - again, simple and convenient, but only for a very small amount of data
Use a dependency injection library (e.g. Dagger), make it a Singleton, and inject into the Activities that need it.

Android - Determine App Launches and Total Time as Top Activity

I am working on a solution or code that can be embedded inside of an Android APK to track how many times the app has been launched and how long the app has ran for. I know one way to do this is using the ActivityLifecycleMethods in API 14 and in lower versions of Android having code placed in all Activity Lifecycle events or by providing a base Activity class.
1) Is there a way to hook the ActivityLifecycleMethods without the developer having to make any changes to their code outside of dropping additional code into their App?
I believe this answer is no because even with an Enum Singleton it is not loaded until it is referenced. Also the Enum Singleton will go away once the activity is changed since a different class loader is used when activities change.
If I wanted to keep the Enum Singleton around would it be possible to store a reference to the applicationContext and thus it wouldn't be removed when the Activity changes? Is that what google means by
"There is normally no need to subclass Application. In most situation, static singletons can provide the same functionality in a more modular way. If your singleton needs a global context (for example to register broadcast receivers), the function to retrieve it can be given a Context which internally uses Context.getApplicationContext() when first constructing the singleton." on http://developer.android.com/reference/android/app/Application.html
2) I am not a fan of this solution for older API versions. It seems very likely developers could forget to modify their Activity Lifecycle methods or forget to inherit from the created BaseActivity. Are there any other unique solutions for these older platforms? Is there any other approaches that can be done to determine when an activity isn't running? Could any of the following work:
a) User a class loader to ensure the base activity with the proper metrics are always used
b) Implement some type of heart beat. Will a timer stop working if the app is paused or killed? Is there some other way? Could the ActivityManager be used?
You have many Analytic Agents like Flurry to do that.
When ever you want to track an event, you will add it to flurry and inturn it syncs with server after specific time.
You may use the same logic.
Better create a library file with following features:
Start Application
End Application and report time to db.
Track a specific event count and update to db.
Sync the data to server you like to.
Call appropriate events from your app.

How can Android source code not have a main method and still run?

I've seen this in a few tutorials now... but how in the world can Android source code not have a main method and still run.
For example (from http://developer.android.com/guide/tutorials/hello-world.html):
public class HelloAndroid extends Activity {
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
}
That runs but there is no main!!!
I've also thought that using things like onCreate (or formLoad, etc.) was bad becuase a constructor should do that work and such built-in methods can be smelly sometimes. But onCreate is an entry point? Even without a main?
What if there is more than one activity... is there a hierarchy to these built in event handlers? OnCreate trumps everything else? Otherwise, how would the app know what to run or where to enter the program?
Thanks!
Each application will be having it's own Virtual Machine. To run an app, within it's space (VM), must have a main method.
Activities are not the actual classes to be invoked for start of application. There is a class called Application, which will be the root class for an application to be launched.
If there is no main method, how can a VM recognize how to start an app?
Framework has classes called Process, VMRuntime which are responsible for starting an application. Which indeed deal with main method.
For better understanding, study the Zygote service of Android. deals with Applicationmanager Service, ActivityStack Activity Threadds etc.
That runs but there is no main!!!
Of course. Many things that you might think of as a Java "application" do not have their own main() method. For example, IIRC, servlets, WARs, and the like do not have main() methods -- the main() method, if there is one, is in the container.
But onCreate is an entry point?
onCreate() is a method.
What if there is more than one activity... is there a hierarchy to these built in event handlers?
Not really.
OnCreate trumps everything else?
Not really.
Otherwise, how would the app know what to run or where to enter the program?
An app does not "know what to run or where to enter the program".
An Android application is a basket of components. Some components may be tied to icons in a home screen launcher. Some components may be tied to scheduled timers, like cron jobs or Windows scheduled tasks. Some components may be tied to system events, such as when the device is placed into or removed from a car dock. Those components will be automatically created and used when appropriate (e.g., when a user taps the icon in the home screen launcher). Yet other components are only created and used when your code specifically asks for them.
Thinking of an Android application as if it were a monolithic console-mode Java program will cause you no end of trouble.
You tell it which one to run on startup in the manifest file. There isn't a main() because there doesn't have to be, main may be a convention used for "regular" java apps, but it isn't for things like browser applets. The system creates the activity object and calls methods within it, which may or may not be called main. In this case, it's not.
onCreate is different from a main, and from a constructor, in that it can be called twice on a single activity, such as if the process is killed and the user navigates back to the activity. See http://developer.android.com/reference/android/app/Activity.html#ActivityLifecycle
Actually, this type of pattern is not peculiar of Android, but happens whenever you have some framework in the middle. Some basic examples are java Applets and Servlets. Some of the answers already provide give the correct response, but I will try to elaborate a bit.
When you launch a Java app, you start a JVM and then you need to load something into it: so you need a static method (the main) because there are no objects (yet) living in the JVM that you can refer to.
If you have some sort of framework in the middle, it is the framework that will start the JVM and will start populating it with its own service objects: writing your code then means writing your own objects (which will be subclasses of given "template"). Your objects can then be injected (loaded) by the framework. The framework service objects manage the lifecycle of the injected objects by calling the lifecycle methods defined in the "template" superclass.
So for instance when you provide an applet to a browser, you do not launch a static main method: you rather only provide a subclass of java.applet.Applet that implements some instance methods which act as callback to manage the lifecycle (init, paint, stop...). It is the browser that will launch the JVM, instantiate what's needed for the launching an applet, load your applet and call it.
Similarly, with servlets you subclass the javax.servlet.http.HttpServlet class and implement some instance (non static) methods (doGet, doPost...). The Web container (e.g. Tomcat) will be in charge to launch the JVM, instantiate what's needed for launching a servlet, load your servlet and call it.
The pattern in Android is pretty much the same: what do you do is to create a subclass of android.app.Activity. When you launch an app, the system looks in the manifest to find out which activity should be started, then the "framework" loads it and calls its instance methods (onCreate, onPause, onResume...).
In Java programs we need a main() method, because while executing the byte code the JVM will search for the main() method in the class and start executing there.
In Android, the Dalvik Virtual Machine is designed to find a class which is a subclass of Activity and which is set to start the execution of the application from its onCreate() method, so there is no need of a main() method.
The order in which Dalvik Virtual Machine calls methods is based on order of priorities called android life cycle for more information on android life cycle check the link below
Android Life Cycle: https://developer.android.com/guide/components/activities/activity-lifecycle.html
While there is no specific main entry point, intent filters describe which activity is started when the application is launched.
They are controlled in AndroidManifest.xml as described here:
http://developer.android.com/guide/topics/intents/intents-filters.html
where a note pad application example is described:
This filter declares the main entry point into the Note Pad application. The standard MAIN action is an entry point that does not require any other information in the Intent (no data specification, for example), and the LAUNCHER category says that this entry point should be listed in the application launcher.
An android programmer should learn this like the back of their hands it simply explains everything and would help in the future when creating activities.
http://developer.android.com/reference/android/app/Activity.html
There is a main of sorts, it just happens to be out of your hands. After all, there's nothing special about a main function in any language. It's just the entry point where your code starts executing. The Android operating system expects applications to have a certain structure and it calls your code based on the conventions you follow.
I found this particularly useful...
http://developer.android.com/guide/topics/fundamentals.html#appcomp
Applets don't have main() methods either. It just depends on how your code is packaged.
The Android UI frame encapsulate some Java common details, you can study the source code of the android UI framework
I think that Jonathon's answer is going in the right direction. He says the OS expects a certain structure. There's a name for that structure which is a "state machine". In this case Android calls it the "activity lifecycle". Rob gives a link to the documentation which contains an important diagram of that state machine though the text is a bit dry. A quick search also found me the following link that explains it fairly clearly: http://www.android-app-market.com/android-activity-lifecycle.html
In Java, there is a main even if it isn't listed as main(). The page you get after the icon click, whatever its name, is the main().

Categories

Resources