"singleton" pattern method best way in kotlin - android

Can someone help me to find a better way to create a single instance in Kotlin?
class Bar(private val blub) {
private lateinit var foo: FooService
private lateinit var doo: DooService
override fun getFooService(): FooService {
if (!::foo.isInitialized) {
foo = FooService(blub)
}
return foo
}
override fun getDooService(): DooService {
if (!::doo.isInitialized) {
doo = DooService(blub)
}
return doo
}
}
Edit:
I don't want to init every object at beginning - should be only done when needed.
Thanks in advance!

If your FooService doesn't take any parameters via the getter for its initialization, you can use an object for this:
object FooHolder {
val foo: FooService = FooService(...)
}
Otherwise, your pattern seems just fine, the alternative would be to use a nullable variable instead of lateinit, but they're essentially the same:
private var foo: FooService? = null
override fun getService(): FooService {
if (foo == null) {
foo = FooService(...)
}
return foo!!
}

Your class is not looking as singleton. Maybe you want something like this
class Bar(private val blub) {
var foo by lazy{ FooService(blub) }
}
OR you can put it in companion object to have the same instance between all objects

Related

Correct flow between Kotlin, Realm and ViewModels using Coroutines

Disclaimer: This is not actual code from any app, but an example of the flow and my current understanding on how best to do this. I am looking for help improving upon or what I am doing wrong.
I am trying to figure out the best way to structure an android application using the new jetpack viewModels, realm, and coroutines. I put together a gist of the flow that I have so far, and would love some feedback on how I can improve, what I could change, or what I am doing wrong. Ideally with examples or direct changes to my code.
It works as is, I am just not sure if I am using coroutines correctly or efficiently, and if there is a better way to structure the DAO's so that Realm can be injected for better testability. Someone has already mentioned changing the DAO to extend the LiveData<>, and using onActive() and onInactive() for posting the object. Is that a good idea?
// About Model is the model used by Realm. These models contains realm specific types, like RealmList
open class AboutModel(
var name: String = "",
#PrimaryKey
var version: String = ""
): RealmObject() {
/**
* Conversion function, to convert the view model layer object to the data layer object
*/
companion object {
fun from(about: About): AboutModel = AboutModel(about.name, about.version)
}
fun toObject(): About =
About(
this.name,
this.version
)
}
// About class used everywhere outside of the data/realm layer.
// Lines up with the AboutModel class, but free of realm or any other database specific types.
// This way, realm objects are not being referenced anywhere else. In case I ever need to
// replace realm for something else.
class About (val name: String = "Test", val version: String = "1.0.0") {
override fun toString(): String {
return "author is : $name, version is: $version"
}
}
// Couldn't inject the realm instance because its thread would not match with a suspend function.
// Even if both where background threads. Would be better if I could inject it, but couldn't get
// that to work.
class AboutDao() {
private val _about = MutableLiveData<About>()
init {
val realm = Realm.getDefaultInstance()
val aboutModel = realm.where(AboutModel::class.java).findFirst()
_about.postValue(aboutModel?.toObject() ?: About())
realm.close()
}
suspend fun setAbout(about: About) = withContext(Dispatchers.IO) {
val realm: Realm = Realm.getDefaultInstance()
realm.executeTransaction {
realm.copyToRealmOrUpdate(AboutModel.from(about))
_about.postValue(about)
}
realm.close()
}
fun getAbout() = _about as LiveData<About>
}
// Database is a singleton instance, so there is only ever one instance of the DAO classes
class Database private constructor() {
var aboutDao = AboutDao()
private set
companion object {
// #Volatile - Writes to this property are immediately visible to other threads
#Volatile private var instance: Database? = null
suspend fun getInstance() = withContext(Dispatchers.IO) {
return#withContext instance ?: synchronized(this) {
instance ?: Database().also { instance = it }
}
}
}
}
// Repo maintains the dao access. Is also setup to run as a singleton
class AboutRepo private constructor(private val aboutDao: AboutDao){
// This may seem redundant.
// Imagine a code which also updates and checks the backend.
suspend fun set(about: About) {
aboutDao.setAbout(about)
}
suspend fun getAbout() = aboutDao.getAbout()
companion object {
// Singleton instantiation you already know and love
#Volatile private var instance: AboutRepo? = null
fun getInstance(aboutDao: AboutDao) =
instance ?: synchronized(this) {
instance ?: AboutRepo(aboutDao).also { instance = it }
}
}
}
// Injector is used to help keep the injection in a single place for the fragments and activities.
object Injector {
// This will be called from About Fragment
suspend fun provideAboutViewModelFactory(): AboutViewModelFactory = withContext(Dispatchers.Default) {
AboutViewModelFactory(getAboutRepo())
}
private suspend fun getAboutRepo() = withContext(Dispatchers.IO) {
AboutRepo.getInstance(Database.getInstance().aboutDao)
}
}
// AboutViewModel's Factory. I found this code online, as a helper for injecting into the viewModel's factory.
class AboutViewModelFactory (private val aboutRepo: AboutRepo)
: ViewModelProvider.NewInstanceFactory() {
#Suppress("UNCHECKED_CAST")
override fun <T : ViewModel?> create(modelClass: Class<T>): T {
return AboutViewModel(aboutRepo) as T
}
}
// About Fragments ViewModel
class AboutViewModel(private val aboutRepo: AboutRepo) : ViewModel() {
suspend fun getAbout() = aboutRepo.getAbout()
suspend fun setAbout(about: About) = aboutRepo.set(about)
}
// Fragment's onActivityCreated, I set the viewModel and observe the model from the view model for changes
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
lifecycleScope.launch {
viewModel = ViewModelProviders.of(
this#AboutFragment,
Injector.provideAboutViewModelFactory()
).get(AboutViewModel::class.java)
withContext(Dispatchers.Main) {
viewModel.getAbout().observe(viewLifecycleOwner, Observer { about ->
version_number.text = about?.version
})
}
}
}

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

