Hilt is converting a public field to private and failing to inject - android

I'm trying to learn Hilt and am getting the error "Dagger does not support injection into private fields". But the field in question isn't private in the original Kotlin. It's only private when it's converted to Java. Why is this? How can I correct it?
Original Kotlin file:
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import androidx.lifecycle.ViewModelProvider
import com.example.vennwithnav.databinding.FragmentLoginBinding
import dagger.hilt.android.AndroidEntryPoint
import javax.inject.Inject
#AndroidEntryPoint
class LoginFragment : Fragment() {
#Inject public var profileViewModel: ProfileViewModel? = null
private var binding: FragmentLoginBinding? = null
Java file after conversion (accessed via the error):
package com.example.vennwithnav.ui.profile;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import androidx.fragment.app.Fragment;
import androidx.lifecycle.ViewModelProvider;
import com.example.vennwithnav.databinding.FragmentLoginBinding;
import dagger.hilt.android.AndroidEntryPoint;
import javax.inject.Inject;
#kotlin.Metadata(mv = {1, 4, 1}, bv = {1, 0, 3}, k = 1, d1 = {"\u0000:\n\u0002\u0018\u0002\n\u0002\u0018\u0002\n\u0002\b\u0002\n\u0002\u0018\u0002\n\u0000\n\u0002\u0018\u0002\n\u0002\b\u0005\n\u0002\u0010\u0002\n\u0000\n\u0002\u0018\u0002\n\u0000\n\u0002\u0018\u0002\n\u0000\n\u0002\u0018\u0002\n\u0000\n\u0002\u0018\u0002\n\u0002\b\u0002\b\u0007\u0018\u00002\u00020\u0001B\u0005\u00a2\u0006\u0002\u0010\u0002J\u0006\u0010\u000b\u001a\u00020\fJ&\u0010\r\u001a\u0004\u0018\u00010\u000e2\u0006\u0010\u000f\u001a\u00020\u00102\b\u0010\u0011\u001a\u0004\u0018\u00010\u00122\b\u0010\u0013\u001a\u0004\u0018\u00010\u0014H\u0016J\b\u0010\u0015\u001a\u00020\fH\u0016R\u0010\u0010\u0003\u001a\u0004\u0018\u00010\u0004X\u0082\u000e\u00a2\u0006\u0002\n\u0000R\u001a\u0010\u0005\u001a\u00020\u0006X\u0086\u000e\u00a2\u0006\u000e\n\u0000\u001a\u0004\b\u0007\u0010\b\"\u0004\b\t\u0010\n\u00a8\u0006\u0016"}, d2 = {"Lcom/example/vennwithnav/ui/profile/LoginFragment;", "Landroidx/fragment/app/Fragment;", "()V", "binding", "Lcom/example/vennwithnav/databinding/FragmentLoginBinding;", "profileViewModel", "Lcom/example/vennwithnav/ui/profile/ProfileViewModel;", "getProfileViewModel", "()Lcom/example/vennwithnav/ui/profile/ProfileViewModel;", "setProfileViewModel", "(Lcom/example/vennwithnav/ui/profile/ProfileViewModel;)V", "login", "", "onCreateView", "Landroid/view/View;", "inflater", "Landroid/view/LayoutInflater;", "container", "Landroid/view/ViewGroup;", "savedInstanceState", "Landroid/os/Bundle;", "onDestroyView", "app_debug"})
#dagger.hilt.android.AndroidEntryPoint()
public final class LoginFragment extends androidx.fragment.app.Fragment {
#org.jetbrains.annotations.NotNull()
private com.example.vennwithnav.ui.profile.ProfileViewModel profileViewModel; // this line is causing the error
private com.example.vennwithnav.databinding.FragmentLoginBinding binding;
#org.jetbrains.annotations.NotNull()
public final com.example.vennwithnav.ui.profile.ProfileViewModel getProfileViewModel() {
return null;
}
public final void setProfileViewModel(#org.jetbrains.annotations.NotNull()
com.example.vennwithnav.ui.profile.ProfileViewModel p0) {
}

One more google search found the answer. https://kotlinlang.org/docs/java-to-kotlin-interop.html#instance-fields
Adding #JvmField in front of var fixed the problem.
#Inject #JvmField var profileViewModel: ProfileViewModel? = null
per IR42, this works too, and is the used in the developer.android.com tutorials, so it's probably better.
#Inject lateinit var profileViewModel: ProfileViewModel

Related

I'm trying to follow MVVM architecture to hit api using Retrofit. I've got error saying unable to create call Adapter

I'm trying to follow MVVM pattern to fetch data from the given api but getting error while Initiating a connection. My application gets crashed showing the error in the logcat.
My ModalClass.kt
package com.example.retrofitdemo2.api
class ModelClass : ArrayList<ModelClassItem>()
ModelClassItem:
package com.example.retrofitdemo2.api
data class ModelClassItem(
val body: String,
val id: Int,
val title: String,
val userId: Int
)
RetrofitHelperClass.kt
package com.example.retrofitdemo2.api
import com.google.gson.GsonBuilder
import okhttp3.OkHttpClient
import okhttp3.logging.HttpLoggingInterceptor
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
class RetrofitHelperClass {
companion object {
private val BASE_URL = "https://jsonplaceholder.typicode.com/"
var interceptor = HttpLoggingInterceptor().apply {
this.level = HttpLoggingInterceptor.Level.BODY
}
var client = OkHttpClient.Builder().apply {
this.addInterceptor(interceptor)
}.build()
fun getInstance(): Retrofit {
return Retrofit.Builder().baseUrl(BASE_URL).client(client)
.addConverterFactory(GsonConverterFactory.create(GsonBuilder().create())).build()
}
}
}
RetrofitService.kt
package com.example.retrofitdemo2.api
import androidx.lifecycle.LiveData
import retrofit2.Response
import retrofit2.http.GET
interface RetrofitService {
#GET("/albums")
fun get(): LiveData<Response<ModelClass>>
}
Repository.kt: Here i'm getting errors which is mentioned at the end.
Seems like repository is unable to create Adapter call.enter code here
package com.example.retrofitdemo2.repository
import com.example.retrofitdemo2.api.RetrofitService
class Repositroy(retrofitService: RetrofitService) {
val response = retrofitService.get()
}
viewmodel.kt:
package com.example.retrofitdemo2.viewmodel
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.example.retrofitdemo2.api.ModelClass
import com.example.retrofitdemo2.api.ModelClassItem
import com.example.retrofitdemo2.repository.Repositroy
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
class MainViewModel(repositroy: Repositroy) : ViewModel() {
var getdata = repositroy.response
}
MainViewModelFactory.kt:
package com.example.retrofitdemo2.viewmodel
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import com.example.retrofitdemo2.repository.Repositroy
class MainViewModelFactory(private val repositroy: Repositroy) :
ViewModelProvider.Factory
{
override fun <T : ViewModel> create(modelClass: Class<T>): T {
if (modelClass.isAssignableFrom(MainViewModel::class.java)){
return MainViewModel(repositroy) as T
}
throw IllegalArgumentException("Problem in View Model Factory")
}
}
MainActivity.kt:
package com.example.retrofitdemo2
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
import androidx.databinding.DataBindingUtil
import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModelProvider
import com.example.retrofitdemo2.api.RetrofitHelperClass
import com.example.retrofitdemo2.api.RetrofitService
import com.example.retrofitdemo2.databinding.ActivityMainBinding
import com.example.retrofitdemo2.repository.Repositroy
import com.example.retrofitdemo2.viewmodel.MainViewModel
import com.example.retrofitdemo2.viewmodel.MainViewModelFactory
import retrofit2.Retrofit
class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
private lateinit var viewmodel : MainViewModel
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = DataBindingUtil.setContentView(this, R.layout.activity_main)
var retorservice =
RetrofitHelperClass.getInstance().create(RetrofitService::class.java)
val repositroy = Repositroy(retorservice)
val factory = MainViewModelFactory(repositroy)
viewmodel = ViewModelProvider(this, factory).get(MainViewModel::class.java)
binding.viewmodel = viewmodel
binding.lifecycleOwner = this
viewmodel.getdata.observe(this, Observer {
Log.i("MainActivity", "${it}")
})
}
}
Error:
Unable to start activity
ComponentInfo{com.example.retrofitdemo2/com.example.retrofitdemo2.MainActivity}:
java.lang.IllegalArgumentException: Unable to create call adapter for
androidx.lifecycle.LiveData<retrofit2.Response<com.example.retrof
at com.example.retrofitdemo2.repository.Repositroy.<init>(Repositroy.kt:7)
at com.example.retrofitdemo2.MainActivity.onCreate(MainActivity.kt:28)
at android.app.Activity.performCreate(Activity.java:8109)
at android.app.Activity.performCreate(Activity.java:8083)

