I got a null pointer exception while playing with navigation in jetpack compose. Dont know exactly why it is giving a null pointer exception. I have two screens Home and Details.
This is MainActivity.
package com.example.composenavigation
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.navigation.NavController
import androidx.navigation.NavHostController
import androidx.navigation.compose.rememberNavController
import com.example.composenavigation.ui.theme.ComposeNavigationTheme
class MainActivity : ComponentActivity() {
private lateinit var navController: NavHostController
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
ComposeNavigationTheme {
navController = rememberNavController()
SetupNavGraph(navController = navController)
}
}
}
}
This is My Home and Detailed Screen respectively.
package com.example.composenavigation
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.tooling.preview.Preview
import androidx.navigation.NavController
import androidx.navigation.compose.rememberNavController
#Composable
fun HomeScreen(
navController: NavController
) {
Box(
modifier = Modifier.fillMaxSize(),
contentAlignment = Alignment.Center
) {
Text(
modifier = Modifier.clickable {
navController.navigate(route = Screen.Detail.route)
},
text = "Home",
color = MaterialTheme.colorScheme.primary,
fontSize = MaterialTheme.typography.displayMedium.fontSize
)
}
}
#Preview(showBackground = true)
#Composable
fun HomeScreenPreview() {
HomeScreen(navController = rememberNavController())
}
package com.example.composenavigation
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.tooling.preview.Preview
import androidx.navigation.NavController
import androidx.navigation.compose.rememberNavController
#Composable
fun DetailedScreen(
navController: NavController
) {
Box(
modifier = Modifier.fillMaxSize(),
contentAlignment = Alignment.Center
) {
Text(
modifier = Modifier.clickable {
navController.popBackStack()
},
text = "Details",
color = Color.Red,
fontSize = MaterialTheme.typography.displayMedium.fontSize
)
}
}
#Preview(showBackground = true)
#Composable
fun DetailedScreenPreview() {
DetailedScreen(navController = rememberNavController())
}
This is my Screen.kt sealed class.
package com.example.composenavigation
sealed class Screen(val route: String) {
object Home : Screen(route = "home_route")
object Detail : Screen(route = "detail_route")
}
This is my Nav Graph.
package com.example.composenavigation
import androidx.compose.runtime.Composable
import androidx.navigation.NavController
import androidx.navigation.NavHostController
import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable
import androidx.navigation.compose.rememberNavController
#Composable
fun SetupNavGraph(
navController: NavHostController
) {
NavHost(
navController = navController,
startDestination = Screen.Home.route
) {
composable(
route = Screen.Home.route
) {
HomeScreen(navController = rememberNavController())
}
composable(
route = Screen.Detail.route
) {
DetailedScreen(navController = rememberNavController())
}
}
}
This is my stack trace.
FATAL EXCEPTION: main
Process: com.example.composenavigation, PID: 14947
java.lang.NullPointerException
at androidx.navigation.NavController.navigate(NavController.kt:1612)
at androidx.navigation.NavController.navigate(NavController.kt:1938)
at androidx.navigation.NavController.navigate$default(NavController.kt:1933)
at com.example.composenavigation.HomeScreenKt$HomeScreen$1$1.invoke(HomeScreen.kt:26)
at com.example.composenavigation.HomeScreenKt$HomeScreen$1$1.invoke(HomeScreen.kt:25)
at androidx.compose.foundation.ClickableKt$clickable$4$gesture$1$1$2.invoke-k-4lQ0M(Clickable.kt:167)
at androidx.compose.foundation.ClickableKt$clickable$4$gesture$1$1$2.invoke(Clickable.kt:156)
at androidx.compose.foundation.gestures.TapGestureDetectorKt$detectTapAndPress$2$1$1.invokeSuspend(TapGestureDetector.kt:234)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
at kotlinx.coroutines.DispatchedTaskKt.resume(DispatchedTask.kt:178)
at kotlinx.coroutines.DispatchedTaskKt.dispatch(DispatchedTask.kt:166)
at kotlinx.coroutines.CancellableContinuationImpl.dispatchResume(CancellableContinuationImpl.kt:397)
at kotlinx.coroutines.CancellableContinuationImpl.resumeImpl(CancellableContinuationImpl.kt:431)
at kotlinx.coroutines.CancellableContinuationImpl.resumeImpl$default(CancellableContinuationImpl.kt:420)
at kotlinx.coroutines.CancellableContinuationImpl.resumeWith(CancellableContinuationImpl.kt:328)
at androidx.compose.ui.input.pointer.SuspendingPointerInputFilter$PointerEventHandlerCoroutine.offerPointerEvent(SuspendingPointerInputFilter.kt:566)
at androidx.compose.ui.input.pointer.SuspendingPointerInputFilter.dispatchPointerEvent(SuspendingPointerInputFilter.kt:456)
at androidx.compose.ui.input.pointer.SuspendingPointerInputFilter.onPointerEvent-H0pRuoY(SuspendingPointerInputFilter.kt:469)
at androidx.compose.ui.node.BackwardsCompatNode.onPointerEvent-H0pRuoY(BackwardsCompatNode.kt:394)
at androidx.compose.ui.input.pointer.Node.dispatchMainEventPass(HitPathTracker.kt:314)
at androidx.compose.ui.input.pointer.Node.dispatchMainEventPass(HitPathTracker.kt:301)
at androidx.compose.ui.input.pointer.NodeParent.dispatchMainEventPass(HitPathTracker.kt:183)
at androidx.compose.ui.input.pointer.HitPathTracker.dispatchChanges(HitPathTracker.kt:102)
at androidx.compose.ui.input.pointer.PointerInputEventProcessor.process-BIzXfog(PointerInputEventProcessor.kt:98)
at androidx.compose.ui.platform.AndroidComposeView.sendMotionEvent-8iAsVTc(AndroidComposeView.android.kt:1329)
at androidx.compose.ui.platform.AndroidComposeView.handleMotionEvent-8iAsVTc(AndroidComposeView.android.kt:1275)
at androidx.compose.ui.platform.AndroidComposeView.dispatchTouchEvent(AndroidComposeView.android.kt:1214)
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:3138)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2797)
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:3138)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2797)
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:3138)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2797)
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:3138)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2797)
at com.android.internal.policy.DecorView.superDispatchTouchEvent(DecorView.java:469)
at com.android.internal.policy.PhoneWindow.superDispatchTouchEvent(PhoneWindow.java:1859)
at android.app.Activity.dispatchTouchEvent(Activity.java:3996)
at com.android.internal.policy.DecorView.dispatchTouchEvent(DecorView.java:427)
at android.view.View.dispatchPointerEvent(View.java:13737)
at android.view.ViewRootImpl$ViewPostImeInputStage.processPointerEvent(ViewRootImpl.java:5691)
at android.view.ViewRootImpl$ViewPostImeInputStage.onProcess(ViewRootImpl.java:5485)
at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:4984)
2023-02-17 14:41:48.799 AndroidRuntime E at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:5037)
at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:5003)
at android.view.ViewRootImpl$AsyncInputStage.forward(ViewRootImpl.java:5143)
at android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:5011)
at android.view.ViewRootImpl$AsyncInputStage.apply(ViewRootImpl.java:5200)
at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:4984)
at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:5037)
at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:5003)
at android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:5011)
at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:4984)
at android.view.ViewRootImpl.deliverInputEvent(ViewRootImpl.java:7810)
at android.view.ViewRootImpl.doProcessInputEvents(ViewRootImpl.java:7779)
at android.view.ViewRootImpl.enqueueInputEvent(ViewRootImpl.java:7729)
at android.view.ViewRootImpl$WindowInputEventReceiver.onInputEvent(ViewRootImpl.java:7949)
at android.view.InputEventReceiver.dispatchInputEvent(InputEventReceiver.java:188)
at android.os.MessageQueue.nativePollOnce(Native Method)
at android.os.MessageQueue.next(MessageQueue.java:336)
at android.os.Looper.loop(Looper.java:215)
at android.app.ActivityThread.main(ActivityThread.java:7593)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:980)
Suppressed: kotlinx.coroutines.DiagnosticCoroutineContextException: [androidx.compose.ui.platform.MotionDurationScaleImpl#e98cd80, androidx.compose.runtime.BroadcastFrameClock#6acafb9, StandaloneCoroutine{Cancelling}#7275ffe, AndroidUiDispatcher#777735f]
What's wrong here?
You have too many navControllers.
You only need one:
setContent {
ComposeNavigationTheme {
navController = rememberNavController() // Leave this one
SetupNavGraph(navController = navController)
}
}
Use an existing controller, don't create new ones:
#Composable
fun SetupNavGraph(
navController: NavHostController
) {
NavHost(
navController = navController,
startDestination = Screen.Home.route
) {
composable(
route = Screen.Home.route
) {
HomeScreen(navController = navController) // Here
}
composable(
route = Screen.Detail.route
) {
DetailedScreen(navController = navController) //And here
}
}
}
Related
We have looked at a number of posts and tried a few with no results.
Here is the Github link for full code.
Here is the code for the activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".activity.MainActivity">
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/todoRv"
android:layout_width="match_parent"
android:layout_height="wrap_content"
/>
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="#+id/AddTask"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:clickable="true"
app:srcCompat="#android:drawable/ic_input_add"
android:layout_alignParentBottom="true"
android:layout_alignParentRight="true"
android:layout_margin="25dp"
android:onClick="openNewTask"
/>
</RelativeLayout>
Here is the code for the activity_task.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
tools:context=".activity.TaskActivity">
<TextView
android:id="#+id/txtTaskName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="Task Name"
android:layout_margin="14dp"
android:textSize="33sp"/>
<EditText
android:id="#+id/etTaskName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:ems="10"
android:hint="Please Enter Task Name"
android:layout_margin="14dp"
android:textSize="20sp"
android:inputType="textPersonName"
/>
<Button
android:id="#+id/saveTask"
android:layout_width="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_marginTop="34dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:onClick="saveTask"
android:text="Save Task" />
</LinearLayout>
Here is the code for the item_todo.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="#+id/txtShowTitle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="25dp"
android:layout_marginLeft="15dp"
android:textSize="35sp"
android:text="Task Title Name" />
</LinearLayout>
Here is the code for the MainActivity.kt
package abc.com.onetaskadd.activity
import abc.com.onetaskadd.R
import abc.com.onetaskadd.adapter.TodoAdapter
import abc.com.onetaskadd.database.TodoDatabase
import abc.com.onetaskadd.model.TodoModel
import android.content.Intent
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.view.View
import android.widget.Adapter
import androidx.lifecycle.Observer
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
class MainActivity : AppCompatActivity() {
val todoList = arrayListOf<TodoModel>()
var recyclerAdapter= TodoAdapter(todoList)
lateinit var layoutmanger: RecyclerView.LayoutManager
lateinit var todoRv: RecyclerView
val db by lazy {
TodoDatabase.getDatabase(this)
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
todoRv= findViewById(R.id.todoRv)
todoRv.apply {
layoutmanger= LinearLayoutManager(this#MainActivity)
adapter=this#MainActivity.recyclerAdapter
}
db.todoDao().getAllTask().observe(this, Observer {
if (!it.isNullOrEmpty()) {
todoList.clear()
todoList.addAll(it)
recyclerAdapter.notifyDataSetChanged()
}
})
}
fun openNewTask(view: View) {
startActivity(Intent(this, TaskActivity::class.java))
}
}
Here is the code for the TaskActivity.kt
package abc.com.onetaskadd.activity
import abc.com.onetaskadd.R
import abc.com.onetaskadd.database.TodoDatabase
import abc.com.onetaskadd.model.TodoModel
import android.content.Intent
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.provider.SyncStateContract.Helpers.insert
import android.view.View
import android.widget.Button
import android.widget.EditText
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
const val DB_NAME = "todo.db"
class TaskActivity : AppCompatActivity() {
lateinit var etTaskName: EditText
lateinit var saveTask: Button
val db by lazy {
TodoDatabase.getDatabase(this)
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_task)
etTaskName = findViewById(R.id.etTaskName)
saveTask= findViewById(R.id.saveTask)
}
fun saveTask(view: View) {
val taskName = etTaskName.editableText.toString()
GlobalScope.launch(Dispatchers.Main) {
val id = withContext(Dispatchers.IO) {
return#withContext db.todoDao ().insertTask(
TodoModel(
taskName
)
)
}
finish()
}
}
}
Here is the code for the TodoAdapter.kt
package abc.com.onetaskadd.adapter
import abc.com.onetaskadd.R
import abc.com.onetaskadd.model.TodoModel
import android.content.Context
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView
class TodoAdapter (val todoList: List<TodoModel>) :RecyclerView.Adapter<TodoAdapter.TodoViewHolder>(){
class TodoViewHolder(view: View):RecyclerView.ViewHolder(view)
{
fun bind(todoModel: TodoModel) {
with(itemView){
val txtShowTitle: TextView= findViewById(R.id.txtShowTitle)
txtShowTitle.text=todoModel.taskName
}
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): TodoViewHolder {
val view= LayoutInflater.from(parent.context).inflate(R.layout.item_todo, parent, false)
return TodoViewHolder(view)
}
override fun onBindViewHolder(holder: TodoViewHolder, position: Int) {
holder.bind(todoList[position])
}
override fun getItemCount(): Int {
return todoList.size
}
}
Here is the code for the TodoDao.kt
package abc.com.onetaskadd.database
import abc.com.onetaskadd.model.TodoModel
import androidx.lifecycle.LiveData
import androidx.room.Dao
import androidx.room.Insert
import androidx.room.Query
#Dao
interface TodoDao {
#Insert()
suspend fun insertTask(todoModel: TodoModel):Long
#Query("Select * From TodoModel where isFinished != -1 ")
fun getAllTask():LiveData<List<TodoModel>>
}
Here is the code for the TaskDatabase.kt
package abc.com.onetaskadd.database
import abc.com.onetaskadd.activity.DB_NAME
import abc.com.onetaskadd.model.TodoModel
import android.content.Context
import androidx.room.Database
import androidx.room.Room
import androidx.room.RoomDatabase
#Database(entities = [TodoModel::class],version = 1)
abstract class TodoDatabase: RoomDatabase() {
abstract fun todoDao(): TodoDao
companion object{
#Volatile
private var INSTANCE: TodoDatabase? =null
fun getDatabase(context: Context): TodoDatabase {
val tempInsance = INSTANCE
if (tempInsance != null) {
return tempInsance
}
synchronized(this){
val instance= Room.databaseBuilder(
context.applicationContext,
TodoDatabase:: class.java,
DB_NAME
).build()
INSTANCE= instance
return instance
}
}
}
}
Here is the code for the TodoModel.kt
package abc.com.onetaskadd.model
import androidx.room.Entity
import androidx.room.PrimaryKey
#Entity
data class TodoModel(
val taskName: String,
var isFinished: Int =-1,
#PrimaryKey
var id:Long=0
)
You should replace this code in TaskDatabase.kt file
synchronized(this){
val instance= Room.databaseBuilder(
context.applicationContext,
TodoDatabase:: class.java,
DB_NAME
).fallbackToDestructiveMigration().build()
It will Solve the debug problem.
Hi I have problem with Navigation drawer. I used the default layout with navigation drawer to learn how to add more. I create similar classes like this default. But these thre clases witch was at the start are working, but another witch I crated don't and when i trying click into this three "naprawa", "oc", "pt" app is crashing.In every fragment....xml i have tools:context=".ui.<folder>.<...Fragment>"with name of Fragments. Someone know where could be problem?
Also I have this errors:
Process: com.example.carplanner, PID: 23240
kotlin.UninitializedPropertyAccessException: lateinit property naprawaViewModel has not been initialized
at com.example.carplanner.ui.naprawa.NaprawaFragment.onCreateView(NaprawaFragment.kt:23)
at androidx.fragment.app.Fragment.performCreateView(Fragment.java:2698)
at androidx.fragment.app.FragmentStateManager.createView(FragmentStateManager.java:320)
at androidx.fragment.app.FragmentManager.moveToState(FragmentManager.java:1187)
at androidx.fragment.app.FragmentManager.addAddedFragments(FragmentManager.java:2224)
at androidx.fragment.app.FragmentManager.executeOpsTogether(FragmentManager.java:1997)
at androidx.fragment.app.FragmentManager.removeRedundantOperationsAndExecute(FragmentManager.java:1953)
at androidx.fragment.app.FragmentManager.execPendingActions(FragmentManager.java:1849)
at androidx.fragment.app.FragmentManager$4.run(FragmentManager.java:413)
at android.os.Handler.handleCallback(Handler.java:938)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:223)
at android.app.ActivityThread.main(ActivityThread.java:7656)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947)
and this is the code :
package com.example.carplanner
import android.os.Bundle
import android.view.Menu
import android.view.MenuItem
import android.widget.Toast
import com.google.android.material.floatingactionbutton.FloatingActionButton
import com.google.android.material.snackbar.Snackbar
import com.google.android.material.navigation.NavigationView
import androidx.navigation.findNavController
import androidx.navigation.ui.AppBarConfiguration
import androidx.navigation.ui.navigateUp
import androidx.navigation.ui.setupActionBarWithNavController
import androidx.navigation.ui.setupWithNavController
import androidx.drawerlayout.widget.DrawerLayout
import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.widget.Toolbar
import android.view.View
import android.content.Intent
class MainActivity : AppCompatActivity() {
private lateinit var appBarConfiguration: AppBarConfiguration
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val toolbar: Toolbar = findViewById(R.id.toolbar)
setSupportActionBar(toolbar)
val fab: FloatingActionButton = findViewById(R.id.fab)
fab.setOnClickListener { view ->
Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
.setAction("Action", null).show()
}
val drawerLayout: DrawerLayout = findViewById(R.id.drawer_layout)
val navView: NavigationView = findViewById(R.id.nav_view)
val navController = findNavController(R.id.nav_host_fragment)
// Passing each menu ID as a set of Ids because each
// menu should be considered as top level destinations.
appBarConfiguration = AppBarConfiguration(setOf(
R.id.nav_home,
R.id.nav_paliwo,
R.id.nav_naprawa,
R.id.nav_wydatki,
R.id.nav_oc,
R.id.nav_pt), drawerLayout)
setupActionBarWithNavController(navController, appBarConfiguration)
navView.setupWithNavController(navController)
}
override fun onCreateOptionsMenu(menu: Menu): Boolean {
// Inflate the menu; this adds items to the action bar if it is present.
menuInflater.inflate(R.menu.main, menu)
return true
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
val id = item.itemId
if (id == R.id.btn_settings) {
val intent = Intent(
this, SettingsActivity ::class.java)
startActivity (intent)
}else{
if (id == R.id.btn_about){
val intent = Intent(
this, About ::class.java)
startActivity (intent)
}
}
return super.onOptionsItemSelected(item)
}
override fun onSupportNavigateUp(): Boolean {
val navController = findNavController(R.id.nav_host_fragment)
return navController.navigateUp(appBarConfiguration) || super.onSupportNavigateUp()
}
}
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
tools:showIn="navigation_view">
<group android:checkableBehavior="single">
<item
android:id="#+id/nav_home"
android:icon="#android:drawable/ic_dialog_dialer"
android:title="#string/strona_g_wna" />
<item
android:id="#+id/nav_paliwo"
android:icon="#drawable/ic_paliwo"
android:title="#string/tankowanie" />
<item
android:id="#+id/nav_naprawa"
android:icon="#drawable/ic_naprawa"
android:title="#string/naprawy" />
<item
android:id="#+id/nav_wydatki"
android:icon="#drawable/ic_wydatki"
android:title="#string/wydatki" />
<item
android:id="#+id/nav_oc"
android:icon="#drawable/ic_oc"
android:title="#string/ubezpieczenia" />
<item
android:id="#+id/nav_pt"
android:icon="#android:drawable/stat_notify_error"
android:title="#string/przegl_d_techniczny" />
</group>
</menu>
<?xml version="1.0" encoding="utf-8"?>
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/mobile_navigation"
app:startDestination="#+id/nav_home">
<fragment
android:id="#+id/nav_home"
android:name="com.example.carplanner.ui.home.HomeFragment"
android:label="Strona Główna"
tools:layout="#layout/fragment_home" />
<fragment
android:id="#+id/nav_paliwo"
android:name="com.example.carplanner.ui.paliwo.PaliwoFragment"
android:label="Paliwo"
tools:layout="#layout/fragment_paliwo" />
<fragment
android:id="#+id/nav_naprawa"
android:name="com.example.carplanner.ui.naprawa.NaprawaFragment"
android:label="Naprawy"
tools:layout="#layout/fragment_naprawa" />
<fragment
android:id="#+id/nav_wydatki"
android:name="com.example.carplanner.ui.wydatki.WydatkiFragment"
android:label="Wydatki"
tools:layout="#layout/fragment_wydatki" />
<fragment
android:id="#+id/nav_oc"
android:name="com.example.carplanner.ui.oc.OcFragment"
android:label="Ubezpieczenia"
tools:layout="#layout/fragment_oc" />
<fragment
android:id="#+id/nav_pt"
android:name="com.example.carplanner.ui.pt.PtFragment"
android:label="Przegląd techniczny"
tools:layout="#layout/fragment_pt" />
<fragment
android:id="#+id/nav_setting"
android:name="com.example.carplanner.SettingsActivity$SettingsFragment"
tools:layout="#layout/settings_activity" />
</navigation>
and the NaprawaFragment code:
package com.example.carplanner.ui.naprawa
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import androidx.fragment.app.Fragment
import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModelProvider
import com.example.carplanner.R
class NaprawaFragment : Fragment() {
private lateinit var naprawaViewModel: NaprawaViewModel
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
naprawaViewModel =
ViewModelProvider(this).get(naprawaViewModel::class.java)
val root = inflater.inflate(R.layout.fragment_naprawa, container, false)
val textView: TextView = root.findViewById(R.id.text_naprawa)
naprawaViewModel.text.observe(viewLifecycleOwner, Observer {
textView.text = it
})
return root
}
}
And HomeFragment which is working properly
package com.example.carplanner.ui.home
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import androidx.fragment.app.Fragment
import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModelProvider
import com.example.carplanner.R
class HomeFragment : Fragment() {
private lateinit var homeViewModel: HomeViewModel
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
homeViewModel =
ViewModelProvider(this).get(HomeViewModel::class.java)
val root = inflater.inflate(R.layout.fragment_home, container, false)
val textView: TextView = root.findViewById(R.id.text_home)
homeViewModel.text.observe(viewLifecycleOwner, Observer {
textView.text = it
})
return root
}
}
Process: com.bignerdranch.android.on_callbabysitting, PID: 19624
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.bignerdranch.android.on_callbabysitting/com.bignerdranch.android.on_callbabysitting.Home}: java.lang.IllegalStateException: recyclerv_view must not be null
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2817)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2892)
at android.app.ActivityThread.-wrap11(Unknown Source:0)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1593)
at android.os.Handler.dispatchMessage(Handler.java:105)
at android.os.Looper.loop(Looper.java:164)
at android.app.ActivityThread.main(ActivityThread.java:6541)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:240)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:767)
Caused by: java.lang.IllegalStateException: recyclerv_view must not be null
at com.bignerdranch.android.on_callbabysitting.Home.onCreate(Home.kt:42)
at android.app.Activity.performCreate(Activity.java:6975)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1213)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2770)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2892)
at android.app.ActivityThread.-wrap11(Unknown Source:0)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1593)
at android.os.Handler.dispatchMessage(Handler.java:105)
at android.os.Looper.loop(Looper.java:164)
at android.app.ActivityThread.main(ActivityThread.java:6541)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:240)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:767)
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:tools="http://schemas.android.com/tools"
android:orientation="vertical"
tools:context=".Home">
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/recyclerv_view"
android:layout_width="match_parent"
android:layout_height ="match_parent">
</androidx.recyclerview.widget.RecyclerView>
</RelativeLayout>
package com.bignerdranch.android.on_callbabysitting
import android.content.Context
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.View.inflate
import android.widget.EditText
import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import kotlinx.android.synthetic.main.activity_main.*
import kotlinx.android.synthetic.main.recycv1.*
import kotlinx.android.synthetic.main.sidebar.*
import java.lang.IllegalStateException
class Home : AppCompatActivity() {
var names = ArrayList<String>()
var imgUrls = ArrayList<String>()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.homepage)
lateinit var context: Context
var helper = MyDBHelper(applicationContext)
var db = helper.readableDatabase
var rs = db.rawQuery("SELECT * FROM USERS", null)
rs.moveToFirst()
while(rs.isAfterLast == false)
{
names.add(rs.getString(rs.getColumnIndex("EMAIL")))
rs.moveToNext()
names.add(rs.getString(rs.getColumnIndex("FIRST_NAME")))
rs.moveToNext()
//names.add(rs.getString(rs.getColumnIndex("LAST_NAME")))
//rs.moveToNext()
}
recyclerv_view.layoutManager = LinearLayoutManager(this)
recyclerv_view.adapter = RecyclerViewAdapter(imgUrls, names, this)
/*names.add(editTextTextEmailAddress3.getText().toString())
names.add(editTextTextPassword.getText().toString())
//names.add(editTextTextEmailAddress3.getText().toString())
//names.add(editTextTextPassword.getText().toString())*/
//try {
// recyclerv_view.adapter = RecyclerViewAdapter.First(this, imgUrls, names)
//recyclerv_view.layoutManager = LinearLayoutManager(this)
// }catch (ignored: IllegalStateException)
//{
//}
//val recyclerView : RecyclerView = findViewById(R.id.recyclerv_view)
//val recyclerView = findViewById<RecyclerView>(R.id.recyclerv_view)
//recyclerView.setAdapter(first)
//recyclerView.setLayoutManager(LinearLayoutManager(this))
}
}
package com.bignerdranch.android.on_callbabysitting
import android.app.PendingIntent.getActivity
import android.content.Context
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.EditText
import androidx.recyclerview.widget.RecyclerView
import de.hdodenhof.circleimageview.CircleImageView
import android.widget.TextView
import android.widget.LinearLayout
import com.bumptech.glide.Glide
import java.security.AccessController.getContext
open class RecyclerViewAdapter(val imgNames: ArrayList<String>, val imgPic: ArrayList<String>, val context: Context) : RecyclerView.Adapter<RecyclerViewAdapter.ViewHolder>() {
//var Context = context
class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView)
{
// lateinit var cimg:CircleImageView
//lateinit var img:TextView
//lateinit var parentLayout: LinearLayout
val CircleImageView = itemView.findViewById<CircleImageView>(R.id.profile_image)
val TextView = itemView.findViewById<TextView>(R.id.textView19)
val TextView1 = itemView.findViewById<TextView>(R.id.textView18)
val TextView2 = itemView.findViewById<TextView>(R.id.textView20)
val parentLayout = itemView.findViewById<LinearLayout>(R.id.parent_layout)
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
//var View = LayoutInflater.from(parent.getContext()).inflate(R.layout.homepage, parent, false)
//var viewHolder = ViewHolder(View)
return ViewHolder(LayoutInflater.from(context).inflate(R.layout.homepage, parent, false))
}
override fun getItemCount(): Int {
return imgNames.size
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
/* Glide
.with(context)
.asBitmap()
.load(imgPic.get(position))
.into(holder.CircleImageView)
var First = First(context,imgNames, imgPic)
First.imgN.add(imgNames.get(position))
*/
holder?.TextView?.text = imgNames.get(position)
holder?.TextView1.text = imgNames.get(position)
holder?.TextView2.text = imgNames.get(position)
holder?.parentLayout.parent
}
}
I am trying to have my code display the user's name at login in the home page, I can successfully move in from one activity to the next with a click, but when I add the recycler view in my home activity, it doesn't work. Attached is the recycler view XML, adapter activity, and my home class activity along with the log.
In your imports there are multiple UI's imported. Just check once where the recyclerview lies actually.
import kotlinx.android.synthetic.main.activity_main.*
import kotlinx.android.synthetic.main.recycv1.*
import kotlinx.android.synthetic.main.sidebar.*
you've not initialized the recyclerv_view in the activity class.
I have error in this code (
java.lang.IllegalArgumentException: Parameter specified as non-null is null: method kotlin.jvm.internal.Intrinsics.checkParameterIsNotNull, parameter result)
And didn't save image
i will give you all the code:
MainActivity code:
package com.masreta87.backhussian
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
import android.view.View
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.masreta87.backhussian.models.BlogPost
import com.masreta87.backhussian.models.DataSource
import kotlinx.android.synthetic.main.activity_main.*
class MainActivity : AppCompatActivity() {
private lateinit var blogAdapter:BlogRecyclerAdapter
lateinit var data: List<BlogPost>
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
initRecyclerView()
addDataSet()
}
private fun addDataSet(){
data=DataSource.createDataSet()
blogAdapter.submitList(data)
}
private fun initRecyclerView(){
recycler_view.apply {
layoutManager=LinearLayoutManager(this#MainActivity)
blogAdapter=BlogRecyclerAdapter()
adapter=blogAdapter
}
}
}
and BlogRecyclerAdapter.kt
package com.masreta87.backhussian
import android.content.Context
import android.graphics.Bitmap
import android.os.AsyncTask
import android.os.Environment
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView
import com.bumptech.glide.Glide
import com.bumptech.glide.request.RequestOptions
import com.masreta87.backhussian.models.BlogPost
import kotlinx.android.synthetic.main.layout_blog_list_item.view.*
import java.net.URL
import android.os.Environment.getExternalStorageDirectory
import com.bumptech.glide.load.engine.DiskCacheStrategy
import com.bumptech.glide.load.resource.bitmap.DownsampleStrategy
import java.io.File
import java.io.FileOutputStream
import java.lang.ref.WeakReference
import android.widget.Toast
import android.content.Intent
import android.annotation.SuppressLint
import android.app.ProgressDialog
import android.net.Uri
import com.squareup.picasso.Picasso
import java.io.IOException
class BlogRecyclerAdapter :RecyclerView.Adapter<RecyclerView.ViewHolder>(){
private var items:List <BlogPost> = ArrayList()
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
return BlogViewHolder(
LayoutInflater.from(parent.context).inflate(R.layout.layout_blog_list_item,parent,false)
)
}
override fun getItemCount(): Int {
return items.size
}
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
when(holder){
is BlogViewHolder ->{
holder.bind(items.get(position))
}
}
}
fun submitList(blogList: List<BlogPost>){
items = blogList
}
class BlogViewHolder constructor(
itemView:View
):RecyclerView.ViewHolder(itemView){
val blogImage:ImageView =itemView.blog_image
fun bind(blogPost:BlogPost){
val requestOptions =RequestOptions()
.placeholder(R.drawable.ic_launcher_background)
.error(R.drawable.ic_launcher_background)
Glide.with(itemView.context)
.applyDefaultRequestOptions(requestOptions)
.load(blogPost.image)
.into(blogImage)
itemView.setOnClickListener{
SaveImage(itemView.context,blogPost.image.toString() );
}
}
}
}
private fun SaveImage(context: Context, MyUrl: String) {
val progress = ProgressDialog(context)
class SaveThisImage : AsyncTask<Void, Void, Void>() {
override fun onPreExecute() {
super.onPreExecute()
progress.setTitle("Processing")
progress.setMessage("Please Wait...")
progress.setCancelable(false)
progress.show()
}
override fun doInBackground(vararg arg0: Void): Void? {
try {
val sdCard = Environment.getExternalStorageDirectory()
#SuppressLint("DefaultLocale") val fileName =
String.format("%dm.png", System.currentTimeMillis())
val dir = File(sdCard.absolutePath + "/Image")
dir.mkdirs()
val myImageFile = File(dir,fileName) // Create image file
**var fos:FileOutputStream? = null**
try {
Log.d("ala",myImageFile.toString())
**fos = FileOutputStream(myImageFile)**
val bitmap = Picasso.get().load(MyUrl).get()
bitmap.compress(Bitmap.CompressFormat.PNG, 100, fos)
val intent = Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE)
intent.data = Uri.fromFile(myImageFile)
context.sendBroadcast(intent)
} catch (e: IOException) {
e.printStackTrace()
} finally {
try {
fos!!.close()
} catch (e: IOException) {
e.printStackTrace()
}
}
} catch (e: Exception) {
}
return null
}
override fun onPostExecute(result: Void) {
super.onPostExecute(result)
if (progress.isShowing) {
progress.dismiss()
}
Toast.makeText(context, "Saved", Toast.LENGTH_SHORT).show()
}
}
val shareimg = SaveThisImage()
shareimg.execute()
}
And BlogPost.class
package com.masreta87.backhussian.models
data class BlogPost(
var image:String
)
{
}
AND DataStore.class
package com.masreta87.backhussian.models
class DataSource{
companion object{
fun createDataSet(): ArrayList<BlogPost>{
val list = ArrayList<BlogPost>()
list.add(
BlogPost(
"https://firebasestorage.googleapis.com/v0/b/databaseim-56ef5.appspot.com/o/rpic%20(2).jpg?alt=media&token=138c2c3b-33ce-4a96-a7f5-74816af21809"
)
)
list.add(
BlogPost(
"https://firebasestorage.googleapis.com/v0/b/databaseim-56ef5.appspot.com/o/v1.png?alt=media&token=2e80d218-eb48-4c51-b51a-0fac43f76da7"
)
)
list.add(
BlogPost(
"https://firebasestorage.googleapis.com/v0/b/databaseim-56ef5.appspot.com/o/v10.jpg?alt=media&token=5e7207eb-1dac-41c0-bb3b-95abf9a54a2e"
)
)
list.add(
BlogPost(
"https://firebasestorage.googleapis.com/v0/b/databaseim-56ef5.appspot.com/o/v11.jpg?alt=media&token=2ab2b0c4-5ca1-4042-85c5-6d3e58181f45"
)
)
return list
}
}
}
And Mainifest
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
And activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<androidx.recyclerview.widget.RecyclerView
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
android:id="#+id/recycler_view"/>
</androidx.constraintlayout.widget.ConstraintLayout>
And layout_blog_list_item.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.cardview.widget.CardView
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
xmlns:app="http://schemas.android.com/apk/res-auto"
app:cardElevation="10dp"
app:cardCornerRadius="2dp"
app:cardPreventCornerOverlap="false"
>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
>
<ImageView
android:layout_width="match_parent"
android:layout_height="610dp"
app:layout_constraintTop_toTopOf="parent"
android:id="#+id/blog_image"
android:background="#drawable/boder_image"
android:padding="10dp"
android:layout_margin="0dp"
android:adjustViewBounds="true"
android:scaleType="fitXY"
/>
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.cardview.widget.CardView>
and full error:
2020-01-15 21:34:36.509 32083-32083/? E/AndroidRuntime: FATAL
EXCEPTION: main
Process: com.masreta87.backhussian, PID: 32083
java.lang.IllegalArgumentException: Parameter specified as non-null is null: method
kotlin.jvm.internal.Intrinsics.checkParameterIsNotNull, parameter
result
at com.masreta87.backhussian.BlogRecyclerAdapterKt$SaveImage$SaveThisImage.onPostExecute(Unknown
Source:2)
at com.masreta87.backhussian.BlogRecyclerAdapterKt$SaveImage$SaveThisImage.onPostExecute(BlogRecyclerAdapter.kt:86)
at android.os.AsyncTask.finish(AsyncTask.java:695)
at android.os.AsyncTask.-wrap1(Unknown Source:0)
at android.os.AsyncTask$InternalHandler.handleMessage(AsyncTask.java:712)
at android.os.Handler.dispatchMessage(Handler.java:105)
at android.os.Looper.loop(Looper.java:164)
at android.app.ActivityThread.main(ActivityThread.java:6541)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:240)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:767)
this is full error in app
Change the parameter type in
override fun onPostExecute(result: Void)
to
override fun onPostExecute(result: Void?).
And as Akhilesh Kumar mentioned here you should also change
class SaveThisImage : AsyncTask<Void, Void, Void>()
to
class SaveThisImage : AsyncTask<Void, Void, Void?>()
This is because the doInBackground in your code returns a nullable type Void?. The return value of doInBackground is passed as an argument to onPostExcecute but your onPostExecute accepts a non null value Void instead of a nullable one Void?.
As a side-note you should use Unit instead of Void when in Kotlin
EDIT
To make your saved image appear the media database needs to be updated. The media database is updated when you restart your device or after some time passes it will show up in the save location. To update the media database immediately you can use the MediaScannerConnection object.
Try passing your saved file to this function after bitmap.compress and pass your myImageFile
/**
* Updates the Pictures gallery to include the newly created file.
* #param fileObj: file path to be scanned so that the new file will appear in the gallery
*/
private fun refreshPhoneGallery(fileObj: File)
{
/* Scan the specified file path so that the new file will appear in gallery */
MediaScannerConnection.scanFile(
yourContext,
arrayOf(fileObj.path),
null,
object : MediaScannerConnection.OnScanCompletedListener
{
override fun onScanCompleted(scannedFilePath: String?, p1: Uri?)
{
// Do whatever
}
}
)
}
I try to do Instrumentation Test in my project but it have an error java.lang.IllegalArgumentException: You cannot start a load for a destroyed activity
This is my error :
at dalvik.system.VMStack.getThreadStackTrace(Native Method)
at java.lang.Thread.getStackTrace(Thread.java:580)
at android.support.test.espresso.base.DefaultFailureHandler.getUserFriendlyError(DefaultFailureHandler.java:88)
at android.support.test.espresso.base.DefaultFailureHandler.handle(DefaultFailureHandler.java:51)
at android.support.test.espresso.ViewInteraction.waitForAndHandleInteractionResults(ViewInteraction.java:314)
at android.support.test.espresso.ViewInteraction.check(ViewInteraction.java:297)
at com.example.riken.footballmatch.view.HomeActivityTest.testFootballMatchBehaviour(HomeActivityTest.kt:40)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at android.support.test.rule.ActivityTestRule$ActivityStatement.evaluate(ActivityTestRule.java:527)
at org.junit.rules.RunRules.evaluate(RunRules.java:20)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at android.support.test.runner.AndroidJUnit4.run(AndroidJUnit4.java:101)
at org.junit.runners.Suite.runChild(Suite.java:128)
at org.junit.runners.Suite.runChild(Suite.java:27)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
at org.junit.runner.JUnitCore.run(JUnitCore.java:115)
at android.support.test.internal.runner.TestExecutor.execute(TestExecutor.java:56)
at android.support.test.runner.AndroidJUnitRunner.onStart(AndroidJUnitRunner.java:384)
at android.app.Instrumentation$InstrumentationThread.run(Instrumentation.java:1853)
Caused by: junit.framework.AssertionFailedError: 'is displayed on the screen to the user' doesn't match the selected view.
Expected: is displayed on the screen to the user
Got: "AppCompatTextView{id=2131230965, res-name=tvTeam_home_detail, visibility=VISIBLE, width=0, height=46, has-focus=false, has-focusable=false, has-window-focus=true, is-clickable=false, is-enabled=true, is-focused=false, is-focusable=false, is-layout-requested=false, is-selected=false, layout-params=android.widget.LinearLayout$LayoutParams#1c6b0fe, tag=null, root-is-layout-requested=false, has-input-connection=false, x=117.0, y=168.0, text=, input-type=0, ime-target=false, has-links=false}"
at android.support.test.espresso.matcher.ViewMatchers.assertThat(ViewMatchers.java:539)
at android.support.test.espresso.assertion.ViewAssertions$MatchesViewAssertion.check(ViewAssertions.java:103)
at android.support.test.espresso.ViewInteraction$SingleExecutionViewAssertion.check(ViewInteraction.java:415)
at android.support.test.espresso.ViewInteraction$2.call(ViewInteraction.java:279)
at android.support.test.espresso.ViewInteraction$2.call(ViewInteraction.java:265)
at java.util.concurrent.FutureTask.run(FutureTask.java:237)
at android.os.Handler.handleCallback(Handler.java:739)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:135)
at android.app.ActivityThread.main(ActivityThread.java:5283)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:908)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:703)
java.lang.IllegalArgumentException: You cannot start a load for a destroyed activity
at com.bumptech.glide.manager.RequestManagerRetriever.assertNotDestroyed(RequestManagerRetriever.java:323)
at com.bumptech.glide.manager.RequestManagerRetriever.get(RequestManagerRetriever.java:132)
at com.bumptech.glide.Glide.with(Glide.java:723)
at com.example.riken.footballmatch.view.DetailActivity.showAwyLogo(DetailActivity.kt:108)
at com.example.riken.footballmatch.presenter.MatchDetailPresenter$getAwayLogo$1.invokeSuspend(MatchDetailPresenter.kt:40)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:32)
at kotlinx.coroutines.DispatchedTask$DefaultImpls.run(Dispatched.kt:235)
at kotlinx.coroutines.AbstractContinuation.run(AbstractContinuation.kt:19)
at android.os.Handler.handleCallback(Handler.java:739)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:135)
at android.app.ActivityThread.main(ActivityThread.java:5283)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:908)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:703)
Test running failed: Instrumentation run failed due to 'java.lang.IllegalArgumentException'
DetailActivity.kt
package com.example.riken.footballmatch.view
import android.database.sqlite.SQLiteConstraintException
import android.os.Bundle
import android.support.v4.content.ContextCompat
import android.support.v4.widget.SwipeRefreshLayout
import android.support.v7.app.AppCompatActivity
import android.view.Menu
import android.view.MenuItem
import android.widget.ProgressBar
import com.bumptech.glide.Glide
import com.example.riken.footballmatch.R
import com.example.riken.footballmatch.R.id.add_fav_fragment
import com.example.riken.footballmatch.api.ApiRepository
import com.example.riken.footballmatch.database.database
import com.example.riken.footballmatch.extension.gone
import com.example.riken.footballmatch.extension.visible
import com.example.riken.footballmatch.model.FavoriteItem
import com.example.riken.footballmatch.presenter.MatchDetailPresenter
import com.example.riken.footballmatch.model.Team
import com.example.riken.footballmatch.team.detmatch.MatcDetView
import com.example.riken.footballmatch.model.MatchActivity
import com.google.gson.Gson
import kotlinx.android.synthetic.main.activity_detail.*
import org.jetbrains.anko.db.classParser
import org.jetbrains.anko.db.delete
import org.jetbrains.anko.db.insert
import org.jetbrains.anko.db.select
import org.jetbrains.anko.design.snackbar
class DetailActivity : AppCompatActivity(), MatcDetView {
private var matchdet: MutableList<MatchActivity> = mutableListOf()
private var idEvent: String? = ""
private var idTeamHome: String? = ""
private var idTeamAway: String? = ""
private lateinit var matchpresenter: MatchDetailPresenter
private lateinit var progresbar: ProgressBar
private lateinit var swipeRefresh: SwipeRefreshLayout
private var menuItem: Menu? = null
private var isFavorite: Boolean = false
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_detail)
swipeRefresh = swipe_refresh_detail
val intent = intent
idEvent = intent.getStringExtra("id")
idTeamHome = intent.getStringExtra("idHomeTeam")
idTeamAway = intent.getStringExtra("idAwayTeam")
progresbar = progresar_detail
loadingShow()
supportActionBar?.title = "Detail Match"
this.supportActionBar?.setDisplayHomeAsUpEnabled(true)
favoriteState()
val apiRequest = ApiRepository ()
val gson = Gson ()
matchpresenter = MatchDetailPresenter(this, apiRequest, gson)
matchpresenter.getAwayLogo(idTeamAway)
matchpresenter.getHomeLogo(idTeamHome)
matchpresenter.getDetailMatch(idEvent)
}
override fun matchListShow(data: List<MatchActivity>) {
matchdet.clear()
matchdet.addAll(data)
//detailmatch
tvdetail_match_date.text = matchdet[0].dateEvent
// tvdetail_match_date.text = matchdet.get(0).dateEvent
// ?.let { DateHelper.formatDateToMatch(it) }
//detailhome
tvTeam_home_detail.text = matchdet[0].teamHome
tvScore_home_detail.text = matchdet[0].scoreHome
tvHome_goal_detail.text = matchdet[0].homeGoalDetail
tvHome_shot_detail.text = matchdet[0].homeShot
tvHome_gk.text = matchdet[0].homeKeeper
tvHome_deffense.text = matchdet[0].homeDefense
tvHome_mf.text = matchdet[0].homeMidfield
tvHome_fw.text = matchdet[0].homeForward
tvHome_sub.text = matchdet[0].homeSubstitute
//detailAway
tvTeam_away_detail.text = matchdet[0].teamAway
tvScore_away_detail.text = matchdet[0].scoreAway
tvAway_goal_detail.text = matchdet[0].awayGoalDetail
tvAway_shot_detail.text = matchdet[0].awayShot
tvAway_gk.text = matchdet[0].awayKeeper
tvAway_deffense.text = matchdet[0].awayDefense
tvAway_mf.text = matchdet[0].awayMidfield
tvAway_fw.text = matchdet[0].awayForward
tvAway_sub.text = matchdet[0].awaySubstitute
loadingHide()
}
override fun showAwyLogo(data: List<Team>) {
Glide.with(this).load(data[0].team).into(ivAway_detail)
ivAway_detail.visible()
}
override fun showHomeLogo(data: List<Team>) {
Glide.with(this).load(data[0].team).into(ivHome_detail)
ivHome_detail.visible()
}
override fun onCreateOptionsMenu(menu: Menu?): Boolean {
menuInflater.inflate(R.menu.favorite_match, menu)
menuItem = menu
setFavorite()
return true
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
return when (item.itemId) {
android.R.id.home -> {
finish()
true
}
add_fav_fragment -> {
if (isFavorite) removeFromFavorite() else addToFavorite()
isFavorite = !isFavorite
setFavorite()
true
}
else -> super.onOptionsItemSelected(item)
}
}
private fun favoriteState() {
database.use {
val result = select(FavoriteItem.TABLE_MATCH)
.whereArgs("(MATCH_ID = {id})",
"id" to idEvent as Any
)
val favorite = result.parseList(classParser<FavoriteItem>())
if (!favorite.isEmpty()) isFavorite = true
}
}
override fun loadingShow() {
progresbar.visible()
}
override fun loadingHide() {
progresbar.gone()
}
private fun addToFavorite() {
try {
database.use {
insert(
FavoriteItem.TABLE_MATCH,
FavoriteItem.MATCH_ID to matchdet[0].idEvent,
FavoriteItem.MATCH_DATE to matchdet[0].dateEvent,
FavoriteItem.HOME_TEAM to matchdet[0].teamHome,
FavoriteItem.HOME_SCORE to matchdet[0].scoreHome,
FavoriteItem.AWAY_TEAM to matchdet[0].teamAway,
FavoriteItem.AWAY_SCORE to matchdet[0].scoreAway,
FavoriteItem.HOME_ID to matchdet[0].idHomeTeam,
FavoriteItem.AWAY_ID to matchdet[0].idAwayTeam,
FavoriteItem.HOME_GOAL to matchdet[0].homeGoalDetail,
FavoriteItem.AWAY_GOAL to matchdet[0].awayGoalDetail,
FavoriteItem.HOME_SHOTS to matchdet[0].homeShot,
FavoriteItem.AWAY_SHOTS to matchdet[0].awayShot,
FavoriteItem.HOME_GK to matchdet[0].homeKeeper,
FavoriteItem.AWAY_GK to matchdet[0].awayKeeper,
FavoriteItem.HOME_FW to matchdet[0].homeForward,
FavoriteItem.AWAY_FW to matchdet[0].awayForward,
FavoriteItem.HOME_MF to matchdet[0].homeMidfield,
FavoriteItem.AWAY_MF to matchdet[0].awayMidfield,
FavoriteItem.HOME_DF to matchdet[0].homeDefense,
FavoriteItem.AWAY_DF to matchdet[0].awayDefense,
FavoriteItem.HOME_SUB to matchdet[0].homeSubstitute,
FavoriteItem.AWAY_SUB to matchdet[0].awaySubstitute)
}
swipeRefresh.snackbar("Added to favorite").show()
} catch (e: SQLiteConstraintException){
swipeRefresh.snackbar(e.localizedMessage).show()
}
}
private fun removeFromFavorite(){
try {
database.use {
delete(
FavoriteItem.TABLE_MATCH, "(MATCH_ID = {id})",
"id" to matchdet.get(0).idEvent )
}
swipeRefresh.snackbar("Removed from favorite").show()
} catch (e: SQLiteConstraintException){
swipeRefresh.snackbar(e.localizedMessage).show()
}
}
private fun setFavorite() {
if (isFavorite)
menuItem?.getItem(0)?.icon = ContextCompat.getDrawable(this, R.drawable.fav_white)
else
menuItem?.getItem(0)?.icon = ContextCompat.getDrawable(this, R.drawable.fav_white_border)
}
}
MatchDetailPresenter :
package com.example.riken.footballmatch.presenter
import com.example.riken.footballmatch.api.ApiRepository
import com.example.riken.footballmatch.api.TheSportDBApi
import com.example.riken.footballmatch.model.MatchResponse
import com.example.riken.footballmatch.model.TeamResponse
import com.example.riken.footballmatch.team.detmatch.MatcDetView
import com.google.gson.Gson
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import org.jetbrains.anko.doAsync
import org.jetbrains.anko.uiThread
class MatchDetailPresenter (
private val matchDetailView: MatcDetView,
private val apiRepository: ApiRepository,
private val gson: Gson) {
fun getDetailMatch (idEvent: String?) {
matchDetailView.loadingShow()
GlobalScope.launch (Dispatchers.Main){
val data = gson.fromJson(apiRepository.doRequest(TheSportDBApi.getMatchDetail(idEvent)).await(),
MatchResponse::class.java)
matchDetailView.loadingHide()
matchDetailView.matchListShow(data.events)
}
}
fun getAwayLogo (idTeam: String?) {
matchDetailView.loadingShow()
GlobalScope.launch (Dispatchers.Main){
val data = gson.fromJson(apiRepository.doRequest(TheSportDBApi.getTeamLogo(idTeam)).await(),
TeamResponse::class.java)
matchDetailView.loadingHide()
matchDetailView.showAwyLogo(data.teams)
}
}
fun getHomeLogo (idTeam: String?) {
matchDetailView.loadingShow()
GlobalScope.launch(Dispatchers.Main) {
val data = gson.fromJson(
apiRepository.doRequest(TheSportDBApi.getTeamLogo(idTeam)).await(),
TeamResponse::class.java
)
matchDetailView.loadingHide()
matchDetailView.showHomeLogo(data.teams)
}
}
}
HomeActivityTest :
package com.example.riken.footballmatch.view
import android.support.test.espresso.Espresso.onView
import android.support.test.espresso.action.ViewActions
import android.support.test.espresso.assertion.ViewAssertions.matches
import android.support.test.espresso.contrib.RecyclerViewActions
import android.support.test.espresso.matcher.ViewMatchers.isDisplayed
import android.support.test.espresso.matcher.ViewMatchers.withId
import android.support.test.rule.ActivityTestRule
import android.support.test.runner.AndroidJUnit4
import android.support.v7.widget.RecyclerView
import com.example.riken.footballmatch.R.id.*
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
#RunWith(AndroidJUnit4::class)
class HomeActivityTest {
#Rule
#JvmField var activityRule = ActivityTestRule(HomeActivity::class.java)
#Test
fun testFootballMatchBehaviour() {
delay()
onView(withId(recycle_first)).
check(matches(isDisplayed()))
onView(withId(recycle_first))
.perform(RecyclerViewActions.scrollToPosition<RecyclerView.ViewHolder>(7))
onView(withId(recycle_first))
.perform(RecyclerViewActions.actionOnItemAtPosition<RecyclerView.ViewHolder>(7, ViewActions.click()))
onView(withId(tvdetail_match_date))
.check(matches(isDisplayed()))
onView(withId(ivHome_detail))
.check(matches(isDisplayed()))
onView(withId(tvTeam_home_detail))
.check(matches(isDisplayed()))
onView(withId(tvScore_home_detail))
.check(matches(isDisplayed()))
onView(withId(ivAway_detail)).
check(matches(isDisplayed()))
onView(withId(tvTeam_away_detail))
.check(matches(isDisplayed()))
onView(withId(tvScore_away_detail))
.check(matches(isDisplayed()))
onView(withId(add_fav_fragment))
.perform(ViewActions.click())
ViewActions.pressBack()
}
private fun delay(){
try {
Thread.sleep(3000)
}catch (e : InterruptedException){
e.printStackTrace()
}
}
}
DetailActivity line 108 :Glide.with(this).load(data[0].team).into(ivAway_detail)
MatchDetailActivity line 40 : matchDetailView.showAwyLogo(data.teams)
HomeActivityTest line 40 : onView(withId(tvTeam_home_detail)).check(matches(isDisplayed()))
This question has already been asked, please see: You cannot start a load for a destroyed activity in relativelayout image using glide
In conclusion, instead of using "this" in your activity
Glide.with(***this***).load(data[0].team).into(ivHome_detail)
ivHome_detail.visible()
change "this" to "getApplicationContext" like so:
Glide.with(***getApplicationContext()***).load(data[0].team).into(ivHome_detail)
ivHome_detail.visible()