Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android Dynamically Add Item to Array XML Resource

Is there any way I can add items in code to a String-Array resource? For instance, if I want to create a spinner that shows the user values, and I want to allow the user to add their own custom values.

like image 576
Eliezer Avatar asked Feb 03 '12 09:02

Eliezer


2 Answers

No. this is not supported because resources are packaged in the binary .apk and as such cannot be changed.

Don't follow this design pattern, change your approach.

like image 56
JoxTraex Avatar answered Sep 18 '22 05:09

JoxTraex


probably JoxTraex has no idea on android framework or as they are saying:

when someone says this can't be done - there always is someone who doesn't know that and will do it :)

so to the point:

Resources is an open class is just a wrapper around ResourcesImpl class

(with depreciated constructor - but is available)

public Resources(AssetManager assets, DisplayMetrics metrics, Configuration config)

in app every call to it is made via Context

so:

1) you always can provide your own Resources implementation

2) or (when its enough) your own Context implementation (so sky is the limit)

... i now feel eyes on "Context implementation" - yeah you can even replace top most context in LoadedApk, Activity, etc.. yeah cool? but when, how? how: via reflections, when: good app designer knows that this place is where (before) first/any call to such object is made ...

But there is one dangerous catch here - in one case android straight unwrap Context to ContextImp and then you need to return those Context instead yours - where is the place that i'll keep as secret for those who like riddles :)

there is also in Resources

a) a hidden constructor (best entry point as it is not making any ReourceImpl (which can be set by method mentioned bellow)

public Resources(@Nullable ClassLoader classLoader) 

b) hidden method

setResImpl(ResourcesImpl) 

sum up:

so by calling

Resources.getStringArray(**not existing in APK resource id here**);

on our own implementation we could get whatcha want :)

even better we can add to our implementation

addResourceById(int,Object)

method and add new resources :) then with assign ability check on resource we will use and do a up casting to our implementation :) to use our newly added method :)

btw: if someone says to you "you shouldn't do it - blablabla" this is the best reason to do it! - if not permitted by law :)

enough the theory go to a practice:

example Context implementation forwards calls to getString:

    public class MyContext extends Context {
        ....
    // override context get resources method 
    @Override
    public android.content.res.Resources getResources() {
        // get super resources 
        android.content.res.Resources resources = super.getResources();
        // pull assets 
        android.content.res.AssetManager assets = resources.getAssets();
        // pull metrics 
        android.util.DisplayMetrics displayMetrics = resources.getDisplayMetrics();
        // pull configuration 
        android.content.res.Configuration configuration = resources.getConfiguration();
        // construct new anon resource implementation 
        return new android.content.res.Resources(assets, displayMetrics, configuration) {

            // overrride interesting method 
            @android.support.annotation.NonNull
            @Override
            public String getString(int id) throws android.content.res.Resources.NotFoundException {
                return id == pl.ceph3us.base.common.R.string.my_sweet_google
                    ? "fck_you_google";
                    : super.getString(id);
            }
        };
    }

}
like image 27
ceph3us Avatar answered Sep 21 '22 05:09

ceph3us