英文:
Access main project from module in Android Studio?
问题
我正在使用这个库,我已经将其作为模块本地安装。我可以通过我的主项目访问它,但反之则不行。例如,无法从这个库中访问我的主项目中的变量...
我尝试在库的build.gradle
中添加以下行:
implementation project(':app')
但我收到了这个奇怪的错误:
以下任务之间存在循环依赖关系:
:placepicker:generateDebugRFile
\--- :placepicker:generateDebugRFile (*)
(*) - 详细信息已省略(在先前列出)
我该如何解决这个问题?我的项目是用Java编写的,我的库是用Kotlin编写的。
英文:
I am using this library which I have installed locally as a module. I'm able to access it via my main project, but I'm not able to do the opposite. For example, access a variable in my main project from this library...
I tried adding this line in the library's build.gradle
:
implementation project(':app')
But I get this weird error:
Circular dependency between the following tasks:
:placepicker:generateDebugRFile
\--- :placepicker:generateDebugRFile (*)
(*) - details omitted (listed previously)
How can I fix this? My project is in Java and my library is in Kotlin
答案1
得分: 3
"Circular dependency" 只能通过在两者之一上移除导致此问题的依赖关系来解决。
如果您需要从库代码中访问某些数据,您可以在库中实现一个接口,该接口将由项目中的某个类扩展。然后,您将能够在库中使用扩展的类,并访问接口中定义的方法。
示例
假设您需要在库中获取对应用程序上下文的引用。您应该创建一个接口:
interface ContextAccessor {
// 将其标记为可选,以防万一
// 无法从实现ContextAccessor的对象中获取上下文
fun getApplicationContext(): Application?
}
因为您将库添加为项目的依赖项,所以您可以访问ContextAccessor
。扩展某个类以实现这个接口并实现getApplicationContext
方法。假设您想扩展某个Activity
。
class MyActivity: Activity, ContextAccessor {
...其他代码在这里
override fun getApplicationContext(): Application? = application
}
现在,在MyActivity
类内部,您可以将ContextAccessor
设置到库中,就像它是依赖注入一样。
class MyActivity: Activity, ContextAccessor {
...其他代码在这里
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val someLibraryClassInstance = SomeLibraryClass()
someLibraryClassInstance.setContextAccessor(this)
// 或者 -> `someLibraryClassInstance.contextAccessor = this`
}
}
警告:当您保存对任何Android组件的引用时,特别是Activity、Fragment、Dialog等等,请确保在对象即将销毁时删除此引用,以避免内存泄漏。
从上一个代码段中稍微修改的代码的删除引用示例:
class MyActivity: Activity, ContextAccessor {
...其他代码在这里
private val someLibraryClassInstance = SomeLibraryClass()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// 将ContextAccessor引用设置给某个库类
someLibraryClassInstance.setContextAccessor(this)
}
override fun onDestroy() {
super.onDestroy()
// 非常重要!
someLibraryClassInstance.setContextAccessor(null)
// 或者创建一些方法,比如 `someLibraryClassInstance.removeContextAccessor(this)`
}
}
在Java中相同的类
interface ContextAccessor {
// 将其标记为可选,以防万一
// 无法从实现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引用设置给某个库类
someLibraryClassInstance.setContextAccessor(this);
}
@Override
protected void onDestroy() {
super.onDestroy();
// 非常重要!
someLibraryClassInstance.setContextAccessor(null);
// 或者创建一些方法,比如 `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?.getApplicationContext()?.let { nonNullContext ->
// 在这里使用非空的上下文
}
}
}
英文:
"Circular dependency" can be fixed only by removing dependency that causes this issue on one of two sides.
If you need to access some data from the library code you can implement an interface in a library that will be extended by some class in your project. Then you will be able to use extended class in your library and access methods defined in the interface.
Example
Let's imagine you need to get a reference to the application context within your library. You should create an interface:
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?
}
Because you added the library as a dependency in your project you have access to ContextAccessor
. Extend some class with this interface and implement the getApplicationContext
method. Let's say you want to extend some Activity
.
class MyActivity: Activity, ContextAccessor {
... other code here
override fun getApplicationContext(): Application? = application
}
Now from within your MyActivity
class, you can set ContextAccessor
into your library as if it was 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`
}
}
WARNING: when you save a reference to any Android component, especially Activity, Fragment, Dialog etc., make sure you later remove this reference when the object is going to be destroyed to avoid memory leaks.
An example of how to remove a reference on a little bit modified code from the previous code snippet:
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)`
}
}
Same classes in 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();
}
}
Update (10 aug 2020): how to use ContextAccessor?
Here is how you can use ContextAccessor
in your library:
class SomeLibraryClass {
private var mContextAccessor: ContextAccessor?
fun setContextAccessor(contextAccessor: ContextAccessor?) {
mContextAccessor = contextAccessor
}
fun someOtherMethod() {
mContextAccessor?.getAppContext()?.let { nonNullContext ->
// use nonNullContext here
}
}
}
答案2
得分: 2
在应用模块中:
implementation project(":third")
在第二模块中:
implementation project(":third")
英文:
You can move your classes that used in both modules to another (third module) and use it in your app module and another module you want.
in app module:
implementation project(":third")
in second module:
implementation project(":third")
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论