Accessing method from Application class in Kotlin Android - android

I have created an application class in Kotlin. I need to access a method that returns a variable from anywhere in my application. The problem is I am not able to access that method from other parts of the program. I am able to access when code is written in Java , but when code is written in Kotlin,then the method in Application class is not accessible. Please find below code for reference:
class MyRetroApplication : Application() {
lateinit var apiComponent:APIComponent
companion object {
var ctx: Context? = null
}
override fun onCreate() {
super.onCreate()
ctx = applicationContext
apiComponent = initDaggerComponent()
}
fun getMyComponent(): APIComponent {
return apiComponent
}
fun initDaggerComponent():APIComponent{
apiComponent = DaggerAPIComponent
.builder()
.aPIModule(APIModule(APIURL.BASE_URL))
.build()
return apiComponent
} }
In the above code how to access the function getMyComponent() globally in Kotlin.

Put getMyComponen() inside companion like #Md. Asaduzzaman answer or use applicationContext to access it like -
(application as MyRetroApplication).getMyComponent()
or
(applicationContext as MyRetroApplication).getMyComponent()
or
MyRetroApplication.ctx?.let{
(it as MyRetroApplication).getMyComponent() //by your companion app context
}

Approach-1:
Put getMyComponent() inside companion
companion object {
var ctx: Context? = null
private lateinit var apiComponent: APIComponent
fun getMyComponent(): APIComponent = apiComponent
}
And then from anywhere:
MyRetroApplication.getMyComponent()
Approach-2:
Change the type of ctx to MyRetroApplication instead of Context and then from anywhere:
MyRetroApplication.ctx.getMyComponent()
Approach-3:
Same as approach 2 but in a formal way. Create getInstance() inside companion and pass ctx (private)
companion object {
private lateinit var ctx: MyRetroApplication
fun getInstance(): MyRetroApplication {
return ctx
}
}
And then from anywhere:
MyRetroApplication.getInstance().getMyComponent()

Related

Call Application context in Activity

I'm trying to call my database (made with Room) from an activity on Android, but it needs the application context, and if I passed "application : Application" in the constructor of my Activity, the build crash and tell me :
java.lang.Class<com.exemple.instabus.PhotoActivity> has no zero argument constructor
Here is my code :
class PhotoActivity(application: Application) : AppCompatActivity() {
private val pictureDao = PictureDatabase.getDatabase(app)
//Some code ....
I need a context, i've tried to pass "this" but i got another error
Can someone give me some help please, I'm a beginner in this technology
EDIT:
Here is my database class, just to show you why I need an Application Context
#Database(entities = [Picture::class], version = 1, exportSchema = false)
abstract class PictureDatabase : RoomDatabase(){
abstract fun pictureDao() : PictureDao
companion object{
#Volatile
private var INSTANCE : PictureDatabase? = null
fun getDatabase(context: Context): PictureDatabase {
if(INSTANCE == null){
synchronized(this){
INSTANCE = Room.databaseBuilder(
context.applicationContext,
PictureDatabase::class.java,
"pictures.db"
).build()
}
}
return INSTANCE!!
}
}
}
Activity is something we do declare in the manifest and then start them using intent, However, the creation of an instance of an activity is done by the system and not by us. An instance is created using constructor, but if it is us then we can have any number of overloaded constructors. But the system needs only one constructor which should be a zero parameter constructor and it should be public.
So your activity signature
class PhotoActivity(application: Application) : AppCompatActivity() {
should be changed to
class PhotoActivity() : AppCompatActivity() {
To call the fun getDatabase(context: Context): PictureDatabase you can pass this from the activity. Activity is an indirect child of Context.
You can do it in the following ways,
private val pictureDao by lazy{ PictureDatabase.getDatabase(this) }
private lateinit var pictureDao:PictureDatabase
then in onCreate() initialize it
final override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.your_layout)
PictureDatabase.getDatabase(this)
//your logic goes here
}
First create a ViewModel, and inside the ViewModel you can access the your Dao, pictureDao.
class PictureViewModel(application: Application) :
AndroidViewModel(application) {
val pictureDao: PictureDao
init {
pictureDao =
PictureDatabase.getDatabase(application).pictureDao()
}
}
Then in your activity, initialize the ViewModel. And access your Dao.
class PhotoActivity : AppCompatActivity() {
private lateinit var pictureViewModel: PictureViewModel
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_photo)
pictureViewModel =
ViewModelProviders.of(this).get(PictureViewModel::class.java)
//You can now access your Dao class here:
val pictureDao = pictureViewModel.pictureDao
}
}
You should not pass Application to the constructor. You should pass applicationContext to getDatabase(), like private val pictureDao = PictureDatabase.getDatabase(applicationContext)

