I'm making an android library and I want to run some initialization code when the application starts.
In some cases, it might be a little difficult for the developer(using my library) to implement a custom application class. AFAIK, the ContenProvider codes start before application starts and does not need any custom implementation done by the developer using my library.
The question is, Can I use ContentProvider to run code at Application's start up?
I simply create a provider class:
class ExampleProvider : ContentProvider() {
override fun onCreate(): Boolean {
// run code at startup and do initialization
return true
}
...
// Ignore other methods and return null or 0
}
And add the manifest tag.
And it will run before the application starts up. (Without the need of Custom Application class) But will it always behave like this and run code before app starts? Is there any case that ContentProviders will not launch at app startup?
TL; DR
How an android library can run code at application startup, without asking developers to implement a custom Application class?
Recently Android has provided a startup library to initialize components at application startup. If you see the source code of that library, you will see they use ContentProvider to start the library at startup.
Related
I have been trying to imlement in my app a way to run some task when app is "closed" or "breaked", I have created a BroadcastReceiver to do this, but I have notice something that could be logical. In my Broadcast receiver I am using classes from my shared project or PCL, but when app is breaked I have noticed that the only class that still exists is the BroadcastReceiver one, so when I do call a class that is in my shared project in my broadcast it gives me an error, I have conclude this beacuse when my app hasn't been breaked the execution to call the classes of the shared project is OK, but when breaked... not,
I have two questions for this problem:
1) Is my theory correct?
2) If is correct (or not) how can I call from my BroadcastReceiver classes that are in my shared project when the app is breaked?
Here is some sample of my code:
//Android
override void OnReceive(...)//BroadcastReceiver main method
{
...
MyClass myCls = new MyClass();//Class from shared project
}
When I execute this when app is still in use everything of but when is breaker then the app stops and shows me the following typical android pop up:
“MyAplication.Drioid has stopped”
Do you want to let your app restart again after the app is closed? If yes,for android, you can try to use service to achieve this.
When the service is in the background, you can try to restart it by using a BroadcastReceiver which will receive a signal when someone or something kills the service, its role is to restart the service.
For more details, you can refer to: https://fabcirablog.weebly.com/blog/creating-a-never-ending-background-service-in-android
Note:Even though it's Java code, it's easy to understand and convert.
For xamarin Form, because each platform has their own way and rules for background services. You have to make services for each platform.
You can refer to this document: Xamarin Background Tasks
I have a problem with altbeacon library. I am preparing a small library in which one module scanns beacons in background and foreground. I have found sample app in one library on Github and I have tested their code (application class) and everything is ok. After user goes to the task switcher and swipes an app off the screen, scanning is being continued in background.
But I am creating a library so I can't paste my code inside Application class. Insted of this I need to do something like this: MyLibrary.init(this) inside onCreate method in ApplicationClass. So I wrote a BeaconService class with exactly the same code like in application class. I have passed to this class application context (I checked that I have inside my BeaconService application context by debugging my code). After that when app is not killed by swapping off from task switcher evrything works perfectly. After killing the app I got exit from region event and I am not able to continue scanning even if the beacon is about 20 cm far from device.
I created an issue on altbeacon Github (you can find my sample code and logs here) and I got an answer that library is not design for my requirements. Moreover if I have further questions how to resolve my problem I should ask about that on stackoverflow.
So I have an idea that maybe I can use WorkManager and re-schedule scanning beacon worker (OneTimeWork) again and again. This may be a way around the delay limits of scheduling background tasking which is introduced from Android 8+.
Belowe sample code:
class BeaconWorker(appCtx: Context, workerParameters: WorkerParameters) : CoroutineWorker(appCtx, workerParameters) {
override val coroutineContext: CoroutineDispatcher
get() = Dispatchers.Default
override suspend fun doWork() = supervisorScope {
// rescheduling worker
if(isActive) {
enqueNextWork()
}
// make scan (This could be only one scan with list of found beacons)
val beacons = makeScan()
Result.success()
}
}
How to achieve this using altbeacon library?
I think you are making this too hard.
The Android Beacon Library is designed to scan for beacons in the background and auto restart itself after the app is killed to scan for beacons. It does this all automatically out of the box with no need for you to create any wrapping services or work managers. Such wrappers are likely to make things more complicated and cause unexpected side-effects.
The above also works if you are making your own library that wraps the Android Beacon Library, provided that the library's AndroidManifest.xml entries are merged into your library's AndroidManifest.xml. This will expose a number of internal Android Beacon Library services in the manifest, including StartupBroadcastReceiver, BeaconService, and ScanJob. Those three services are needed to accomplish the functions in the first paragraph.
If you have done the above, the only other thing you need to do is to provide some code hook to set up your beacon monitoring/ranging at application startup. This can simply be a POJO method call inside your library like new MyLibraryManager().start(Context context); (You will likely have to pass a Context object as this is needed to create the Android Beacon Library's BeaconManager.)
For automatic scanning restart after the app is killed, the above hook must somehow be executed when the application starts back up. (The library auto restarts is services described above, but you still need to make calls to tell the library whether to start scanning and with what settings.)
The easiest solution is to instruct the developers using your library to put the call to the hook desribed above (e.g. new MyLibraryManager().start(Context context);) inside their own custom Application#onCreate() method. You might be able to figure out some other clever solution with a BroadcastReceiver that does not require this.
TLDR: I am developing an application which runs in multiple processes. For the purposes of UI testing, I want to inject a fake API dependency to make the app running under tests independent of network interactions, however, this doesn't seem to work in the multi-process setting.
I am using the approach described in this post, so I implemented a custom AndroidJUnitRunner which instantiates the application with mock dependencies (let it be MockApplication) instead of the one with real dependencies (let it be RealApplication). It does work and my app queries the fake API interface from the main process.
My app, however, uses multiple processes, e.g. there is a data processing Service which runs in its own process and which only starts on startService invocation from the application code. For some reason, this process runs with the instance of RealApplication, without any mock dependencies.
Is there any way I could make it work? I tried digging into Android code responsible for application instantiation, but haven't really found anything particular useful yet.
P.S. I am using Dagger 2 for DI, but this is probably not really relevant.
The problem is that your custom application class does not override real one in the AndroidManifest.xml.
You're just telling the instrumentation test runner to run your custom application class but then if app starts another process, Android Framework won't even know that it needs to run your custom application class instead of real one.
So, I'd suggest you to override the application class to the custom one in AndroidManifest.xml during the connectedAndroid task execution, as a result your app will use custom class even without hacking the test runner and whenever new processes start.
I struggled on this problem too as I need to mock network calls emitted from a Service started in its own process.
To use a custom Application object (MockApplication) in every process of your app during your tests, a solution is to inject a build variable in your AndroidManifest.xml with the help of manifestPlaceholders.
I defined two product flavors in build.gradle:
productFlavors {
mock {
manifestPlaceholders = [application:".MockApplication"]
}
prod {
manifestPlaceholders = [application:".RealApplication"]
}
}
prod : will set the real Application object (RealApplication) in manifest
mock : will set the mock Application object (MockApplication) to mock network calls
In AndroidManifest.xml, use the variable "application" like this:
<application
android:label="#string/app_name"
android:name="${application}">
Now, when you want to use the MockApplication, just run your instrumentation test with build variant "mockDebug"
I have an android app that uses ORMLite/SQLite and I use Robolectric in conjunction with JUnit 4 to allow me to run unit tests in Android Studio and on a Jenkins build server.
Typically I would setup test data in my tests, in the setup, and then run my test scenarios against it but when I tried to do this I started getting issues and exceptions which seemed to be related to files being locked or something and that seems to be a problem others have had... so what I have done up until now is use the create database method in my database helper to create some dummy data which the tests expect to be there.
The problem is my application now needs to plug into a real database and I can't have it setup dummy data when it runs.
If there a way, within my database helper class, to detect if the code is executing on a device or within Robolectric?
This is what works well for me on Robolectric 3.
public static boolean isRoboUnitTest() {
return "robolectric".equals(Build.FINGERPRINT);
}
To start with, I'll say that you shouldn't be putting code to initialise dummy/test data in the normal releasable code and in general you shouldn't need to know from the main app if you're in a robo run or not.
Now moving past the disclaimer and to actually answer your question... One way you could to this is to have a method in your application class like this
public boolean isRoboTestRun() {
return false;
}
Then create a "TestApplication" in the test package that extends your normal application and overrides this method to return true.
It's hacky, but that's because it's not really meant to work that way :)
At some point you have to init OrmLiteSqliteOpenHelper with your Context.
Let assume you do this in your application class in onCreate. So just create Test<your application class name> in your tests sources and override onCreate with empty implementation.
Robolectric will find this class and will use during the tests. More details here.
I have an android app that uses ORMLite/SQLite and I use Robolectric in conjunction with JUnit 4 to allow me to run unit tests in Android Studio and on a Jenkins build server.
Typically I would setup test data in my tests, in the setup, and then run my test scenarios against it but when I tried to do this I started getting issues and exceptions which seemed to be related to files being locked or something and that seems to be a problem others have had... so what I have done up until now is use the create database method in my database helper to create some dummy data which the tests expect to be there.
The problem is my application now needs to plug into a real database and I can't have it setup dummy data when it runs.
If there a way, within my database helper class, to detect if the code is executing on a device or within Robolectric?
This is what works well for me on Robolectric 3.
public static boolean isRoboUnitTest() {
return "robolectric".equals(Build.FINGERPRINT);
}
To start with, I'll say that you shouldn't be putting code to initialise dummy/test data in the normal releasable code and in general you shouldn't need to know from the main app if you're in a robo run or not.
Now moving past the disclaimer and to actually answer your question... One way you could to this is to have a method in your application class like this
public boolean isRoboTestRun() {
return false;
}
Then create a "TestApplication" in the test package that extends your normal application and overrides this method to return true.
It's hacky, but that's because it's not really meant to work that way :)
At some point you have to init OrmLiteSqliteOpenHelper with your Context.
Let assume you do this in your application class in onCreate. So just create Test<your application class name> in your tests sources and override onCreate with empty implementation.
Robolectric will find this class and will use during the tests. More details here.