最佳实践。扩展或覆盖一个Android库项目类[英] Best practice: Extending or overriding an Android library project class

本文是小编为大家收集整理的关于最佳实践。扩展或覆盖一个Android库项目类的处理/解决方法,可以参考本文帮助大家快速定位并解决问题,中文翻译不准确的可切换到English标签页查看源文。

问题描述

我们正在使用 android库项目在我们的Android应用程序的不同构建(目标)上共享核心类和资源.每个特定目标的Android项目 a>(在幕后,Eclipse创建并引用了引用库项目的JAR).

诸如图像和XML布局之类的资源很容易.放置在目标项目中的资源文件,例如应用程序图标或XML布局,在构建应用程序时,将自动覆盖具有相同名称的核心库资源.但是,有时需要覆盖类以实现特定于目标的行为.例如,Amazon目标首选项屏幕不能包含指向Google Play应用程序页面的链接,需要更改Amazon Project的preverences.xml和Preverences活动类.

目标是减少目标项目中的重复代码的数量,同时从核心库中删除特定于目标的代码.我们提出了几种方法来实施特定于不同目标的逻辑:

  1. 在核心库类中编写目标特异性功能,并使用if/switch块根据产品SKU选择行为.这种方法不是很模块化,并且会膨胀核心库代码库.
  2. 在目标项目中扩展特定的核心类,并根据需要覆盖基础(Core)类功能.然后在核心库中保留对基类对象的引用,并使用扩展类的对象实例化(来自如何在Android库项目中覆盖类?)

还有其他策略可以覆盖或扩展Android图书馆项目类吗?在Android应用程序中共享和扩展共同类的最佳实践是什么?

推荐答案

库项目被称为原始项目依赖关系(基于源的机制),而不是编译JAR依赖关系(基于编译的库库机制).

@yorkw对于Eclipse的ADT插件的最新版本不正确 http://developer.android.com/sdky.com/sdk/eclipse-eclipse-adt.htt.ht.html

版本17更改日志

新构建功能 为自动设置JAR依赖项添加了功能./libs文件夹中的任何.jar文件都添加到构建配置中(类似于蚂蚁构建系统的工作方式).另外,库项目所需的JAR文件也会自动添加到取决于这些图书馆项目的项目中. (更多信息)

更多信息 >

在此之前,更新图书馆项目的活动覆盖很容易,只需不包括课程即可.现在,该库作为JAR文件包含,并且无法将类文件排除在JAR依赖项中.

编辑:

我从图书馆jar的旋转/扩展活动的解决方案:

我创建了一个简单的UTIL类:

public class ActivityUtil {

private static Class getActivityClass(Class clazz) {

    // Check for extended activity
    String extClassName = clazz.getName() + "Extended";
    try {
        Class extClass = Class.forName(extClassName);
        return extClass;
    } catch (ClassNotFoundException e) {
        e.printStackTrace();
        // Extended class is not found return base
        return clazz;
    }
}

public static Intent createIntent(Context context, Class clazz) {
    Class activityClass = getActivityClass(clazz);
    return new Intent(context, activityClass);
}
}

为了覆盖图书馆的" SampleActivity"类,它依赖于该库的项目,创建一个新类,其中包含同一软件包中的项目中的sampleactivityExtivityExtivedent在同一软件包中,并将新活动添加到您的androidManifest.xml.<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

重要:所有参考覆盖活动的意图都应通过以下方式通过util类创建:

Intent intent = ActivityUtil.createIntent(MainActivity.this, SampleActivity.class);
...
startActivity(intent);

其他推荐答案

幕后,Eclipse创建并引用了引用库项目的JAR.

这不是很准确.图书馆项目被称为原始项目依赖关系(基于源的机制),而不是编译JAR依赖关系(基于编译代码的库机制).当前,Android SDK不支持将库项目导出到独立的JAR文件.必须始终通过在依赖应用程序和构建该应用程序中引用库来间接编译/构建库项目.当构建依赖项目时,需要将需要过滤/合并从库项目合并的编译源和原始资源将被复制并正确包含在最终APK文件中.请注意,自R14以来,Android团队已经开始对整个图书馆项目设计(将其从基于我们的机制移动到基于编译的库机制),如图书馆项目. br> Java给出的解决方案是 sastaritance 多态性.
聚在一起,最好的做法是IMO是您在问题中提到的第二个选项:

2.将特定的核心类放置在目标项目中,并根据需要覆盖基础(Core)类功能.然后在核心库中保留对基类对象的引用,并使用扩展类的对象(来自Android库项目 - 如何覆盖类?)

根据我的个人经验,我始终使用Android库项目(有时使用常规Java项目,仅包含POJO的JAR/buolding common-jar)管理通用代码,例如超级活动或超级服务,并扩展/扩展/实施适当的代码多态性的依赖项目中的类/接口.

其他推荐答案

基于毒药溶液和涡轮溶液的解决方案.

public static Class<?> getExtendedClass(Context context, String clsName) {

    // Check for extended activity
    String pkgName = context.getPackageName();
    Logger.log("pkgName", pkgName);
    String extClassName = pkgName + "." + clsName + "Extended";
    Logger.log("extClassName", extClassName);

    try {
        Class<?> extClass = Class.forName(extClassName);
        return extClass;
    } catch (ClassNotFoundException e) {
        e.printStackTrace();
        // Extended class is not found return base
        return null;
    }
}

