如何从android中的另一个应用程序资源更改主题?
Posted
技术标签:
【中文标题】如何从android中的另一个应用程序资源更改主题?【英文标题】:How to change theme from another app resource in android? 【发布时间】:2017-06-11 20:09:36 【问题描述】:我知道有一种方法可以通过在 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);
那么,我应该怎么做才能使用来自不同包资源的主题?
【问题讨论】:
您可以从另一个包中获取资源 ID,但这些资源在您的 APK 中不存在。使用PackageManager#getResourcesForApplication(String packageName)
加载资源应该适用于可绘制对象、字符串、布尔值等。但是,我认为加载另一个 APK 的主题是不可能的,而且绝对不推荐。
虽然我可以从其他包资源中获得可绘制对象、字符串、布尔值,但我也希望获得主题。为什么不可能?
有可能(见我的回答)。您需要覆盖 getResrouces 以返回其他应用程序的资源,以便您可以应用主题。这也会返回来自其他应用程序的所有字符串、布局、可绘制对象和其他资源,因此不建议这样做。
【参考方案1】:
正如评论中已经提到的,您可以从其他应用程序访问资源,但使用其他应用程序主题将不起作用。
既然有证据总是一件好事,让我们看看源代码(我使用了 API 24 源代码)
在Activity
上调用setTheme()
将调用ContextThemeWrapper
父类中的initializeTheme()
,最终将调用onApplyThemeResource(..)
,而onApplyThemeResource(..)
又将尝试通过调用@987654327 从资源中加载实际的主题数据@
通过包装器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
。
因此,使用其他应用资源的唯一方法是将资源添加到您的资源中。
【讨论】:
sharedUserId 怎么样?如果我将 sharedUserId 用于两个应用程序并使用相同的证书进行签名,会发生什么?我试过但没有运气。也许我在代码的某个地方做错了【参考方案2】:那么,我应该怎么做才能使用来自不同包资源的主题?
出于多种原因,您不应该这样做。我写了一个简单的项目,表明只要包包含您的活动使用的资源,它确实是可能的。
见:https://github.com/jaredrummler/SO-41872033
基本上,您需要从活动中返回包的资源:
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;
这只是为了表明它是可能的。同样,我建议您避免这种情况。
【讨论】:
是否可以通过这种方式在运行时更改资源?我的意思是,我想在从另一个资源设置主题后设置原始资源? 我不认为这是可能的,但我也不认为从另一个包中应用主题是可能的。这就是为什么我不推荐这个解决方案。您不想将另一个包的资源用于布局和活动中的任何可绘制对象。你到底想用这个实现什么? 我实际上尝试编写一个主题管理器和不同的 apk,其中包括一些主题(主题包括背景图像、默认声音、应用程序图标等)当我打开主题管理器应用程序时,我可以检索可绘制对象和列表他们从主题apk的相应。但是,当我更改主题时,我还想更改一些应用程序主题(如设置应用程序)。 (我想设置主色、强调色等)顺便说一句,我正在做 AOSP 项目,我可以轻松更改设置代码。我想要的只是从我的主题应用程序资源之一更改设置主题。【参考方案3】:你看过这个演示吗:Multiple Theme Material Design
您可以查看此演示以了解运行时主题更改。
希望对你有帮助。
【讨论】:
该问题要求从设备上安装的不同软件包更改主题。这会将应用程序主题更改为当前包样式中预定义的内容。虽然这是应用主题的推荐方式,但它不能回答 OP 的问题。以上是关于如何从android中的另一个应用程序资源更改主题?的主要内容,如果未能解决你的问题,请参考以下文章
如何在 Android 中更改 SettingsActivity 的主题?
Android 如何从 Main Activity 中的另一个类调用 Activity 数据类型?
如何使用数据库将大量数据从一个活动传递到android中的另一个活动