Andriod 切换主题(APK主题包)

Android apk主题切换方式有很多种,比较传统的方法是:

1.为APK定制多个style/theme内容,供用户动态切换【优点:实现简单方便;缺点:主题固定,新增麻烦】

2.作为资源放置到SD卡下,再进行读取(暂无)

当前目前有一种方式可以通过新建一个资源apk,主应用去获取资源apk的主题,这种方法可以有效的减小主应用的大小。新增主题类型方便。缺点就是实现过程较麻烦

实现原理:

1.新建资源apk,该资源APK只要提供必要的资源文件[style、theme、pic等]供主应用调用即可

2.主应用调用通过PackageManager类来实现

详细说明下主应用的实现方法

通过浏览Android系统PackageManager的源码,PackageManager提供了如下的方法

  /**
     * Retrieve overall information about an application package that is
     * installed on the system.
     * <p>
     * Throws {@link NameNotFoundException} if a package with the given name can
     * not be found on the system.
     *
     * @param packageName The full name (i.e. com.google.apps.contacts) of the
     *            desired package.
     * @param flags Additional option flags. Use any combination of
     *            {@link #GET_ACTIVITIES}, {@link #GET_GIDS},
     *            {@link #GET_CONFIGURATIONS}, {@link #GET_INSTRUMENTATION},
     *            {@link #GET_PERMISSIONS}, {@link #GET_PROVIDERS},
     *            {@link #GET_RECEIVERS}, {@link #GET_SERVICES},
     *            {@link #GET_SIGNATURES}, {@link #GET_UNINSTALLED_PACKAGES} to
     *            modify the data returned.
     * @return Returns a PackageInfo object containing information about the
     *         package. If flag GET_UNINSTALLED_PACKAGES is set and if the
     *         package is not found in the list of installed applications, the
     *         package information is retrieved from the list of uninstalled
     *         applications (which includes installed applications as well as
     *         applications with data directory i.e. applications which had been
     *         deleted with {@code DONT_DELETE_DATA} flag set).
     * @see #GET_ACTIVITIES
     * @see #GET_GIDS
     * @see #GET_CONFIGURATIONS
     * @see #GET_INSTRUMENTATION
     * @see #GET_PERMISSIONS
     * @see #GET_PROVIDERS
     * @see #GET_RECEIVERS
     * @see #GET_SERVICES
     * @see #GET_SIGNATURES
     * @see #GET_UNINSTALLED_PACKAGES
     */
    public abstract PackageInfo getPackageInfo(String packageName, int flags)
            throws NameNotFoundException;

 根据注释,该方法需要提供资源apk完整的包名(packageName)及附加选项(flags,该选项会影响方法的参数返回)

 要获取资源APK的resource资源,该类为我们提供了getResourcesForApplication方法

    /**
     * Retrieve the resources for an application.  Throws NameNotFoundException
     * if the package is no longer installed.
     *
     * @param app Information about the desired application.
     *
     * @return Returns the application's Resources.
     * @throws NameNotFoundException Thrown if the resources for the given
     * application could not be loaded (most likely because it was uninstalled).
     */
    public abstract Resources getResourcesForApplication(ApplicationInfo app)
            throws NameNotFoundException;

该方法的参数我们可以从上一个方法中返回的PackageInfo对象中获取(packageInfo.applicationInfo)

到这里我们已经成功拿到了资源APK的所有Resources 文件。剩下的就是怎么获取到特定的资源并且使用它。

使用资源文件,一般我们是通过该资源的ID使用该资源(asset资源除外),所以只要我们能够拿到资源的ID,我们就有办法使用该资源。很幸运,Resources类给我们提供了如下的方法:

   /**
     * Return a resource identifier for the given resource name.  A fully
     * qualified resource name is of the form "package:type/entry".  The first
     * two components (package and type) are optional if defType and
     * defPackage, respectively, are specified here.
     * 
     * <p>Note: use of this function is discouraged.  It is much more
     * efficient to retrieve resources by identifier than by name.
     * 
     * @param name The name of the desired resource.
     * @param defType Optional default resource type to find, if "type/" is
     *                not included in the name.  Can be null to require an
     *                explicit type.
     * @param defPackage Optional default package to find, if "package:" is
     *                   not included in the name.  Can be null to require an
     *                   explicit package.
     * 
     * @return int The associated resource identifier.  Returns 0 if no such
     *         resource was found.  (0 is not a valid resource ID.)
     */
    public int getIdentifier(String name, String defType, String defPackage) {
        if (name == null) {
            throw new NullPointerException("name is null");
        }
        try {
            return Integer.parseInt(name);
        } catch (Exception e) {
            // Ignore
        }
        return mAssets.getResourceIdentifier(name, defType, defPackage);
    }

该方法需要传递如下的参数

(name:需要查找的资源名称,比如你的资源APK中有一张test.jpg的图片,想知道它的id,name="test")

 (defType:待查找的资源类型,可以是"layout","dimen"等)

(defpackage:在哪个包下查找)

如果未找到 资源文件,该方法将返回0.

//--------------------------------------------------------------------

代码实现:(待补充)

原文地址:https://www.cnblogs.com/IntelligentBrain/p/4938850.html