如何从 android 中的另一个应用程序资源更改主题?

How to change theme from another app resource in android?

我知道有一种方法可以通过在 styles.xml 中定义来设置主题并像那样使用它

setTheme(android.R.style.MyTheme);

但是,我想从我开发的另一个应用程序中获取主题。我知道资源名称,实际上我可以使用此代码块获取主题 ID;

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

调试时,我发现 resThemeId 不为零。

然后,我需要最后的命令来设置这个主题。在 super.onCreate() 函数之前,我尝试实现这个方法,但它似乎不起作用

setTheme(resThemeId);

但不是这样,如果我写下面的语句,我工作正常

setTheme(android.R.style.Theme_Holo_Light);

那么,如何使用来自不同包资源的主题?

如评论中所述,您可以从其他应用程序访问资源,但使用其他应用程序主题将不起作用。


既然有证据总是好事,让我们看看源代码(我使用了 API 24 个源代码)

Activity 上调用 setTheme() 将在 ContextThemeWrapper 父 class 中调用 initializeTheme(),这将最终调用 onApplyThemeResource(..)反过来将尝试通过调用 theme.applyStyle(resId, true)

从资源中加载实际的主题数据

通过包装器跟踪链 Resources.Theme 我们可以在 ResourcesImpl.ThemeImpl 中看到以下内容,其中调用 AssetManager 将样式加载到主题中:

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

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

这是您尝试从其他应用加载 foreign 主题的地方。


由于您需要使用的大多数方法都是静态调用或封装本地方法,因此似乎没有任何方法可以实现您想要的(例如应用或创建新主题)

即使您通过在上下文 there is no accessible method to create or apply themes.

上使用 getAssets() 获得其他应用程序的 AssetManager

因此,使用其他应用程序资源的唯一方法是将资源添加到您的资源中。

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

出于多种原因,您不应该这样做。我写了一个简单的项目,表明只要包中包含您的 activity 使用的资源,它确实是可能的。

参见:https://github.com/jaredrummler/SO-41872033


基本上,您需要 return 来自 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;
  }

}

这只是为了证明这是可能的。同样,我建议您避免这种情况。

你看过这个演示吗:Multiple Theme Material Design

您可以查看此演示以了解运行时主题更改。

希望对您有所帮助。