How i can use context in Singleton?

I need in my Singleton -> Context. I know that I can't passing argument in constructor, because object hasn't constructor.
Then I call it from my Application class.
Here is the code:
object Singleton {
var userAgentInfo: String = UserAgentTools.buildUserAgent(context)
fun initializeSdk() {
AuthenticatorApiManager.initializeSdk(userAgentInfo)
}
}
Move the initialization of userAgentInfo to the initializeSDK method, and send the Context as an argument, make sure to send the ApplicationContext.
object Singleton {
var userAgentInfo: String? = null
fun initializeSdk(context: Context) {
userAgentInfo = UserAgentTools.buildUserAgent(context)
AuthenticatorApiManager.initializeSdk(userAgentInfo)
}
}
Make Application class and write below code.
companion object {
private lateinit var sInstance: ApplicationClass
fun getInstance(): ApplicationClass {
return sInstance
}
}
Use in object like below.
ApplicationClass.getInstance()
You can use context in your Singleton class using Application class instance.here it is

Access application context in companion object in kotlin

How can we access application context inside companion object in Android kotlin?
I have a companion object inside an abstract class and I want to access context to read Shared Preferences, but I'm not able to get the context.
UPDATE: I'm working with this stuff in an Android library and also the class that I'm working in is abstract
please see this go to link
class MainApplication : Application() {
init {
instance = this
}
companion object {
private var instance: MainApplication? = null
fun applicationContext() : Context {
return instance!!.applicationContext
}
}
override fun onCreate() {
super.onCreate()
// initialize for any
// Use ApplicationContext.
// example: SharedPreferences etc...
val context: Context = MainApplication.applicationContext()
}
}
Extends Application class like this
import android.app.Application
import android.content.Context
class MyApplication : Application() {
override fun onCreate() {
super.onCreate()
MyApplication.appContext = applicationContext
}
companion object {
lateinit var appContext: Context
}
}
then get context like this
val context = MyApplication.appContext
Actually I'm working inside an Android library and the class is abstract, so can't go with the already suggested solutions. However, I found way to do that.
Creat a lateinit Context field inside companion object.
abstract class MyClass {
companion object {
private lateinit var context: Context
fun setContext(con: Context) {
context=con
}
}
}
And then set it after the app has started
public class WelcomeActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_welcome);
MyClass.Companion.setContext(this);
}
}
There is a super cool article from the guys from Firebase explaining how their SDK gets hold of the context.
Basically my contentprovider looks like this:
/**
* This content provider is only responsible to inject the application context into the common module.
*/
class ContextProvider : ContentProvider() {
companion object {
private val TAG = ContextProvider::class.java.simpleName
}
override fun onCreate(): Boolean {
context?.let {
Common.setContext(it)
return true
}
Logger.e(TAG, "Context injection to common failed. Context is null! Check ContextProvider registration in the Manifest!")
return false
}
override fun query(uri: Uri, projection: Array<String>?, selection: String?, selectionArgs: Array<String>?, sortOrder: String?): Cursor? = null
override fun getType(uri: Uri): String? = null
override fun insert(uri: Uri, values: ContentValues?): Uri? = null
override fun delete(uri: Uri, selection: String?, selectionArgs: Array<String>?): Int = 0
override fun update(uri: Uri, values: ContentValues?, selection: String?, selectionArgs: Array<String>?): Int = 0
}
And the Common object, which I treat like an sibling of any Application class looks like this:
/**
* Partially working like an Application class by holding the appContext which makes it accessible inside this module.
*/
#SuppressLint("StaticFieldLeak")
object Common {
/**
* App appContext
*/
#Volatile
lateinit var appContext: Context
var isStoreVersion: Boolean = false
fun setContext(context: Context) {
appContext = context
}
}
As you can see I also enriched the Common object with a flag to store if the current build is a store version or not. Mainly because the BuildConfig of the app module is also not available in a module or library.
Don't forget to add the ContentProvider to the AndroidManifest of your library within the <application> tag
<provider android:name=".util.ContextProvider"
android:authorities="${applicationId}.common.util.contextprovider"
android:exported="false" />
You can save the instance directly inside a companion object and accessing it outside without problems, I think this approach is the simplest.
IMPORTANT: change the visibility of the instance property to private to ensure no one but Application has write access.
class App : Application() {
override fun onCreate() {
super.onCreate()
instance = this
}
companion object {
lateinit var instance: App
private set
}
}
class Test {
companion object {
lateinit var sharedPreferences: SharedPreferences
fun init(context: Context) {
// to prevent multiple initialization
if (!Companion::sharedPreferences.isInitialized) {
sharedPreferences = context.getSharedPreferences("preference_name", Context.MODE_PRIVATE)
}
}
}
}