这样的好处是

  1. 扩展类可以在项目的包中,而不是库的软件包.感谢Turbo的这一部分.

  2. 通过将String作为参数而不是Class对象,即使在proguard中也可以使用此方法. getName()是proguard的问题,因为它将返回类似" a"的东西,而不是原始类的名称.因此,在原始解决方案中而不是寻找classextending,它将寻找不存在的东西.

本文地址:https://www.itbaoku.cn/post/627664.html

问题描述

We're using an Android Library Project to share core classes and resources across different builds (targets) of our Android application. The Android projects for each specific target reference the Core library project (behind the scenes, Eclipse creates and references a jar from the referenced library project).

Overriding resources such as images and XML layouts is easy. Resource files placed in the target project, such as the app icon or an XML layout, automatically override the core library's resources with the same name when the app is built. However, sometimes a class needs to be overridden to enable target-specific behavior. For example, the Amazon target preferences screen cannot contain a link to the Google Play app page, requiring a change in the Amazon project's preferences.xml and preferences Activity class.

The goal is to reduce the amount of duplicate code among target projects while removing as much target-specific code from the Core library as possible. We've come up with a couple of approaches to implement logic specific to different targets:

  1. Write the target-specific functions within Core library classes and use if/switch blocks to select behavior based on product SKU. This approach is not very modular and bloats the Core library codebase.
  2. Extend the particular Core class in a target project and override the base (Core) class functions as needed. Then keep a reference to the base-class object in the Core library and instantiate it with an extended class object (from How to override a class within an Android library project?)

Are there other strategies to override or extend an Android library project class? What are some of the best practices for sharing and extending common classes among Android app targets?

推荐答案

Library project is referenced as a raw project dependency (source-based mechanism), not as a compiled jar dependency (compiled-code based library mechanism).

@yorkw this is not true for the latest versions of ADT Plugin for Eclipse http://developer.android.com/sdk/eclipse-adt.html

From version 17 Change log

New build features Added feature to automatically setup JAR dependencies. Any .jar files in the /libs folder are added to the build configuration (similar to how the Ant build system works). Also, .jar files needed by library projects are also automatically added to projects that depend on those library projects. (more info)

More info http://tools.android.com/recent/dealingwithdependenciesinandroidprojects

Before that, update overwriting of the Activity from Library project was easy, just exclude the class. Now the library is included as jar file, and there is no way to exclude class file from jar dependency.

EDIT:

My solution to overwrete/extend Activity from library jar:

I created a simple util class:

public class ActivityUtil {

private static Class getActivityClass(Class clazz) {

    // Check for extended activity
    String extClassName = clazz.getName() + "Extended";
    try {
        Class extClass = Class.forName(extClassName);
        return extClass;
    } catch (ClassNotFoundException e) {
        e.printStackTrace();
        // Extended class is not found return base
        return clazz;
    }
}

public static Intent createIntent(Context context, Class clazz) {
    Class activityClass = getActivityClass(clazz);
    return new Intent(context, activityClass);
}
}

In order to overwrite a library's "SampleActivity" class it a the project which depends on that library, create a new class with the name SampleActivityExtended in the project in the same package and add the new activity to your AndroidManifest.xml.

IMPORTANT: all intents referencing overwritten activities should be created through the util class in the following manner:

Intent intent = ActivityUtil.createIntent(MainActivity.this, SampleActivity.class);
...
startActivity(intent);

其他推荐答案

behind the scenes, Eclipse creates and references a jar from the referenced library project.

This is not quite accurate. Library project is referenced as a raw project dependency (source-based mechanism), not as a compiled jar dependency (compiled-code based library mechanism). Currently Android SDK does not support exporting a library project to a self-contained JAR file. The library project must always be compiled/built indirectly, by referencing the library in the dependent application and building that application. When build dependent project, the compiled source and raw resources that need to be filtered/merged from Library project are copied and properly included in the final apk file. Note that Android team had started revamping the whole Library Project design (move it from ource-based mechanism to compiled-code based library mechanism) since r14, as mentioned in this earlier blog post.

What are some of the best practices for sharing and extending common classes among Android app targets?

The solution given by Android is Library Project.
The solution given by Java is Inheritance and Polymorphism.
Come together, the best practice IMO is the second option you mentioned in the question:

2.Extend the particular Core class in a target project and override the base (Core) class functions as needed. Then keep a reference to the base-class object in the Core library and instantiate it with an extended class object (from Android library project - How to overwrite a class?)

From my personal experience, I always use Android Library Project (Sometimes with Regular Java Project, for implementing/building common-lib.jar that contains only POJO) manage common code, for instance SuperActivity or SuperService, and extends/implements proper classes/interfaces in the dependent project for Polymorphism.

其他推荐答案

Solution based on PoisoneR's solution and Turbo's solution.

public static Class<?> getExtendedClass(Context context, String clsName) {

    // Check for extended activity
    String pkgName = context.getPackageName();
    Logger.log("pkgName", pkgName);
    String extClassName = pkgName + "." + clsName + "Extended";
    Logger.log("extClassName", extClassName);

    try {
        Class<?> extClass = Class.forName(extClassName);
        return extClass;
    } catch (ClassNotFoundException e) {
        e.printStackTrace();
        // Extended class is not found return base
        return null;
    }
}

The benefits of this is that

  1. The extended class can be in the project's package, not the library's package. Thanks to Turbo for this part.

  2. By taking a String as an argument instead of a Class object, this method is able to be used even with ProGuard. getName() is where the problem is with ProGuard, as that will return something like "a" instead of the name of the original class. So in the original solution instead of looking for ClassExtended it will look for aExtended instead, something which does not exist.