I have been happily refactoring code from different versions of the same app (paid/free) into Android library projects so that the actual apps can simply customize the library and reduce code duplication.
One thing I'm started to wonder is what getApplicationContext() inside the library code means? Is is the same ApplicationContext as one would get from the child apps? What happens when I access SharedPreferences from a library project's getApplicationContext() instead of the original app's getApplicationContext()? Will the SharedPreferences file be same or different?
What if I had used the activity to access SharedPreferences? Does it matter that the activity is now a library activity and not the original app? Is the SharedPreferences the same?
Thanks for clarifying.
When the APK is packaged up then all classes will be belong to the main application.
call getApplicationContext().getPackageName() and it will return the app's package name, and not the library's package.
I have the same setup for a free/paid application and no issues when I moved my classes into a library project.
However you have to check your xml files (manifest, widgets, etc.) to use the full package name of your library project.
A library project is almost like having all the code in one project. There are a couple of things to watch out for related to namespaces but generally it works very well.
e.g. Your library has its own namespace
Library package name = uk.co.lib
Main App package name = uk.co.app
Activities in the library that you want tro access from the main app have to be added to the app manifest. Activity named A in library project would be added to manifest in main app like this:
<activity android:name="uk.co.lib.A">
Accessing shared preferences etc would give the same result from either namespace and would return the preferences for the app.
There is only one application so there is only one ApplicationContext
Related
My usage scenario is a bit complicated.
In the dynamic form, I only have some views and resources. Those views should have access to those resources. In my base module, I will use these views from the activity of a basic module. Both my application and activity replace the attachBaseContext method.
But when I download and install the dynamic form, my views can not access resources using the task context. However, resources are accessible from applicationContext.
I do not understand how SplitCompat works. So the classes and resources loaded by the dynamic module connect only to applicationContext?
This problem is probably caused by an Android Studio bug. Clean the project and invalidate the cache, or build the project again.
You can take a look at how Dynamic Features are implemented in this sample.
There's sample code on how to open some resources, located in a dynamic module, from the base module.
Plus, the samples includes others dynamic modules with activities in implemented in Java/Kotlin and native.
I am creating an Android dependency library which will be packaged as an AAR file. The dependency will have layouts, strings, dimens, images etc. I created a sample demo project which includes this dependency.
Now consider the following scenario.
My library includes an Image file named filter.png and uses it inside a layout file. The demo project also has an Image named filter.png but it is a different image. So when the project gets built, only the app's filter.png is picked up. So even in my library's layout file, I am seeing the image used by the demo project.
As of now, I have changed the name and appended package name before every resource name to avoid the above scenario.
But is there any way I can force Android to pick resources only from the current module?
A library will only have access to its own set of resources, but nothing can prevent the application from intentionally overriding the library's resources.
To prevent accidental overrides, you usually prefix your library resource names. For example, AppCompat uses the abc_ prefix and the Design support library uses the design_ prefix.
Furthermore, you can explicitly declare which resources of your library are public, so that the other ones will be private by default and if the app overrides them you will get a Lint warning.
You app and library will have different package names, yes.
As of now, I have changed the name and appended package name before every resource name to avoid the above scenario
And that is correct because resources are associated by package name.
com.example.app.R.drawable.filter (Which is often just R.drawable.filter, check your import statements!), the current module.
vs some other module, com.example.library.R.drawable.filter
Android - Accessing Resources
[<package_name>.]R.<resource_type>.<resource_name>
I am developing an android app in which I have included a library project, I am able to use the resources of library project (ie layouts, styles etc) inside my main project. But I want to use the resources of my main project inside my library project. Is there any way to do that? I am stuck at this problem for quite a time.
You can create dummy resources inside your library project, and anything with the same name in the main project will override it.
Example:
LibProject/res/values/strings.xml:
<string name="greeting">Hello from Library Project</string>
MainProject/res/values/strings.xml:
<string name="greeting">Hello from App Project</string>
Then, wherever you use R.string.greeting, even in your library project, the value from the main project will be used.
From the docs:
The application itself has highest priority and its resources are
always used in preference to identical resource IDs defined in
libraries.
Is it possible to share resources across APK's? For example, can application A (in APK A) load an icon or layout view from application B (in APK B)?
You can make use of getResourcesForApplication
That way you can load whatever you want from other app package as long as you know at least the package name and the id or name of the resource to load.
As a side note, layouts cannot be loaded without further processing them with an XMLResourceParser because of possible id mismatches between your app package and the "guest" package.
Two different apps can share resources - images/ files,etc. if they are signed with same certificate.
Please check android doc here
Only if it is delivered by content provider and the content serialized.
You can have two applications use the same Android library, which lets you share resources like activities, etc.
An Android library project is a
development project that holds shared
Android source code and resources.
Other Android application projects can
reference the library project and, at
build time, include its compiled
sources in their .apk files. Multiple
application projects can reference the
same library project and any single
application project can reference
multiple library projects.
I have an abstract Activity in an Android library (AbstractActivity) that is supposed to be used in other applications as the base Activity.
Since this Activity isn't supposed to be used directly, it isn't declared in the library AndroidManifest.xml file (the real reason is because the Activity is declared as abstract) and so I can't declare it in the applications AndroidManifest.xml file.
The real problem is that when I create an application that uses the library, two .apk files get deployed to the device, Library.apk and Application.apk, and when the Application.apk is started it closes with the following message in LogCat:
ERROR/AndroidRuntime(4709): java.lang.RuntimeException: Unable to instantiate activity ComponentInfo{foo.bar/foo.bar.ApplicationActivity}: java.lang.ClassNotFoundException: foo.bar.ApplicationActivity in loader dalvik.system.PathClassLoader#44bec098
Can I reference an abstract Activity that is declared in a library and use it as the base for an Activity in a project that references this library?
Deploying separate APKs is probably not want you want. The APKs live in different sandboxes and cannot access each other.
If you want to reuse code, create an Android library project (in Eclipse, open properties of your library project, select Android and check "Is Library" under the library section.
Then, reference the library by clicking "Add" under the library section in the projects that use this library.
You end up with a single APK then.
The best (and correct) way to do this is to use the solution #Michael has suggested. However, for completeness, I thought I'd offer another solution that would work with the current setup of two apk files if for some reason you want to avoid making the one apk a library. Also note that this won't work if the activity that subclasses the AbstractActivity is loaded first, this will only work if the subclass is instantiated or called from another Activity in the same application.
In another Activity you can instantiate a PathClassLoader like so
PathClassLoader loader = new PathClassLoader("/data/data/com.yourlibrarypackage.apk", PathClassLoader.getSystemClassLoader());
And then use it to load the class you want
loader.loadClass("com.yourpackage.YourAbstractActivity")
The loadClass method returns a Class<T> object which you can ignore because it has the side-effect of making it available to other classes sharing the same memory space. That call is akin to Class.forName().