Accessing method from Application class in Kotlin 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()

Access Parent class variables in companion Object in Kotlin

I am trying to call static function of one class in other like java , But in kotlin I can not make a static function , and I have to make a companion object in which I have to define my function , But while doing this I am not able to access parent class variables , is there any way I can achieve this in kotlin .
class One {
val abcList = ArrayList<String>()
companion object {
fun returnString() {
println(abcList[0]) // not able to access abcList here
}
}
}
class Two {
fun tryPrint() {
One.returnString()
}
}
// In Java we can do it like this
class One {
private static ArrayList<String> abcList = new ArrayList<>();
public void tryPrint() {
// assume list is not empty
for(String ab : abcList) {
System.out.println(ab);
}
}
public static void printOnDemand() {
System.out.println(abcList.get(0));
}
}
class Two {
public void tryPrint(){
One.printOnDemand();
}
}
I want to access fun returnString() like static function of class one like we do in java , if any one have achieved this please help .
In your case abcList is a member variable of the class. Each instance of a class has their own version of its member variables which means that a static method cannot access them. If you want to access it from your companion object it has to be static too.
class One {
companion object {
val abcList = ArrayList<String>()
fun returnString() {
println(abcList[0])
}
}
}
class Two {
fun tryPrint() {
One.returnString()
}
}
This code will work, but keep in mind that in this case there will be only one instance of abcList. Accessing a member variable from a static function is not possible (not even in Java).
Here's the Kotlin version of your Java example:
class One {
companion object {
val abcList = ArrayList<String>()
fun printOnDemand() {
println(abcList[0])
}
}
fun tryPrint() {
for (ab in abcList) {
println(ab)
}
}
}
class Two {
fun tryPrint() {
One.printOnDemand()
}
}
Rule: You can't access static properties, members of a class in none static members and you can't access none static properties, members of a class in static members which is the companion object class.
This rule is in both Java and Kotlin. If you want to access a none static member of a class
inside static members you have to declare it inside companion object class.
Use the following code for you case.
object One {
val abcList: MutableList<String> = mutableListOf()
fun returnString() {
println(abcList[0])
}
fun printOnDemand() {
println(abcList[0]);
}
}
class Two {
fun tryPrint() {
One.printOnDemand()
}
}