mockito is not working for sharedPreferences with instrumentedTest

I have three activity activityA, activityB and activityC.
whenever we will start app it will launch activityA and based on shared preferences (based on boolean value which we will receive from shared preferences.) it will start activityB or activityC with onCreate Activity lifecycle event
here is my test code
package com.panther_nine.t2_mini
import android.content.Context
import android.content.Intent
import android.content.SharedPreferences
import androidx.test.espresso.action.ViewActions.*
import androidx.test.espresso.assertion.ViewAssertions.*
import androidx.test.espresso.matcher.ViewMatchers.*
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.LargeTest
import androidx.test.rule.ActivityTestRule
import com.panther_nine.t2_mini.database.sharedPref.dao.AppDao
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.Mock
import org.mockito.Mockito.*
import org.mockito.MockitoAnnotations
#LargeTest
#RunWith(AndroidJUnit4::class)
class ActivityATest {
#Mock
private lateinit var mPreferences: SharedPreferences
#Mock
private lateinit var mContext: Context
#get:Rule
val activityRule = ActivityTestRule(MainActivity::class.java, true, false)
#Before
fun setup(){
MockitoAnnotations.initMocks(this)
`when`(mContext.getSharedPreferences(anyString(), anyInt())).thenReturn(mPreferences)
}
#Test
fun testEvent() {
`when`(mPreferences.getBoolean(anyString(), anyBoolean())).thenReturn(false)
activityRule.launchActivity(Intent())
}
}
whenever I am launching my code sharedPreferences always returnning "true". it mean that mocking is not working

