I would like to know - are there ways to access android resources and/or assets files (or files from any other folder) outside of an Activity (without passing context)?
Can't access without context:
getResources().getIdentifier("resource_name", "drawable", getPackageName());
getAssets().open("file_in_assets_folder_name");
Throws Exception if not in Activity:
try {
Class class = R.drawable.class;
Field field = class.getField("resource_name");
Integer i = new Integer(field.getInt(null));
} catch (Exception e) {}
Also tried the below, but it complains file doesn't exist (doing something wrong here?):
URL url = new URL("file:///android_asset/file_name.ext");
InputSource source = new InputSource(url.openStream());
//exception looks like so 04-10 00:40:43.382: W/System.err(5547): java.io.FileNotFoundException: /android_asset/InfoItems.xml (No such file or directory)
If the folders are included in the Project Build Path, you can use ClassLoader access files under them outside the android.content.Context, for instance, from a POJO (in case if you don't want to pass a reference of android.content.Context):
String file = "res/raw/test.txt";
InputStream in = this.getClass().getClassLoader().getResourceAsStream(file);
The res folder is included into Project Build Path by default by all Android SDK version so far.
The assets folder was included into Project Build Path by default before Android SDK r14.
To add folders into Project Build Path, right click your project -- Build Path -- Configure Build Path, add your folder (for example, assets if using later SDK version) as a Source folder in build path.
Check out the similar question I answered before at here.
Android framework when compile your app create static class call:
your.namespace.project.R
you can statically call this class like:
your.namespace.project.R.string.my_prop
this.context.findViewById(your.namespace.project.R.id.my_id_prop);
Maybe you can access dynamic resources this way:
Resources res = this.context.getResources();
int id = res.getIdentifier("bar"+Integer.toString(i+1), "id", this.context.getPackageName());
Related
I am trying to use the android TensorFlow demo TF classify app code to change training data. I want to use two flowers instead just like in this demo: https://medium.com/#daj/creating-an-image-classifier-on-android-using-tensorflow-part-3-215d61cb5fcd
the problem is according to the tutorial im following it says that there should be a assets folder generated and i can put my training data in there and then re-build.
But when i built the tensorflow android demo there was no assets folder created in bazel-bin or in android src folder. i also did a search for assets folder and nothing.
I am using the docker container outlined in the article.
You have to create assets folder by yourself.
If you are using Android Studio, then select menu from
File -> New... -> Folder -> Assets Folder and then paste the files to that folder.
FYI, you also have to create libs folder (in project level) and jniLibs folder.
UPDATE:
After putting those graph file(.pb) and label file (.txt) in that Assets folder, you have to specify and load them from your code.
For example, assuming that your graph file name is "my_graph.pb" and label file is
"my_labels.txt", then specify them as :
private static final String MODEL_FILE = "file:///android_asset/my_graph.pb";
private static final String LABEL_FILE ="file:///android_asset/my_labels.txt";
and you can load them when initializing:
classifier = TensorFlowImageClassifier.create(
getAssets(),
MODEL_FILE,
LABEL_FILE,
IMAGE_SIZE,
IMAGE_MEAN,
IMAGE_STD,
INPUT_NAME,
OUTPUT_NAME);
} catch (final Exception e) {
throw new RuntimeException("Error initializing TensorFlow!", e);
}
Of course don't forget to define other constants (IMAGE_SIZE, IMAGE_MEAN, etc..) with appropriate values before initializing.
UPDATE 2
FYI, here's sample project's app structure in android studio:
I'm trying to load dynamically external classes using DexClassLoader, like #Shlublu proposes here
When I execute my application and the DexClassLoader object try to find the class, it throws a ClassNotFound exception. I have added read and write permissions in the manifest.xml, so it is not the mistake.
I think the problem is the method that I use to make the .jar that I want to load on my application. So I have some questions...
What is the correct method to convert a .java file to .jar using dx
tool?
It is necessary that the package where the external class is loaded be the same that the package of my .jar file? (I think no)
I'm using an Android emulator API 19 (kit-kat)
Since APK is the standard Android package, my suggestion is that you use an APK instead of a JAR. Build an application APK linking the needed JAR (let the Android build tools "dex" the JAR) but without any activity, then install the APK as if it was a normal app. You can then access the APK file itself using the PackageManager to get its path and load it using DexClassLoader.
public static ClassLoader loadAPK(final Context context, final String appName) throws PackageManager.NameNotFoundException {
final String apkPath = context.getPackageManager().getApplicationInfo(appName, 0).sourceDir;
final File tmpDir = context.getDir("tmp", 0);
return new DexClassLoader(apkPath, tmpDir.getAbsolutePath(), null, context.getClassLoader());
}
How can I access a text file in my directory 'src/test/resources'
I can't seem to get it to pickup during my JUnit test
mobile/build.gradle:
sourceSets {
test {
java {
srcDirs = [ 'src/test/java' ]
}
resources {
srcDirs = [ 'src/test/resources' ]
}
}
}
Test method:
#Test
public void test_file() {
URL resource = getClass().getResource("file_four_lines.txt");
File file = new File(resource.getFile()); // Get NullPointerException here
...
}
Prefix the file path with /.
Basically, you'd do something like this:
File helloBleprintJson = new File(
getClass().getResource("/helloBlueprint.json").getPath());
Above snippet is taken from here.
I think this link will help. In your case why not hard code strings for testing? Why not use String.xml instead of "file_four_lines.txt". Internationalization requires a directory structure for each resource file having different language, screen size, orientation, flavor, night/day vision version. For this reason resources are compiled and accessed from the R file. You are trying to bypass this convention by using .txt instead of .xml and accessing the resource directly, it just feels wrong. I don't think testing is you problem as much as not following convention.
Forgive me for posting twice, I do have an answer from the official documentation" Arbitrary files to save in their raw form. To open these resources with a raw InputStream, call Resources.openRawResource() with the resource ID, which is R.raw.filename.
However, if you need access to original file names and file hierarchy, you might consider saving some resources in the assets/ directory (instead of res/raw/). Files in assets/ are not given a resource ID, so you can read them only using AssetManager." Json and txt are non-standard(unsupported) so you have to provide your own implementation/parcer to read this type file. Thanks for this post. I knew something about resources but thanks to your prodding now I know even more. To recap The Android resource system keeps track of all non-code assets associated with an application. The Android SDK tools compile your application's resources into the application binary at build time. To use a resource, you must install it correctly in the source tree (inside your project's res/ directory) and build your application. As part of the build process, the SDK tools generate symbols for each resource, which you can use in your application code to access the resources and of course the symbols referred to are in the generated R file
I am using PowerMockRunner to run my unit tests. I want to load some canned network response json files from my assets folder.
I am using this method to try to get the file.
private static File getFileFromPath(Object obj, String fileName) {
ClassLoader classLoader = obj.getClass().getClassLoader();
URL resource = classLoader.getResource(fileName);
return new File(resource.getPath());
}
I call the method like this from my class which has these annotations at the top.
#RunWith(PowerMockRunner.class)
#PrepareForTest(Network.class)
File file = getFileFromPath(this, "mock_response.json");
However, when I evaluate this expression.
classLoader.getResource(".");
It shows that I am currently in this the directory below while running this test.
/Users/tylerpfaff/Library/Android/sdk/platforms/android-23/data/res/
Seeing as I'm in the platforms resource directory, there is no hope of me successfully loading my resources from my project's resource directory. What do I need to do to access my resource directory of my project?
You have two options:
try to get system classloader via ClassLoader.getSystemClassLoader()
Get classloader from the class that has been ignored by PowerMock. By default:
"org.hamcrest.", "java.",
"javax.accessibility.", "sun.", "org.junit.", "org.testng.",
"junit.", "org.pitest.", "org.powermock.modules.junit4.common.internal.",
"org.powermock.modules.junit3.internal.PowerMockJUnit3RunnerDelegate",
"org.powermock.core*", "org.jacoco.agent.rt.*"
Or you may use #PowerMockIgnore.
I'm developing an android library project that should read from an xml file in its raw resources (let's call it xml_file_name.myextension).
What I do is basically creating a jar file of the library project including these folders:
src
gen
lib
res/raw
and referencing it as a library in a test app. This is the code that I use (inside the library project) in order to get the xml file:
int xml_res_id = -1;
for (Field f : R.raw.class.getFields()) {
System.out.println("Raw resource found: " + f.getName());
if (f.getName().equalsIgnoreCase("xml_file_name"))
xml_res_id = f.getInt(null);
}
if(xml_res_id != -1){
System.out.println("xml_file_id: " + xml_res_id);
InputStream is = context.getResources().openRawResource(xml_res_id);
// Decode xml file with SAXParser..
}
(I have the app context because the app explicitly passes it to the library project.)
What happens is that when I launch the test app (and call the method that reads the xml file) I get this error:
It seems that the xml file is actually in the right folder, because:
1) The for loop actually prints "Raw resource found: xml_file_name.myextension" and "xml_file_id: 2130968576"
2) If I put a file named "xml_file_name.myextension" in the res/raw folder of the app, it does not compile, and the error is: "Error generating final archive: Found duplicate file for APK: res/raw/xml_file_name.myextension". This basically gives me the proof that the
file is correctly "imported" from the library project.
Please Note:
I also tried in this other way
InputStream is = context.getResources().openRawResource(R.raw.xml_file_name);
getting the same error.
I honestly don't understand what could be the problem.. what am I doing wrong?
Edit:
for anyone interested in this issue:
I finally realized that this is not possible, basically because when I try to get a resource through context.anymethod I refer to the R file of the app, so I can't give the resource ID got from the R file of my library project.
It will compile, because the library project jar file contains the resource (R.raw.xml_file), but the call to context.something will always give null as a result because it refers to the app R file, that does not have that particular resource in it.
I finally had to put my xml file in the res/raw folder of the app, and access the xml_file raw resource in this way:
int xml_id = context.getResources().getIdentifier("xml_file_name", "raw", context.getPackageName());
// Getting input stream from xml file
InputStream is = context.getResources().openRawResource(xml_id);
I have actually done this with success - the library object should be within the app context. However, it only works with Activity and no other type that I have found. Using the same library with a FragmentActivity fails with NoClassDefFoundError.
EDIT****
It may work with a FragmentActivity within the same root namespace as the library. I was accessing from a different root namespace.
END EDIT****
I have a library project that references an xml file:
InputStream is = context.getResources().openRawResource(R.raw.application_table_defs);
when I call the library method that executes the previous line I have to pass in a context:
Context context = this.getContext();
The key is fully qualifying the getResource to context.getResources()... that was injected.