1

So I have a (Kotlin) data class that gets instantiated in my startup activity (we'll just call the object dataObj). I have two other activities that need access to the dataObj that was instantiated on startup. I know I could have my data class implement the Serializable interface so that I could pass the object between the three activities using intents. But I also have been thinking that I could use a static variable in the constructor so that I could easily just grab the values for the class. I'm just trying to figure out what is recommended and what is good practice.

Slaknation
  • 1,604
  • 2
  • 15
  • 30

4 Answers4

1

One big issue with this is that static variables don't survive Android low-memory state, but sending intent between survives. Also read here about static variable. (Link)

Dmytro Ivanov
  • 1,189
  • 1
  • 7
  • 10
  • Technically they don't survive, but you CAN save them to `onSaveInstanceState` bundle, it's just that all activities need to do it, and should only be restored *once* (if app is starting but the first `savedInstanceState` is `!= null`). – EpicPandaForce Dec 22 '18 at 21:53
1

You have two options here:

  1. Send it via Intent after implementing Serializable or Parcelable by you data class,
  2. Save your data object to .txt file and read it when you need it.

static it is not created for this kind of things and You shouldn't use it in this case.

In my opinion You should go with first option.

DawidJ
  • 1,159
  • 11
  • 19
  • What about a singleton? I am beginning to think that a Singleton might be a good option (thanks tomerpacific) – Slaknation Dec 22 '18 at 21:01
  • that only works right/correctly if you save it to `onSaveInstanceState` in `BaseActivity` and restore it only once when app starts but `savedInstanceState != null` – EpicPandaForce Dec 22 '18 at 21:53
  • You can use it also but the question is, is it not a overkill for Your needs? https://en.wikipedia.org/wiki/Overengineering – DawidJ Dec 22 '18 at 21:57
1

It really depends on your use case, but I'd generally recommend against static implementations (to include singletons, see What is so bad about singletons?). They become hard to test adequately over time and can (in short) lead to many other problems depending on implementation.

If it is a relatively simple object where state change is rare, only done in one Activity at a time, and/or irrelevant, implementing a Parcelable and passing that to each Activity via an Intent is probably best.

If this is a complex object or an object that can change dynamically, the preferable solution would be to use a dependency injection platform (such as Koin if you're using Kotlin) to instantiate the data and provide it as a dependency. Koin is pretty straight forward, a very basic implementation from the Koin website (and missing just a few lines to be complete):

// Injected by constructor
class MyViewModel(val repo : MyRepository) : ViewModel()

// declared ViewModel using the viewModel keyword
val myModule : Module = module {
  viewModel { MyViewModel(get()) } 
  single { MyRepository() }
}

// Just get it
class MyActivity() : AppCompatActivity() {

  // lazy inject MyViewModel
  val vm : MyViewModel by viewModel()
}

In this case, your object would be something like MyRepository() in the example. You'd just have to add the startKoin([list of modules]) from there. If you wanted MyRepository() in your Activity you'd include it like val myRepo: MyRepository by inject(). I don't know if this is outside the scope of your project though, it all depends on what you're trying to do exactly.

Dan 0
  • 737
  • 6
  • 14
0

This isn't the best method (although there really isn't a perfect way to do this), but you could instantiate it in a custom Application class.

class App : Application() {

    val yourObject by lazy { YourObject() } //by lazy is useful if the Object needs to hold a Context or something that isn't immediately available

}

Add android:name=".App" to the application tag in your manifest so your App class is actually used. .App assumes it's in the root of your application package.

Then, from anywhere you have a reference to a Context, you can do something like:

(context.applicationContext as App).yourObject

to access the Object.

TheWanderer
  • 13,765
  • 5
  • 37
  • 54