【问题标题】:Access main project from module in Android Studio?从 Android Studio 中的模块访问主项目?
【发布时间】:2020-08-01 11:25:09
【问题描述】:

我正在使用 this library 作为模块在本地安装。我可以通过我的主项目访问它,但我不能做相反的事情。例如,从这个库访问我的主项目中的一个变量...

我尝试在库的build.gradle 中添加这一行:

    implementation project(':app')

但我收到了这个奇怪的错误:

Circular dependency between the following tasks:
:placepicker:generateDebugRFile
\--- :placepicker:generateDebugRFile (*)
    
(*) - details omitted (listed previously)

我该如何解决这个问题?我的项目是 Java,我的库是 Kotlin

【问题讨论】:

  • AIDL 成功了吗?

标签: java android kotlin


【解决方案1】:

“循环依赖”只能通过删除在两侧之一上导致此问题的依赖性来修复。

如果您需要从库代码中访问某些数据,您可以在库中实现一个接口,该接口将由您项目中的某个类扩展。然后,您将能够使用库中的扩展类和接口中定义的访问方法

示例

假设您需要在库中获取对应用程序上下文的引用。你应该创建一个接口:

interface ContextAccessor {
    // Marking it as optional just in case
    // you will not be able to get a context
    // from an object that implemented ContextAccessor
    fun getApplicationContext(): Application?
}

因为您将该库作为依赖项添加到项目中,所以您可以访问ContextAccessor。用这个接口扩展一些类并实现getApplicationContext 方法。假设您想扩展一些Activity

class MyActivity: Activity, ContextAccessor {
    ... other code here

    override fun getApplicationContext(): Application? = application
}

现在,在您的 MyActivity 类中,您可以将 ContextAccessor 设置到您的库中,就好像它是 dependency injection

class MyActivity: Activity, ContextAccessor {
    ... other code here 
    
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        val someLibraryClassInstance = SomeLibraryClass()
        someLibraryClassInstance.setContextAccessor(this)
        // OR -> `someLibraryClassInstance.contextAccessor = this`
    }
}

警告当您保存对任何 Android 组件(尤其是 Activity、Fragment、Dialog 等)的引用时,请确保稍后在对象将要被销毁时删除此引用避免内存泄漏。

如何从之前的代码sn-p中删除对一点点修改代码的引用:

class MyActivity: Activity, ContextAccessor {
    ... other code here 

    private val someLibraryClassInstance = SomeLibraryClass()   
 
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
         
        // ContextAccessor reference is set to some library class
        someLibraryClassInstance.setContextAccessor(this)
    }

    override fun onDestroy() {
        super.onDestroy()

        // Super important!
        someLibraryClassInstance.setContextAccessor(null)
        // OR create some method like `someLibraryClassInstance.removeContextAccessor(this)`
    }
}

Java 中的相同类

interface ContextAccessor {
    // Marking it as optional just in case
    // you will not be able to get a context
    // from an object that implemented ContextAccessor
    Application getApplicationContext();
}
public class MyActivity extends Activity implements  MyActivity.ContextAccessor {
    
    private SomeLibraryClass someLibraryClassInstance = SomeLibraryClass();

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // ContextAccessor reference is set to some library class
        someLibraryClassInstance.setContextAccessor(this);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        // Super important!
        someLibraryClassInstance.setContextAccessor(null);
        // OR create some method like `someLibraryClassInstance.removeContextAccessor(this)`
    }

    @Override
    public Application getApplicationContext() {
        return super.getApplication();
    }
}

更新(2020 年 8 月 10 日):如何使用 ContextAccessor?

您可以在库中使用ContextAccessor

class SomeLibraryClass {
    private var mContextAccessor: ContextAccessor?

    fun setContextAccessor(contextAccessor: ContextAccessor?) {
        mContextAccessor = contextAccessor
    }
    
    fun someOtherMethod() {
        mContextAccessor?.getAppContext()?.let { nonNullContext ->
            // use nonNullContext here
        }
    }
}

【讨论】:

  • 我的项目活动是在 Java 中,我的库是在 Kotlin 中,所以请编辑您的代码
  • @Bandy,给你。请记住 interface ContextAccessor 是在库中定义的,因此它可以被其他依赖于库的项目使用!
  • 没什么大不了的。将接口中定义的 getApplicationContext() 函数重命名为其他名称,例如:getAppContext()。如果你在某个地方实现了它,也可以在那里重命名。
  • 我的错误。在 Java 中,接口在实现时应该在“实现”一词之后枚举。答案已更新。
  • 在您的活动中实现接口。按照我的例子。 '@Override public Application getAppContext() { return super.getApplication(); }'
【解决方案2】:

您可以将在两个模块中使用的类移动到另一个(第三个模块),并在您的应用模块和您想要的另一个模块中使用它。

在应用模块中: 实施项目(":third")

在第二个模块中: 实施项目(":third")

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-23
    • 2013-06-15
    • 2019-07-15
    相关资源
    最近更新 更多