I'm working on a Android application and using this nice class to load a resource file, located in the applications res/raw folder, as a Java String:
public class ResourceReader {
public static String resourceToString(Context context, int id) {
try {
Resources res = context.getResources();
InputStream in_s = res.openRawResource(id);
byte[] b = new byte[in_s.available()];
in_s.read(b);
return new String(b);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
}
The context is the Activity based application class, the id is found using R.raw.mytext. The resource is a file, created in the mentioned folder.
When used in the app, it is no problem to get the file's content as a string with this line:
String content = ResourceReader.resourceToString(this, R.raw.mytext);
As the resources I read are likely to be used in other applications, I would like to put not only the classes, but also the resources into an external JAR file.
In eclipse I can create an android jar file, complete with resources and associated R class. The integer values associated with the names are accessible as expected, but how do I read the content?
I need to get the resources of the library, not those of the application.
The resourceToString method needs a context:
Resources res = context.getResources();
The Question is: is there a library context? And how do I get this context? - Or any other method to access the content of a library resource?
You can create an Android library. The output shall be an arr file which includes the classes and resources.
You may check Create an Android library for details.
The following is an excerpt from that page:
An Android library is structurally the same as an Android app module. It can include everything needed to build an app, including source code, resource files, and an Android manifest. However, instead of compiling into an APK that runs on a device, an Android library compiles into an Android Archive (AAR) file that you can use as a dependency for an Android app module. Unlike JAR files, AAR files can contain Android resources and a manifest file, which allows you to bundle in shared resources like layouts and drawables in addition to Java classes and methods.
A library module is useful in the following situations:
When you're building multiple apps that use some of the same components, such as activities, services, or UI layouts.
When you're building an app that exists in multiple APK variations, such as a free and paid version and you need the same core components in both.
In either case, simply move the files you want to reuse into a library module then add the library as a dependency for each app module.
Related
I have a desktop application that produces resource / data files for my android app. These are XML text files that store instances of my custom data class. These objects are serialized using the Simple XML Serialization library. In my android app, I'd like to instantiate objects from this XML serialization class.
I like to add these xml files to Android Studio so they are included in the APK on device install and are placed, for example, in the private app directory "files", to which getFilesDir() is mapped. I can't find a way to do that.
If I add these xml files to the Android XML resource folder, I need to use Android's XML resource parser, and can not use the Simple XML library.
Any tips? I feel I made a wrong design choice seeing how restrictive the resource bundling is.
Thanks, Kind regards,
Harmen
As per CommonsWare's comment: the solution was adding it to the raw resource folder, then you can access it using:
InputStream xmlExerciseInputStream = getResources().openRawResource(R.raw.myresource);
MyClass myClass = serializer.read(MyClass.class, xmlExerciseInputStream);
I am currently working on an Android project with multiple source sets.
My question is concerned with string resources.
The majority of the string resources are in the main/res/values directory.
There is an alternative source set called foo which overrides some of the string resources in main/res/values. This works just fine, however there is an additional source set we can call foobar that is a slightly different version of foo.
Is there a way foobar can be configured to use the resources defined in foo/res/values instead of defaulting back to main/res/values? Despite the source sets both being slightly different, the resources between foo and foobar are to be identical so I'd only like to write them once.
Essentially in foobar if I try to get the string resource cat I want it to look in foo/res/values/string.xml as if I was making the resource reqeust in foo; and just like in foo; fallback to main/res/values if that resource isn't defined.
Is there a way that I can structure my project to have this behavior? I am limited in how much I can restructure the source sets within the project, so I understand that the problem I am presenting might go against some conventional practices.
The solution to my problem was to add the following to my application's build.gradle
android.sourceSets {
foobar.res.srcDirs = ['src/foo/res']
}
I had developed 3 applications in android where the major functionalities are the same but the UI looks different. Images and the background color of the screens are different.
NOw, i want to create a single code base from which i can generate multiple .apk files for the 3 apps.
I tried creating 3 different packages for src folder for the 3 apps. But i dont know how to set the res folder for these apps.
Need pointers on creating a single code base from which we can generate multiple .apk files which includes only the respective src and res folders.
Use an Android Library Project that contains all your common code.
Create separate Android projects that reference the Library Project (you will need to copy your Manifest into each of these and make sure all components are declared with their full Java package name).
Put any resources specific to each app (drawables, colors etc) into the individual project resource folders and they will override similarly named resources in the library project at build time.
i think the best option is to use ant, you'll need to add an ant target for each build and change the resource folder.
if you use the generated build.xml, the res folder is defined like this
<property name="resource.absolute.dir" location="res" /> so you'll want to override that
Can't you put all of your common code into a library project and then just reference that project from each of the 3 unique projects that each contain the relevant resources.
Update: This answer is now obsolete when using the Gradle build system.
Why don't you use a single application, that does three different things based on SharedPreferences values set by the user, or from context at install time. If you really want to separate, you can have three different activities, and you decide which one to launch from a silent main Activity that redirects to either of the different ones.
An alternative is to have a unique activity that inflates itself dynamically from 3 different layouts at onCreate time.
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (...custom check for layout... equals(layout1)) {
setContentView(R.layout.main_layout1);
} else if (... equals(layout2)) {
setContentView(R.layout.main_layout2);
} else if (... equals(layout3)) {
setContentView(R.layout.main_layout3);
} else {
throw new IllegalStateException("Unknown layout!");
}
... your onCreate stuff....
}
It will make code maintenance easier (only one code source to modify, only one version-list and changeset to maintain)
Check here:
How to use SharedPreferences in Android to store, fetch and edit values
I would suggest using Gradle flavors.
It seems to explain all the basics really well. I just finished converting to Gradle today, and it works great. Custom app icons, names, and strings, etc.
As the website explains, part of the purpose behind this design was to make it more dynamic and more easily allow multiple APKs to be created with essentially the same code, which sounds similar what you're doing.
Also see a recent question I had, referring to your project structure and using custom code for each app.
Assume I've got 2 Application A and B.
I want to access resources (drawables, images, strings) of an B application from A application. How would I do that?
Edit:
You can also designate an Android project as a library project, which allows it to be shared with other projects that depend on it. Once an Android project is designated as a library project, it cannot be installed onto a device.
Does it mean That I can not use my library on android market?
My aim is to use default resources of Application A, but also if someone what he can download Application B and use it resources.
If you are the developer of both applications then the right approach would be, as othes noted, to create an Android library project and share it between apps.
Nevertheles, you can still access resources from another app, even if this is not your app:
Resources res = context.getPackageManager().getResourcesForApplication("com.example.foo")
If both apps are your own and you want to bundle these resources at build-time:
Create an Android Library Project, put all the needed resources into it and reference it from both your apps.
Edit to your edit:
You can use the library in the android market. You just can not use it alone (compile it). You have to build an app that uses the library. When you build that app, all the needed content gets basically grabbed from the library and copied to your apk. Which you can put on the market as usual.
This does not work when you want to access resources from an app that gets downloaded onto the device at runtime. A library project bundles all resources when you build the app that uses it. Peter Knego's response is the correct one when accessing at runtime.
It is possible if those both application are yours. Or you can used any Android Library for both these application. If you want you also create your own Android Library for this kind of work. Thnx.
Peter's answer above is great, but I'd like to elaborate a little more...
When you control appA and appB and want to get a drawable from appB, while in appA, then do the following:
Get the identifier of the drawable when in appB (for example, R.drawable.iconInAppB)
Then, in appA
Resources res = context.getPackageManager().getResourcesForApplication("com.example.appB");
Drawable d = res.getDrawable(integer);
//integer was what appB assigned to R.drawable.iconInAppB
*Note: The integer id assigned to R.drawable.iconInAppB will change over time so don't rely on hardcoding. I save the key-value pairs (String resourceName, int resourceId) in a database in appB and access them using a content provider.
For example, let's get the string-array with the ID of entryvalues_font_size from the package com.android.settings
String[] enries = null;
try {
// You can get PackageManager from the Context
Resources res = getPackageManager().getResourcesForApplication("com.android.settings");
int resId = res.getIdentifier("entryvalues_font_size", "array", "com.android.settings");
if (resId != 0) {
enries = res.getStringArray(resId);
}
}
catch (NameNotFoundException e) {
e.printStackTrace();
}
I am trying to separate an application into an app project and a library project (besides moving it from Netbeans to Eclipse). The app will contain resources that are used by the library - for this, I had read on Stackoverflow that we can bundle the resources in the library project and then override them in the app project.
But when I did this, I am getting the error:
...\res\values\attrs.xml:5: error: Attribute "pageBackground" has already been defined
Am I doing something wrong here? Any of my assumptions is faulty?
Thanks,
Rajath
I think I had similar problem when I tried to create a kind of 'configuration file' which was placed in application's resources and was meant to alter behavior of library it used. What I found working was using getIdentifier method from Resources instead of refering directly to R class:
final int resId = getResources().getIdentifier("my_resource", "raw", getPackageName());
You can then use the identifier as normal resource ID, e.g.:
if (resId > 0) {
final InputStream is = getResources().openRawResource(resId);
// ...
}
The idea was to handle both situations: when the file was present in app's resources or when it was not. But I think it should also work in your case of "overriding" the resources from library in application, thanks to getPackageName providing appropriate package name for resources' identifiers' resolving.