1

My MainActivity begins like this:

class MainActivity : AppCompatActivity() {
val mDBAdapter = DBAdapter(this, "nearbydata")

I want to use the database adapter in another class PickFromList (which extends ListActivity).

I don't seem to be able to refer to it as MainActivity.mDBAdapter. I understand that this is because there are no instances of the MainActivity class.

According to How to reference the current or main activity from another class this is "a problem that lots of developers have". The top answer in that thread reads

If you already have a valid context, just use this: Activity activity = (Activity) context;

Unfortunately to someone as inexperienced as me that is not helpful. How do I know whether I have a valid context? If I don't have one how do I get one?

If I try pasting that code into my PickFromList class, Quick Fix tells me that it "cannot resolve symbol 'context'" and offers to create a local variable 'context'. But that doesn't help.

prepbgg
  • 3,454
  • 9
  • 35
  • 46

1 Answers1

1

You should't refer from one activity to another because it can cause memory leaks and crashes (https://android.jlelse.eu/9-ways-to-avoid-memory-leaks-in-android-b6d81648e35e) Then you should share this DBAdapter instance via global state or with dependency injection. And in this case you can use application context to instantiate DBAdapter. For example you could use you App class

class App : Application() {

    companion object {
        lateinit var adapter: DBAdapter
    }

    override fun onCreate() {
        super.onCreate()
        adapter = DBAdapter(this)
    }
}

It's safe because you have just one instance of App class and therefore one Application Context. And after this you can use adapter like App.adapter in your activities.

But this is rough solution. Better way is providing you dependencies via Dependency injection (https://developer.android.com/training/dependency-injection)

ZSergei
  • 708
  • 7
  • 17
  • Thanks very much for your very helpful reply. I wasn't sure, when you referred to my App class, whether this is something that would have been automatically created by Android Studio. I assumed it was not, so added a new Kotlin file and pasted in your App class code, and it worked! This seems to be an effective way of creating global variables. I have read somewhere that it's not recommended, but no reason was offered as to why it was not recommended. I hope to look at Dependency injection in due course, but at the moment this feels like a step too far in my shallow learning curve! – prepbgg Jun 06 '20 at 09:47
  • 1
    More about App classes https://github.com/codepath/android_guides/wiki/Understanding-the-Android-Application-Class. There is nothing wrong in global variables, but if you use them carelessly you can get poor app design that hard to test and maintain. It's a very easy to use global variables - that's why they spread across all yours codebase. But if you pass this global variables via constructor your class would't depend on them and you can easily test it. That is main idea of Dependency injection. – ZSergei Jun 06 '20 at 10:05
  • When I replied earlier that the amended code worked I was relying on the fact that Android Studio no longer indicated any errors. Only now have I tried running the app and have found that it stops with an error at the line in my main activity reading "val mDBAdapter = App.adapter". Logcat says Caused by: kotlin.UninitializedPropertyAccessException: lateinit property adapter has not been initialized at com.example.nearby.App$Companion.getAdapter(App.kt:9) at com.example.nearby.MainActivity.(MainActivity.kt:31). Do I have to create an instance of the App class? – prepbgg Jun 06 '20 at 16:17
  • I tried changing the code in MainActivity to insert val myApp = App and change the existing line to val mDBAdapter = myApp.adapter but this failed with the same error. – prepbgg Jun 06 '20 at 16:21
  • 1
    No, you should't instantiate App class. You only need register it on AndroidManifest (https://stackoverflow.com/questions/2929562/register-application-class-in-manifest) – ZSergei Jun 06 '20 at 16:25
  • I'm sorry to keep coming back, but I'm afraid I don't understand from that thread (or others I've read) exactly how to amend the manifest. I've tried putting after the main block, but Android Studio says "Attribute android:name is not allowed here.". I've tried putting android:name="com.example.nearby.App" inside the block after the block but that says "unexpected text found in layout file". – prepbgg Jun 06 '20 at 17:42
  • 1
    Yours Manifest.xml file should contain only one block. And in this block you should specify name attribute ` – ZSergei Jun 06 '20 at 18:06