Mocking another parameter on function not working when one of them is a callback interface

I successfully did some tests of asynchronous function with only one callback interface as parameter with mockito-kotlin library but when I try to do a test of same function with another parameter like a String or Integer I receive error:
org.mockito.exceptions.misusing.InvalidUseOfMatchersException:
Invalid use of argument matchers!
2 matchers expected, 1 recorded:
-> at com.example.presentation.presenter.MyCollectionPresenterTest.getComicListByHeroOK(MyCollectionPresenterTest.kt:97)
This exception may occur if matchers are combined with raw values:
//incorrect:
someMethod(anyObject(), "raw String");
When using matchers, all arguments have to be provided by matchers.
For example:
//correct:
someMethod(anyObject(), eq("String by matcher"));
For more info see javadoc for Matchers class.
I´m sure I´m mocking properly callback interface with any() but I don´t know if I´m mocking integer parameter correctly. I tried with any(), anyInt(), eq(1) and any() as Int but always the same error.
Here is the class that I want to test:
#PerFragment
class MyCollectionPresenter #Inject constructor(private val useCase: GetComicListByHeroUseCase) {
#Inject
lateinit var view: MyCollectionView
lateinit var models: List<ComicModel>
fun getComicListByHero(heroId: Int) {
useCase.execute(heroId, object : HeroUseCase.GetComicListByHeroCallback {
override fun onComicListReceived(comicList: List<Comic>) {
models = ComicModelMapper.toModel(comicList)
view.setItems(models)
}
override fun onError() {
view.showMessage()
}
})
}
}
And this is the test class:
class MyCollectionPresenterTest : UnitTest() {
private lateinit var presenter: MyCollectionPresenter
#Mock
private lateinit var useCase: GetComicListByHeroUseCase
#Mock
private lateinit var view: MyCollectionView
#Before
fun setUp() {
presenter = MyCollectionPresenter(useCase)
initializeView()
}
#Test
fun getComicListByHeroOK() {
setupGetComicsCallbackOK()
presenter.getComicListByHero(any())
verify(presenter.view).setItems(emptyList())
}
#Test
fun getComicListByHeroError() {
setupGetComicsCallbackError()
presenter.getComicListByHero(any())
verify(presenter.view).showMessage()
}
private fun initializeView() {
presenter.view = view
}
private fun setupGetComicsCallbackError() {
doAnswer {
val callback = it.arguments[0] as HeroUseCase.GetComicListByHeroCallback
callback.onError()
null
}.`when`(useCase).execute(any(), any())
}
private fun setupGetComicsCallbackOK() {
doAnswer {
val callback = it.arguments[0] as HeroUseCase.GetComicListByHeroCallback
callback.onComicListReceived(emptyList())
null
}.`when`(useCase).execute(any(), any())
}
}
This is base unit test class:
#RunWith(MockitoJUnitRunner::class)
abstract class UnitTest {
#Suppress("LeakingThis")
#Rule
#JvmField
val injectMocks = InjectMocksRule.create(this#UnitTest)
}
And this is a class for inject mocks rule:
class InjectMocksRule {
companion object {
fun create(testClass: Any) = TestRule { statement, _ ->
MockitoAnnotations.initMocks(testClass)
statement
}
}
}
Thank you very much for your help and excuse my english.
Regards!
UPDATE: I found the solution and posted as answer.
Finally, I know what I was doing wrong. First at all, it.argument[1] because callback is the second parameter of the function that I want to mock the answer.
And the other thing is that I was mocking the parameter of the function that I want to test presenter.getComicListByHero(1).
Here is the revised code:
#Test
fun getComicListByHeroError() {
setupGetComicsCallbackError()
presenter.getComicListByHero(1)
verify(presenter.view).showMessage()
}
private fun setupGetComicsCallbackError() {
doAnswer {
val callback = it.arguments[1] as HeroUseCase.GetComicListByHeroCallback
callback.onError()
null
}.`when`(useCase).execute(ArgumentMatchers.anyInt(), any())
}
Thank you very much to #voghDev for his help

Categories

Resources