Access main project from module in Android Studio?
"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
}
}
}