Home » Android » How to change theme from another app resource in android?

How to change theme from another app resource in android?

Posted by: admin June 15, 2020 Leave a comment

Questions:

I know there is a way to set themes by defining in styles.xml and use it like that

setTheme(android.R.style.MyTheme);

However, I want to get themes from another app which I developed as well. I know the resources names and actually I am able to get theme id with this code block;

Resources res = getPackageManager().getResourcesForApplication("com.example.theme");
int resThemeId = res.getIdentifier("my_theme","style","com.example.theme");

When I debug, I see that resThemeId is not zero.

Then, I need the final command to set this theme. Before super.onCreate() function, I try to implement this method but it seems it is not working

setTheme(resThemeId);

But instead of this, if I write below statement, I works fine

setTheme(android.R.style.Theme_Holo_Light);

So, what should I do to use a theme from different package resource?

How to&Answers:

So, what should I do to use a theme from different package resource?

You shouldn’t do this for many reasons. I wrote a simple project that shows that it is indeed possible as long as the package contains the resources your activity uses.

See: https://github.com/jaredrummler/SO-41872033


Basically, you would need to return the package’s resources from the activity:

public class MainActivity extends AppCompatActivity {

  Resources resources;

  @Override protected void onCreate(Bundle savedInstanceState) {

    int themeResId = getResources().getIdentifier("AppTheme", "style", "com.example.theme");
    if (themeResId != 0) {
      setTheme(themeResId);
    }

    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
  }

  @Override public Resources getResources() {
    if (resources == null) {
      try {
        resources = getPackageManager().getResourcesForApplication("com.example.theme");
      } catch (PackageManager.NameNotFoundException e) {
        resources = super.getResources();
      }
    }
    return resources;
  }

}

This is just to show that it is possible. Again, I recommend that you avoid this.

Answer:

As already mentioned in a comment you can access resources from other applications, but using another applications theme will not work.


Since having proof is always a good thing let’s have a look at the source code (I used API 24 sources)

Calling setTheme() on an Activity will invoke initializeTheme() in the ContextThemeWrapper parent class, which will end up calling onApplyThemeResource(..) which in turn will try to load the actual theme data from resources by calling theme.applyStyle(resId, true)

Following the chain through the wrapper Resources.Theme we can see in ResourcesImpl.ThemeImpl the following, where AssetManager is called to load the style into the theme:

void applyStyle(int resId, boolean force) {
    synchronized (mKey) {
        AssetManager.applyThemeStyle(mTheme, resId, force);

        mThemeResId = resId;
        mKey.append(resId, force);
    }
}

This is where you try and fail to load the foreign theme from your other app.


Since most of the methods you would need to use are static calls or package local methods it does not seem that there is any way to achieve what you want, (e.g. applying or creating a new Theme)

Even if you get a hold of the other application’s AssetManager by using getAssets() on a context there is no accessible method to create or apply themes.

So the only way to use another app’s resources would be to add the resources to yours.

Answer:

Have you seen this demo: Multiple Theme Material Design

You can check this demo for runtime theme change.

Hope it will helps you.