Static like methods in Android application with kotlin

I am trying to add a "static" method to my MyApplication class in kotlin
I have added (as a property) the variable :
private var context: Context? = null
in method:
override fun onCreate()
I added:
context = applicationContext
then I add a companion object like this
companion object {
#JvmStatic fun getMyApplicationContext(): Context?
{
return MyApplication().context
}
}
when I call this method from other parts of the application like
MyApplication.getMyApplicationContext() it always returns null. I have gleaned all this from several sources but I am not sure if it is anywhere near correct or not.
It sounds like you want a global application context object. Now casting aside my dislike for global variables, I think you are pretty close.
I think you just need to add the variable into the MyApplication classes companion object and use that directly. You only need the #JvmField annotation if you're going to access the field from Java.
class MyApplication {
companion object {
#JvmField
var context: Context? = null
// Not really needed since we can access the variable directly.
#JvmStatic fun getMyApplicationContext(): Context? {
return context
}
}
override fun onCreate() {
...
MyApplication.context = appContext
}
}

Kotlin singleton application class

On Android I want to make my application class a singleton.
Making it like this:
object MyApplication: Application(){}
won't work. The following error is thrown at runtime:
java.lang.IllegalAccessException: private com....is not accessible from class android.app.Instrumentation.
Doing this is also not possible:
class MyApp: Application() {
private val instance_: MyApp
init{
instance_ = this
}
override fun onCreate() {
super.onCreate()
if (BuildConfig.DEBUG) {
Timber.plant(Timber.DebugTree());
}
}
companion object{
fun getInstance() = instance_
}
}
How can I get an instance of my application class everywhere in my app? I would like to use MyApp.instance() instead of (applicationContext as MyApp).
Also an explanation why I want this: I have classes in my app. For example, a SharedPreference Singleton which is initialised with a context, and as it’s a singleton, it can't have arguments.
You can do the same thing you would do in Java, i.e. put the Application instance in a static field. Kotlin doesn't have static fields, but properties in objects are statically accessible.
class MyApp: Application() {
override fun onCreate() {
super.onCreate()
instance = this
}
companion object {
lateinit var instance: MyApp
private set
}
}
You can then access the property via MyApp.instance.
If you want to use it to access some static properties you have there: You will only have one instance of your Application, so simply use the name you gave to the class. Don't worry about it not being an actual singleton, you can use it the same way.
Example:
class MyApp : Application() {
companion object {
const val CONSTANT = 12
lateinit var typeface: Typeface
}
override fun onCreate() {
super.onCreate()
typeface = Typeface.createFromAsset(assets, "fonts/myFont.ttf")
}
}
Then you can use MyApp.CONSTANT and MyApp.typeface anywhere in your app.
-
If what you want is to use it as an application context you can create an extension property for Context:
val Context.myApp: MyApp
get() = applicationContext as MyApp
Then you can use myApp to get the the application context anywhere you have a context.
class AppController : Application() {
init {
instance = this
}
companion object {
private var instance: AppController? = null
fun applicationContext() : AppController {
return instance as AppController
}
}
override fun onCreate() {
super.onCreate()
}
}
You cannot do that because Android creates an Application instance using its parameterless constructor.
The problem you want to solve can be easily solved with DI. Just create instances with an injector so that the Context can be injected into objects as a dependency.

Categories

Resources