Search code examples
androidandroid-resourcesaapt

Programmatically change the value of a color resource obtained from API response


Let's say, on my API call I have a parameter that's called color. Is it possible to edit or modify an existent R.colors.color to assign the color from the API result?

As an example:

I make a call to my API and it returns green, now I want to load my app with i.e (green Toolbar, green TextView color, etc.), is that possible?

My first thought was:

Create a item on colors.xml called demo then assign it a default color, then use this demo color wherever I want (Button, TextView, etc.) Then I thought it could be possible to change this value programmatically with the result from the API so I wouldn't need to create a SharedPreferences or something like that and for avoiding more code.

As @Y.S. said to me

Unfortunately, you WILL have to set the color of the text or view manually everywhere ... :(

I would like if there is other way to do it, since I don't know how many Activities my project will contain, so if is there other way to do it I'm glad to hear other guesses.

EDIT

I'm trying the @Jared Rummler answer and maybe i'm doing something wrong... I've created a simple Json and I put on my Assets I parse the Json and I put it on a GlobalConstant then I made a "simple app".

First of all I have a TextView and a Button which contains the "your_special_color", and the return of it I put the GlobalConstant int as follows :

case "your_special_color":                
            return GlobalConstant.color; 

Then what I tried is my first Activity has 1 TextView and 1 Button as I said before and they have the color "your_special_color" that I don't want to change it, BUT I have an Intent on my Button to open the other Activity that contains the same but with the GlobalConstant.color and it doesn't change.

I tried it doing this (my second Activity):

public class Main2Activity extends AppCompatActivity {
private Res res;
@Override public Resources getResources() {
    if (res == null) {
        res = new Res(super.getResources());
    }
    return res;
}
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main2);
    Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
    setSupportActionBar(toolbar);
}

Did I miss something?

Oh.. I figured it out I guess is doing this on my MainActivity2 ?

 Button btn = (Button)findViewById(R.id.button2);
 btn.setBackgroundColor(res.getColor(R.color.your_special_color));

Solution

  • If you take a look at the Accessing Resources document, what it says is that ...

    Once you provide a resource in your application, you can apply it by referencing its resource ID. All resource IDs are defined in your project's R class, which the aapt tool automatically generates.

    Furthermore,

    When your application is compiled, aapt generates the R class, which contains resource IDs for all the resources in your res/ directory. For each type of resource, there is an R subclass (for example, R.drawable for all drawable resources), and for each resource of that type, there is a static integer (for example, R.drawable.icon). This integer is the resource ID that you can use to retrieve your resource.

    What this is saying, essentially, is that pretty much everything held as a resource in the res/ directory is compiled and referenced as an unchangeable constant. It is for this reason that the values of resource elements cannot be changed programmatically/at runtime, because they are compiled. As opposed to local/global variables & SharedPreferences, resource elements are represented in program memory as fixed, unchangeable objects. They are held in a special read-only region of program memory. In this regard, see also Changing value of R.String Programmatically.

    What you can do is, to avoid using the same code at a thousand places in your project, create a common function that changes the value of the color in the SharedPreferences and use this method everywhere. I'm sure you knew this already, of course.

    To reduce the amount of code you need to add to the project, there is an alternative. I have previously used the calligraphy library which allowed me to fix the font style & color throughout the app. This may be of some good use to you, check it out ...