pressBack() in espresso test is not working

I am a beginner to do the espresso test. I am using pressBack but it is not working it should return to the main activity from the second activity. The problem is that the press back is not working and due to this I get NoMatchingViewException. Can someone please help? I looked at different Solutions but I have not found an answer.
mport android.app.Activity
import android.app.Instrumentation
import android.content.Intent
import android.content.pm.ActivityInfo
import android.util.Log
import android.widget.TextView
import androidx.test.core.app.ActivityScenario
import androidx.test.espresso.Espresso.onView
import androidx.test.espresso.action.ViewActions
import androidx.test.espresso.action.ViewActions.*
import androidx.test.espresso.assertion.ViewAssertions.matches
import androidx.test.espresso.intent.Intents
import androidx.test.espresso.intent.matcher.IntentMatchers
import androidx.test.espresso.matcher.ViewMatchers.*
import androidx.test.ext.junit.rules.ActivityScenarioRule
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.LargeTest
import androidx.test.platform.app.InstrumentationRegistry
import androidx.test.uiautomator.UiDevice
import org.junit.After
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
/**
* Instrumented test, which will execute on an Android device.
*
* See [testing documentation](http://d.android.com/tools/testing).
*/
#LargeTest
#RunWith(AndroidJUnit4::class)
class MainActivityTest {
private var ivWeribeeZoo = 0
private var tvWeribeeName = 0
private var tvWeribeeRating = 0
private var ieWeribeeName = 0
private var etWeribeeRate = 0
private var ieDate = 0
#get:Rule
var activityRule: ActivityScenarioRule<MainActivity>
= ActivityScenarioRule(MainActivity::class.java)
#Before
fun setUP()
{
ivWeribeeZoo = R.id.ivWeribeeZoo
tvWeribeeName = R.id.tvZooName
tvWeribeeRating = R.id.suRating
ieWeribeeName = R.id.itName
etWeribeeRate = R.id.etRating
ieDate = R.id.itDate
}
#Test
fun nameInMainMatchesNewName() {
//val activityScenario = ActivityScenario.launch(MainActivity::class.java)
onView(withId(ivWeribeeZoo)).perform(click())
onView(withId(ieWeribeeName)).perform(clearText(), typeText("ZOO"))
closeSoftKeyboard()
/* val mDevice:UiDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
mDevice.pressBack()*/
onView(isRoot()).perform(pressBack())
onView(withId(tvWeribeeName)).check(matches(withText("ZOO")))
}

error of Expecting member declaration android

i'm trying to call manager var but it always shows me the Expecting member declaration ... help
import android.app.Notification
import android.app.NotificationChannel
import android.app.NotificationManager
import android.app.PendingIntent
import android.content.Context
import android.content.Intent
import android.os.Build
import androidx.annotation.RequiresApi
lateinit var channel: NotificationChannel
lateinit var manager:NotificationManager
class notify(var context: Context) {
#RequiresApi(Build.VERSION_CODES.O)
var test=0 // for testing
test++ // just testing same error
manager= // shows an error
}

testing Repository class that takes DAO parameter

I am learning Kotlin to build a note app. I have created a repository class as shown below which takes a Dao parameter. For now, the source of data is just Dao but in the tutorial I am following, it calls an API class as well.
What I want to know is how do I test a repository classes logic?
import androidx.lifecycle.LiveData
import com.example.lastnotetakingapp.db.daos.NoteDao
import com.example.lastnotetakingapp.db.models.Note
class NotesRepo(private val notesDao: NoteDao) {
val allNotes: LiveData<List<Note>> = notesDao.getAllNotes()
suspend fun addNewNote(note: Note): Long {
return notesDao.addNewNote(note)
}
}
My test which is passing but it is 100% identical to the way a Dao would be tested except I use repo object, which made wonder if I am doing it right or not:
Is mocking the Database/DAO possible so I can spy on them to make sure they are called and all?
import androidx.arch.core.executor.testing.InstantTaskExecutorRule
import androidx.lifecycle.LiveData
import androidx.lifecycle.Observer
import androidx.room.Room
import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.example.lastnotetakingapp.db.NoteDB
import com.example.lastnotetakingapp.db.daos.NoteDao
import com.example.lastnotetakingapp.db.models.Note
import com.example.lastnotetakingapp.testHelpers.getOrAwaitValue
import com.google.common.truth.Truth
import kotlinx.coroutines.runBlocking
import org.junit.After
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
#RunWith(AndroidJUnit4::class)
class NotesRepoTest {
private lateinit var dao: NoteDao
private lateinit var db: NoteDB
private lateinit var notesRepo: NotesRepo
#get:Rule
var instantTaskExecutorRule = InstantTaskExecutorRule()
#Before
fun setUp(){
db = Room.inMemoryDatabaseBuilder(
ApplicationProvider.getApplicationContext(),
NoteDB::class.java,
).allowMainThreadQueries().build()
dao= db.noteDao
notesRepo = NotesRepo(dao)
}
#After
fun tearDown(){
db.close()
}
#Test
fun saveNotesTest(): Unit = runBlocking{
val note = Note(0, "tupac", "content", 0)
val id : Long = notesRepo.addNewNote(note)
Truth.assertThat(id).isEqualTo(1)
val notes = notesRepo.allNotes.getOrAwaitValue()
val noteOne: Note? = notes?.get(0)
Truth.assertThat(notes?.size).isEqualTo(1)
Truth.assertThat(noteOne?.title).isEqualTo(note.title)
Truth.assertThat(noteOne?.content).isEqualTo(note.content)
Truth.assertThat(noteOne?.viewed).isEqualTo(false)
}
}

Categories

Resources