Android accessing drawable folder - android

I placed 10 images in drawable folder and I created a custom class which instances are holding an id Integer that should refer it to a image from draw folder. Now I wonder how to set those id-s at once, not one by one. Instead:
object[0].setImage(R.drawable.image1);
object[1].setImage(R.drawable.image2);
I want to do this with loop, but how?

Drawable ids as known are generated within static classes of final class R. So just use reflection to read the values of these static attributes. If you want to get the Int ids then use this code:
for(Field f : R.drawable.class.getDeclaredFields()){
if(f.getType() == int.class){
try {
int id = f.getInt(null);
// read the image from the id
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (IllegalArgumentException e){
e.printStackTrace();
}
}
}
Or if you want to search directly by images' names, you might be interested of the name attribute of fields like :
for(Field f : R.drawable.class.getDeclaredFields()){
if(f.getType() == int.class){
try {
String name = f.getName();
// rest of the code handling file loading
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
}
}
}

Doesn't work as far as I think.
There is code to get a drawable by its name. For example: "image"+myNumber"
Maybe: how to access the drawable resources by name in android

Be aware that the size of the view's list should match with the one that holds the ids:
public class HolderIDs {
public List<Integer> _ids;
public HolderIDs() {
_ids = new ArrayList<Integer>(Arrays.asList(R.drawable.one, R.drawable.two, R.ldrawable.three, R.drawable.four));
}
public List<Integer> getIDs() {
return _ids;
}
}
//Usage
List<ImageView> views = getYourViews();
List<Integer> ids = new HolderIDs().getIDs();
for (int i = 0; i < ids.size(); i++) {
View view = views.get(i);
if (view == null) return;
int id = ids.get(i);
view.setBackgroundResource(id);
}

You can create an integer array for the resources:
int resources = [ R.drawable.image1, R.drawable.image2, ...]
And use a bucle to set the resources into your object array.

Related

List all files, recursively, in Android Dropbox API

How can I list all files, recursively in DropBox folder?
I tried code below but returns no result:
result = dbxClient.files().search("", "*");
And this returns files in path, not subfolders:
result = dbxClient.files().listFolder(path);
You can get a ListFolderBuilder from listFolderBuilder and use the withRecursive option to list out sub-items as well.
Be sure to check ListFolderResult.hasMore to see if you should call back to listFolderContinue to get more results though.
You can check this link, navigate to inner class 'FolderScanTask'. It contains working code for Android:
https://github.com/ControlX/Android-Dropbox-UploadImage-To-SpecificFolder-By-FolderSelection/blob/master/app/src/main/java/io/github/controlx/dbxdemo/MainActivity.java
This is work in progress, here I'm just making an ArrayList for parent folders, has more logic as suggested by Greg is already there you just need to fill in that.
Code Snippet for the same:
String path = "";
DbxClientV2 dbxClient = DropboxClient.getClient(ACCESS_TOKEN);
TreeMap<String, Metadata> children = new TreeMap<String, Metadata>();
try {
try {
result = dbxClient.files()
.listFolder(path);
} catch (ListFolderErrorException ex) {
ex.printStackTrace();
}
List<Metadata> list = result.getEntries();
cs = new CharSequence[list.size()];
arrayList = new ArrayList<>();
arrayList.add("/");
while (true) {
int i = 0;
for (Metadata md : result.getEntries()) {
if (md instanceof DeletedMetadata) {
children.remove(md.getPathLower());
} else {
String fileOrFolder = md.getPathLower();
children.put(fileOrFolder, md);
if(!fileOrFolder.contains("."))
arrayList.add(fileOrFolder);
}
i++;
}
if (!result.getHasMore()) break;
try {
result = dbxClient.files()
.listFolderContinue(result.getCursor());
} catch (ListFolderContinueErrorException ex) {
ex.printStackTrace();
}
}
} catch (DbxException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
Here ArrayList is just for my use wherein I'm just making a list of only folders.
So, modify accordingly.

Which type of ArrayList is used to store Drawable variables in android

In my app I want to store list of app icons in ArrayList. Here is my code from where I get the app icons images:
for(String a:array){ //array contains list of appplications package name
try{
Drawable icon=getPackageManager().getApplicationIcon(a);
}
catch (PackageManager.NameNotFoundException e){
Toast.makeText(MainActivity.this,"error",Toast.LENGTH_SHORT).show();
}
}
Here, I want to store all the app icons which is getting from icon variable into a ArrayList. But how to store all the app icon images in ArrayList because my icons are generating at run time.
So, how can I add all the Drawable icons into a ArrayList- any solution for this?
You can just create your own ArrayList<Drawable> and populate as follows:
final List<Drawable> icons = new ArrayList<Drawable>();
final PackageManager mgr = getPackageManager();
for (final String app : array) {
try {
final Drawable icon = mgr.getApplicationIcon(app);
icons.add(icon);
} catch (final PackageManager.NameNotFoundException ex) {
Toast.makeText(MainActivity.this, "error", Toast.LENGTH_SHORT).show();
}
}
/* now we have our icon Drawables in a list */
Try the code below... This way, you can store/retrieve the drawable by a key (which is the package name)
HashMap<String,Drawable> drawableList = new HashMap<String,Drawable>();
for(String a:array){ //array contains list of appplications package name
try{
Drawable icon=getPackageManager().getApplicationIcon(a);
drawableList.put(a, icon);
}
catch (PackageManager.NameNotFoundException e){
Toast.makeText(MainActivity.this,"error",Toast.LENGTH_SHORT).show();
}
}
Or, you can use ArraList and store only the drawables:
ArrayList<Drawable> drawableList = new ArrayList<Drawable>();
for(String a:array){ //array contains list of appplications package name
try{
Drawable icon=getPackageManager().getApplicationIcon(a);
drawableList.add(icon);
}
catch (PackageManager.NameNotFoundException e){
Toast.makeText(MainActivity.this,"error",Toast.LENGTH_SHORT).show();
}
}

List values in strings.xml

I would need to List all the values in strings.xml (for a given locale),
basically get a dynamic list of all the strings in an application.
My purpose here is to list all strings of all apps inside my (duely rooted) phone in order to speed up translation work.
I have no problem accessing the AssetManager of other apps :
-To get the list of all apps I use :
List<PackageInfo> packs = getPackageManager().getInstalledPackages(0);
-To access the package manager I use :
PackageManager manager = getPackageManager();
Resources mApk1Resources = manager.getResourcesForApplication(pname);
AssetManager a = mApk1Resources.getAssets();
But I am not quite sure where to go from here.
Obviously this is not for production purpose, just for helping my customer's translation team (you know Chinese OEMs...), so jackhammer-dirty solutions are welcome :-P (reflection, dynamic foreign context, live dex loading, dynamite etc...)
Thanks !
Edit 1 : I already know B.A.R.T it doesn't suit my need I need to do it on a live phone (not a zipped ROM) like a "live translation checker app". In particular, I don't have immediate access to the app's source codes, because I have to check a large number of phones, some being few years old. I can spend the time to root all of them if needed, but not much more.
Edit 2 : I really need something that runs on a live phone without the need of a PC. I can't modify the source code of individual apps and I can't decompile the ROM or use external tools like B.A.R.T I need an all-Java solution.
I can see that: usually the string for application label will get the first id in the resource strings. (not found an official document on this yet)
So the plan is: get the id of the label of an app, increase the id each time to get the next resource string until we get the Resources.NotFoundException
try {
List<ApplicationInfo> apps = getPackageManager()
.getInstalledApplications(0);
for (ApplicationInfo appInfo : apps) {
Resources mApk1Resources = getPackageManager()
.getResourcesForApplication(appInfo.packageName);
int id = appInfo.labelRes;
try {
Log.e("Test", "*******************************************");
Log.e("Test", apps.get(0).packageName);
while (true) {
Log.e("Test",
"String resource: "
+ mApk1Resources.getString(id));
id++;
}
} catch (Resources.NotFoundException e) {
// Handle exception
}
}
} catch (NameNotFoundException e) {
// Handle exception
}
Seeing you said you accept "jackhammer-dirty solutions", give this a try:
In your Strings.xml, surround all your String values with a <string-array> tag, and all string tags inside change to item tags, like so (used simple find-and-replace to replace the tag names):
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="hello">Hello World!</string>
<string name="app_name">YourAppNAme</string>
<string-array name="yourTitle">
<item>item1</item> //used to be <string name"blabla">....
<item>item2</item>
<item>item3</item>
</string-array>
</resources>
In your xml Layout file, where you have your ListView, put:
<ListView
android:id=”#+id/yourListView”
android:layout_width=”match_parent”
android:layout_height=”wrap_content”
android:entries="#array/yourTitle"
/>
Now, your Activity where you have your List, just call the ListView which should already be populated with the items from the Strings.xml
Don't forget to revert the changes in Strings.xml once you are done (and backup is always a good idea)!
Read more Here
Hope this helps!
Since you've rooted the phone and have access to every APK in the phone, how about just decompile them and get to the strings that way, see tutorial here: http://www.miui-au.com/add-ons/apktool/
Ok, I guess I found it. Reflection did the trick !
Root was not even needed. Crazy to know that any apps on your phone can see all the other's ressources...
public void listAllStrings(){
List<PackageInfo> packs = getPackageManager().getInstalledPackages(0);
for(int i=0;i<packs.size();i++) {
PackageInfo p = packs.get(i);
String pname = p.packageName;
Resources packageResources=null;
Context packageContext=null;
try
{
packageResources = MainActivity.this.getPackageManager().getResourcesForApplication(pname);
packageContext = MainActivity.this.createPackageContext(pname, Context.CONTEXT_INCLUDE_CODE + Context.CONTEXT_IGNORE_SECURITY);
}
catch(NameNotFoundException excep)
{
// the package does not exist. move on to see if another exists.
Log.e(pname, "Package not found!");
}
Class<?> stringClass=null;
try
{
// using reflection to get the string class inside the R class of the package
stringClass = packageContext.getClassLoader().loadClass(pname + ".R$string");
}
catch (ClassNotFoundException excep1)
{
// Less chances that class won't be there.
Log.e(pname, "R.string not found!");
}
if(stringClass!=null){
//For every fields of the string class
for( Field stringID : stringClass.getFields() )
{
try
{
//We get the id
int id = stringID.getInt(stringClass);
//We get the string value itself
String xmlResourceLayout = packageResources.getString(id);
Log.v(pname, xmlResourceLayout);
}
catch (Exception excep)
{
Log.e(pname, "Can't access : "+stringID.getName());
continue;
}
}
}
}
}
Hope this can help others :-)
Edit : For some Apks, the R class is not at the root of the package, so I had to write a find-R function
String findR(Context packageContext){
try {
//First case, the R class is easy to find !
packageContext.getClassLoader().loadClass(packageContext.getPackageName() + ".R");
return packageContext.getPackageName() + ".R";
} catch (Exception e) {
//Second case, it is not at the root of the package, we will list all classes...
Log.v(packageContext.getPackageName(),"R not found... Continue searching !");
try {
final PackageManager pm = getApplicationContext().getPackageManager();
ApplicationInfo ai = pm.getApplicationInfo(packageContext.getPackageName(), 0);
DexFile dx = DexFile.loadDex(ai.sourceDir, File.createTempFile("opt", "dex",
getCacheDir()).getPath(), 0);
String pathToR=null;
// Search inside each and every class in the dex file
for(Enumeration<String> classNames = dx.entries(); classNames.hasMoreElements();) {
String className = classNames.nextElement();
//for every single class, we will see if one of the fields is called app_name
//Log.v(className, "Class detail : "+className);
if(className.contains("R$string")) pathToR=className;
}
if(pathToR==null) throw new ClassNotFoundException();
pathToR=pathToR.replaceAll("$string", "");
Log.v(packageContext.getPackageName(), "R FOUND ! "+packageContext.getPackageName());
return pathToR;
} catch (Exception exc) {
Log.e(packageContext.getPackageName(), "ERROR ! R NOT FOUND ...");
return null;
}
}
}
But it still doesn't work in every case. So I ended hijacking the apktools library so it could run live on a phone... (I used the jar from 1.5.2 http://code.google.com/p/android-apktool/downloads/detail?name=apktool1.5.2.tar.bz2&can=2&q=) Here is my hijacked class :
public class Decoder {
public void decode(ResTable resTable, ExtFile apkFile, File outDir)
throws AndrolibException {
Duo<ResFileDecoder, AXmlResourceParser> duo = getResFileDecoder();
ResFileDecoder fileDecoder = duo.m1;
ResAttrDecoder attrDecoder = duo.m2.getAttrDecoder();
attrDecoder.setCurrentPackage(resTable.listMainPackages().iterator()
.next());
Directory inApk, in = null, out;
try {
inApk = apkFile.getDirectory();
out = new FileDirectory(outDir);
Log.v(MainActivity.SMALL_TAG,"Decoding AndroidManifest.xml with resources...");
fileDecoder.decodeManifest(inApk, "AndroidManifest.xml", out,
"AndroidManifest.xml");
// fix package if needed
adjust_package_manifest(resTable, outDir.getAbsolutePath()
+ "/AndroidManifest.xml");
if (inApk.containsDir("res")) {
in = inApk.getDir("res");
}
out = out.createDir("res");
} catch (DirectoryException ex) {
throw new AndrolibException(ex);
}
ExtMXSerializer xmlSerializer = getResXmlSerializer();
for (ResPackage pkg : resTable.listMainPackages()) {
attrDecoder.setCurrentPackage(pkg);
//Log.v(MainActivity.SMALL_TAG,"Decoding file-resources...");
//for (ResResource res : pkg.listFiles()) {
// fileDecoder.decode(res, in, out);
//}
Log.v(MainActivity.SMALL_TAG,"Decoding values */* XMLs...");
for (ResValuesFile valuesFile : pkg.listValuesFiles()) {
generateValuesFile(valuesFile, out, xmlSerializer);
}
generatePublicXml(pkg, out, xmlSerializer);
Log.v(MainActivity.SMALL_TAG,"Done.");
}
AndrolibException decodeError = duo.m2.getFirstError();
if (decodeError != null) {
throw decodeError;
}
}
public Duo<ResFileDecoder, AXmlResourceParser> getResFileDecoder() {
ResStreamDecoderContainer decoders = new ResStreamDecoderContainer();
decoders.setDecoder("raw", new ResRawStreamDecoder());
//decoders.setDecoder("9patch", new Res9patchStreamDecoder());
//TODO THIS DECODER CREATES ALL PROBLEMS !
AXmlResourceParser axmlParser = new AXmlResourceParser();
axmlParser.setAttrDecoder(new ResAttrDecoder());
decoders.setDecoder("xml", new XmlPullStreamDecoder(axmlParser,
getResXmlSerializer()));
return new Duo<ResFileDecoder, AXmlResourceParser>(new ResFileDecoder(
decoders), axmlParser);
}
public static final String PROPERTY_SERIALIZER_INDENTATION = "http://xmlpull.org/v1/doc/properties.html#serializer-indentation";
public static final String PROPERTY_SERIALIZER_LINE_SEPARATOR = "http://xmlpull.org/v1/doc/properties.html#serializer-line-separator";
public static final String PROPERTY_DEFAULT_ENCODING = "DEFAULT_ENCODING";
public ExtMXSerializer getResXmlSerializer() {
ExtMXSerializer serial = new ExtMXSerializer();
serial.setProperty(PROPERTY_SERIALIZER_INDENTATION,
" ");
serial.setProperty(PROPERTY_SERIALIZER_LINE_SEPARATOR,
System.getProperty("line.separator"));
serial.setProperty(PROPERTY_DEFAULT_ENCODING, "utf-8");
serial.setDisabledAttrEscape(true);
return serial;
}
public void adjust_package_manifest(ResTable resTable, String filePath)
throws AndrolibException {
// check if packages different, and that package is not equal to
// "android"
Map<String, String> packageInfo = resTable.getPackageInfo();
if ((packageInfo.get("cur_package").equalsIgnoreCase(
packageInfo.get("orig_package")) || ("android"
.equalsIgnoreCase(packageInfo.get("cur_package")) || ("com.htc"
.equalsIgnoreCase(packageInfo.get("cur_package")))))) {
Log.v(MainActivity.SMALL_TAG,"Regular manifest package...");
} else {
try {
Log.v(MainActivity.SMALL_TAG,"Renamed manifest package found! Fixing...");
DocumentBuilderFactory docFactory = DocumentBuilderFactory
.newInstance();
DocumentBuilder docBuilder = docFactory.newDocumentBuilder();
Document doc = docBuilder.parse(filePath.toString());
// Get the manifest line
Node manifest = doc.getFirstChild();
// update package attribute
NamedNodeMap attr = manifest.getAttributes();
Node nodeAttr = attr.getNamedItem("package");
mPackageRenamed = nodeAttr.getNodeValue();
nodeAttr.setNodeValue(packageInfo.get("cur_package"));
// re-save manifest.
TransformerFactory transformerFactory = TransformerFactory
.newInstance();
Transformer transformer = transformerFactory.newTransformer();
DOMSource source = new DOMSource(doc);
StreamResult result = new StreamResult(new File(filePath));
transformer.transform(source, result);
} catch (ParserConfigurationException ex) {
throw new AndrolibException(ex);
} catch (TransformerException ex) {
throw new AndrolibException(ex);
} catch (IOException ex) {
throw new AndrolibException(ex);
} catch (SAXException ex) {
throw new AndrolibException(ex);
}
}
}
private void generatePublicXml(ResPackage pkg, Directory out,
XmlSerializer serial) throws AndrolibException {
try {
OutputStream outStream = out.getFileOutput("values/public.xml");
serial.setOutput(outStream, null);
serial.startDocument(null, null);
serial.startTag(null, "resources");
for (ResResSpec spec : pkg.listResSpecs()) {
serial.startTag(null, "public");
serial.attribute(null, "type", spec.getType().getName());
serial.attribute(null, "name", spec.getName());
serial.attribute(null, "id",
String.format("0x%08x", spec.getId().id));
serial.endTag(null, "public");
}
serial.endTag(null, "resources");
serial.endDocument();
serial.flush();
outStream.close();
} catch (IOException ex) {
throw new AndrolibException("Could not generate public.xml file",
ex);
} catch (DirectoryException ex) {
throw new AndrolibException("Could not generate public.xml file",
ex);
}
}
private void generateValuesFile(ResValuesFile valuesFile, Directory out,
ExtXmlSerializer serial) throws AndrolibException {
try {
OutputStream outStream = out.getFileOutput(valuesFile.getPath());
serial.setOutput((outStream), null);
serial.startDocument(null, null);
serial.startTag(null, "resources");
for (ResResource res : valuesFile.listResources()) {
if (valuesFile.isSynthesized(res)) {
continue;
}
((ResValuesXmlSerializable) res.getValue())
.serializeToResValuesXml(serial, res);
}
serial.endTag(null, "resources");
serial.newLine();
serial.endDocument();
serial.flush();
outStream.close();
} catch (IOException ex) {
throw new AndrolibException("Could not generate: "
+ valuesFile.getPath(), ex);
} catch (DirectoryException ex) {
throw new AndrolibException("Could not generate: "
+ valuesFile.getPath(), ex);
}
}
private String mPackageRenamed = null;
}
and here's how I use it :
String pname = p.packageName;
Context packageContext = MainActivity.this.createPackageContext(pname, Context.CONTEXT_INCLUDE_CODE + Context.CONTEXT_IGNORE_SECURITY);
ApplicationInfo ai = packageContext.getApplicationInfo();
Log.v(TAG,"Analysing : "+pname+" "+ai.sourceDir);
if(new File(destination.getAbsolutePath()+"/"+pname+".strings.xml").exists()){
Log.v(TAG,"Already translated...");
continue;
}
ApkDecoder decoder = new ApkDecoder();
decoder.setApkFile(new File(ai.sourceDir));
File directory = new File(Environment.getExternalStorageDirectory()+File.separator+"tempApk");
directory.mkdirs();
DeleteRecursive(directory);
directory.mkdirs();
decoder.setOutDir(directory);
decoder.setForceDelete(true);
File frmwrk = new File(Environment.getExternalStorageDirectory()+File.separator+"framework");
frmwrk.mkdirs();
decoder.setFrameworkDir(Environment.getExternalStorageDirectory()+File.separator+"framework");
decoder.setDecodeSources((short)0x0000);
decoder.setKeepBrokenResources(true);
try{
//decoder.decode();
new Decoder().decode(decoder.getResTable(), new ExtFile(new File(ai.sourceDir)), directory);
} catch (Throwable e) {
e.printStackTrace();
}
Lots of headaches for few Strings ;-)

Android Soundpool Load(String path, int priority)

I am trying to load a sound from android.
The sound is under res/raw/myownsound.wav.
I know that I can already load the sound using:
soundPool.load(context, R.raw.myownsound, 1)
For customization purposes, I would like to load it using:
soundPool.load("res/raw/myownsound", 1)
... but I get the following error : error loading res/raw/myownsound.
I also tried the following :
soundPool.loadSound("android.resource://upg.GraphismeBase/raw/myownsound", 1)
.. but I get an error as well : error loading android.resource://upg.GraphismeBase/raw/myownsound
What is the correct way of using soundPool.load(path, priority) ?
Create a folder structure in your project
/assets/sounds/data/
Then copy your wav file there.
// Declare globally if needed
int mySoundId;
SoundPool soundPool = new SoundPool(5, AudioManager.STREAM_MUSIC, 0 );
AssetManager am = this.getAssets();
//Use in whatever method is used to load the sounds
try {
mySoundId = soundPool.load(am.openFd("sounds/data/myownsound"), 1);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
May try this (not sure its working) :
SoundPool mySoundPool = new SoundPool(4, AudioManager.STREAM_MUSIC, 0);
int myAudioFile = getResId("claps", R.raw.class);
try{
mySoundPool.load(context.getActivity(),myAudioFile,1);
} catch (Exception e){
message = String.valueOf(e);
}
public static int getResId(String variableName, Class<?> c) {
Field field = null;
int resId = 0;
try {
field = c.getField(variableName);
try {
resId = field.getInt(null);
} catch (Exception e) {
e.printStackTrace();
}
} catch (Exception e) {
e.printStackTrace();
}
return resId;
}
Simple working way of doing so with a context named mContext.
It loads the resource by name by getting the identifier id at run-time.
int sound_id = mContext.getResources().getIdentifier("myownsound", "raw",
mContext.getPackageName());
soundPool.load(mContext, sound_id, 1);
It also works to load drawables or xml files, by replacing "raw" by "drawable" or "xml" for example.

Retrieving all Drawable resources from Resources object

In my Android project, I want to loop through the entire collection of Drawable resources. Normally, you can only retrieve a specific resource via its ID using something like:
InputStream is = Resources.getSystem().openRawResource(resourceId)
However, I want to get all Drawable resources where I won't know their ID's beforehand. Is there a collection I can loop through or perhaps a way to get the list of resource ID's given the resources in my project?
Or, is there a way for me in Java to extract all property values from the R.drawable static class?
Okay, this feels a bit hack-ish, but this is what I came up with via Reflection. (Note that resources is an instance of class android.content.res.Resources.)
final R.drawable drawableResources = new R.drawable();
final Class<R.drawable> c = R.drawable.class;
final Field[] fields = c.getDeclaredFields();
for (int i = 0, max = fields.length; i < max; i++) {
final int resourceId;
try {
resourceId = fields[i].getInt(drawableResources);
} catch (Exception e) {
continue;
}
/* make use of resourceId for accessing Drawables here */
}
If anyone has a better solution that makes better use of Android calls I might not be aware of, I'd definitely like to see them!
i used getResources().getIdentifier to scan through sequentially named images in my resource folders. to be on a safe side, I decided to cache image ids when activity is created first time:
private void getImagesIdentifiers() {
int resID=0;
int imgnum=1;
images = new ArrayList<Integer>();
do {
resID=getResources().getIdentifier("img_"+imgnum, "drawable", "InsertappPackageNameHere");
if (resID!=0)
images.add(resID);
imgnum++;
}
while (resID!=0);
imageMaxNumber=images.size();
}
I have taken Matt Huggins great answer and refactored it to make it more generic:
public static void loadDrawables(Class<?> clz){
final Field[] fields = clz.getDeclaredFields();
for (Field field : fields) {
final int drawableId;
try {
drawableId = field.getInt(clz);
} catch (Exception e) {
continue;
}
/* make use of drawableId for accessing Drawables here */
}
}
Usage:
loadDrawables(R.drawable.class);
You should use the Raw folder and AssetManager, but if you want to use drawables because why not, here is how...
Let's suppose we have a very long file list of JPG drawables and we want to get all the resource ids without the pain of retrieving one by one (R.drawable.pic1, R.drawable.pic2, ... etc)
//first we create an array list to hold all the resources ids
ArrayList<Integer> imageListId = new ArrayList<Integer>();
//we iterate through all the items in the drawable folder
Field[] drawables = R.drawable.class.getFields();
for (Field f : drawables) {
//if the drawable name contains "pic" in the filename...
if (f.getName().contains("image"))
imageListId.add(getResources().getIdentifier(f.getName(), "drawable", getPackageName()));
}
//now the ArrayList "imageListId" holds all ours image resource ids
for (int imgResourceId : imageListId) {
//do whatever you want here
}
Add a picture named aaaa and another named zzzz, then iterate through the following:
public static void loadDrawables() {
for(long identifier = (R.drawable.aaaa + 1);
identifier <= (R.drawable.zzzz - 1);
identifier++) {
String name = getResources().getResourceEntryName(identifier);
//name is the file name without the extension, indentifier is the resource ID
}
}
This worked for me.
If you find yourself wanting to do this you're probably misusing the resource system. Take a look at assets and AssetManager if you want to iterate over files included in your .apk.
I guess the reflection code will work but I don't understand why you need this.
Resources in Android are static once the application is installed so you can have a list of resources or an array. Something like:
<string-array name="drawables_list">
<item>drawable1</item>
<item>drawable2</item>
<item>drawable3</item>
</string-array>
And from your Activity you can get it by doing:
getResources().getStringArray(R.array.drawables_list);
Just do this:
Field[] declaredFields = (R.drawable.class).getDeclaredFields();
The OP wanted drawables and I needed layouts. This is what I came up with for layouts. The name.startsWith business lets me ignore system generated layouts, so you may need to tweak that a bit. This should work for any resource type by modifying the value of clz.
public static Map<String,Integer> loadLayouts(){
final Class<?> clz = R.layout.class;
Map<String,Integer> layouts = new HashMap<>();
final Field[] fields = clz.getDeclaredFields();
for (Field field : fields) {
String name = field.getName();
if (
!name.startsWith("abc_")
&& !name.startsWith("design_")
&& !name.startsWith("notification_")
&& !name.startsWith("select_dialog_")
&& !name.startsWith("support_")
) {
try {
layouts.put(field.getName(), field.getInt(clz));
} catch (Exception e) {
continue;
}
}
}
return layouts;
}
USE THIS MY CODE
R.drawable drawableResources = new R.drawable();
Class<R.drawable> c = R.drawable.class;
Field[] fields = c.getDeclaredFields();
for (int i = 0, max = fields.length; i < max; i++) {
final int resourceId;
try {
resourceId = fields[i].getInt(drawableResources);
// call save with param of resourceId
SaveImage(resourceId);
} catch (Exception e) {
continue;
}
}
...
public void SaveImage(int resId){
if (!CheckExternalStorage()) {
return;
}
Bitmap bmp = BitmapFactory.decodeResource(getResources(), resID);
try {
File dir = new File(path);
if (!dir.exists()) {
dir.mkdirs();
}
OutputStream fOut = null;
File file = new File(path, "image1.png");
file.createNewFile();
fOut = new FileOutputStream(file);
bmp.compress(Bitmap.CompressFormat.PNG, 100, fOut);
fOut.flush();
fOut.close();
MediaStore.Images.Media.insertImage(this.getContentResolver(), file.getAbsolutePath(), file.getName(), file.getName());
Log.i(LOGTAG, "Image Written to Exterbal Storage");
} catch (Exception e) {
Log.e("saveToExternalStorage()", e.getMessage());
}
}
To create an array of drawables in Kotlin:
val drawablesFields: Array<Field> = drawable::class.java.fields
val drawables: ArrayList<Drawable> = ArrayList()
for (field in drawablesFields) {
context?.let { ContextCompat.getDrawable(it, field.getInt(null)) }?.let {
drawables.add (
it
)
}
}

Categories

Resources