Using wave file resource with MediaPlayer - android-studio

I am trying to learn Kotlin and Android Studio by following a tutorial in Java that creates a MediaPlayer and plays a wave file. I am trying to adapt the code to Kotlin:
MainActivity.kt:
package com.example.debugwaveres
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.content.Context
import android.media.MediaPlayer
import android.view.View
//class MainActivity(private val context: Context) : AppCompatActivity() {
class MainActivity : AppCompatActivity() {
private var player: MediaPlayer? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
}
fun play(view: View) {
if (player == null) {
player = MediaPlayer.create(this, R.raw.metro1)
player?.setOnCompletionListener {
//stopPlayer()
}
}
player?.start()
}
}
The .wav resource R.raw.metro1 has been copied to the res/raw resource directory:
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingLeft="16dp"
android:paddingRight="16dp"
android:gravity="center"
android:orientation="vertical" >
<Button
android:layout_width="99dp"
android:layout_height="wrap_content"
android:onClick="play"
android:text="Play" />
</LinearLayout>
This compiles fine in Android Studio using an AVD with target Android 9.0, but when I click the play button I get an Exception java.io.IOException: Prepare failed :
04/07 19:36:36: Launching 'app' on Pixel 2 API 28.
$ adb shell am start -n "com.example.debugwaveres/com.example.debugwaveres.MainActivity" -a android.intent.action.MAIN -c android.intent.category.LAUNCHER
Connected to process 11210 on device 'Pixel_2_API_28 [emulator-5554]'.
Capturing and displaying logcat messages from application. This behavior can be disabled in the "Logcat output" section of the "Debugger" settings page.
E/MediaPlayerNative: error (1, -2147483648)
D/MediaPlayer: create failed:
java.io.IOException: Prepare failed.: status=0x1
at android.media.MediaPlayer._prepare(Native Method)
at android.media.MediaPlayer.prepare(MediaPlayer.java:1282)
at android.media.MediaPlayer.create(MediaPlayer.java:983)
at android.media.MediaPlayer.create(MediaPlayer.java:954)
at com.example.debugwaveres.MainActivity.play(MainActivity.kt:18)
at java.lang.reflect.Method.invoke(Native Method)
at androidx.appcompat.app.AppCompatViewInflater$DeclaredOnClickListener.onClick(AppCompatViewInflater.java:397)
at android.view.View.performClick(View.java:6597)
at android.view.View.performClickInternal(View.java:6574)
at android.view.View.access$3100(View.java:778)
at android.view.View$PerformClick.run(View.java:25885)
at android.os.Handler.handleCallback(Handler.java:873)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:193)
at android.app.ActivityThread.main(ActivityThread.java:6669)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)

I tried your code. It works fine. But you can try like this:
fun play(view : View) {
if (player == null) {
player = MediaPlayer.create(this, R.raw.metro1)
player?.setOnCompletionListener {
//stopPlayer()
}
}
player?.setOnPreparedListener {
it.start()
}
}

Related

Passing arrayAdapter to ListViewAdapter in android

Am having problem while passing my arrayAdapter the ListViewAdapter in android using kotlin.
The error message java.lang.NullPointerException: Attempt to invoke virtual method 'void android.widget.ListView.setAdapter(android.widget.ListAdapter)' on a null object reference indicates that I am trying to call a method on an object reference which is null.
Here is my mainActivity:
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.widget.ArrayAdapter
import android.widget.ListView
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val lv = findViewById<ListView>(R.id.myList)
val array = arrayOf("test", "test", "test", "test", "test")
val myAdapter: ArrayAdapter<String> =
ArrayAdapter(this, android.R.layout.simple_list_item_1, array)
lv.adapter = myAdapter
}
}
Here is the Layout file:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/relativeLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingHorizontal="20dp"
tools:context=".MainActivity">
<ListView
android:id="#+id/myList"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginStart="20dp"
android:layout_marginEnd="20dp" />
</LinearLayout>
And here is the error that I got
Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'void android.widget.ListView.setAdapter(android.widget.ListAdapter)' on a null object reference
at com.example.myapplication5.MainActivity.onCreate(MainActivity.kt:16)
at android.app.Activity.performCreate(Activity.java:7994)
at android.app.Activity.performCreate(Activity.java:7978)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1309)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3422)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3601) 
at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:85) 
at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135) 
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95) 
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2066) 
at android.os.Handler.dispatchMessage(Handler.java:106) 
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) 
2022-12-25 14:33:52.075 14422-14438/com.example.myapplication5 W/System: A resource failed to call close.
Debug shows that myAdapter contains corretly the array values
You are passing ArrayAdapter where in error you can check it needs ListAdapter.
Attempt to invoke virtual method 'void android.widget.ListView.setAdapter(android.widget.ListAdapter)
You have to call setContentView(<Name of your layout file>) before accessing any views. See working example (in my case the name of the layout file is activity_main.xml):
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val lv = findViewById<ListView>(R.id.myList)
val array = arrayOf("test", "test", "test", "test", "test")
val myAdapter: ArrayAdapter<String> =
ArrayAdapter(this, android.R.layout.simple_list_item_1, array)
lv.adapter = myAdapter
}
}

W/RecyclerView: No adapter attached; skipping layout

I have made a basic shopping list app that utilises a recyclerview to display the list items. I am trying to add a settings screen using navigation with fragments. I am running into the issue where my recyclerview & data display when I open the app, however when I go to the settings menu then back to the main screen there's no recyclerview. Logcat shows the error "W/RecyclerView: No adapter attached; skipping layout"
MainActivity.kt
package com.example.shoppinglist
import android.app.Dialog
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.widget.Button
import android.widget.EditText
import android.widget.Toast
import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModelProvider
import androidx.navigation.findNavController
import androidx.navigation.ui.setupActionBarWithNavController
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.google.android.material.floatingactionbutton.FloatingActionButton
class MainActivity : AppCompatActivity(), RVAdapter.ListItemClickInterface {
lateinit var itemsRV: RecyclerView
lateinit var addFAB: FloatingActionButton
lateinit var list: List<ListItems>
lateinit var RVAdapter: RVAdapter
lateinit var viewModel: ViewModel
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
setupActionBarWithNavController(findNavController(R.id.fragment_main))
itemsRV = findViewById(R.id.recyclerView)
addFAB = findViewById(R.id.idFABAdd)
list = ArrayList<ListItems>()
RVAdapter = RVAdapter(list, this)
itemsRV.layoutManager = LinearLayoutManager(this)
itemsRV.adapter = RVAdapter
val repository = Repository(Database(this))
val factory = ViewModelFactory(repository)
viewModel = ViewModelProvider(this, factory).get(ViewModel::class.java)
viewModel.getAllListItems().observe(this, Observer {
RVAdapter.list = it
RVAdapter.notifyDataSetChanged()
})
addFAB.setOnClickListener {
openDialog()
}
}
override fun onSupportNavigateUp(): Boolean {
val navController = findNavController(R.id.fragment_main)
return navController.navigateUp() || super.onSupportNavigateUp()
}
fun openDialog() {
val dialog = Dialog(this)
dialog.setContentView(R.layout.add_dialog)
val cancelButton = dialog.findViewById<Button>(R.id.idBtnCancel)
val addButton = dialog.findViewById<Button>(R.id.idBtnAdd)
val itemEdt = dialog.findViewById<EditText>(R.id.idEditItemName)
val itemQuantityEdt = dialog.findViewById<EditText>(R.id.idEditItemQuantity)
cancelButton.setOnClickListener {
dialog.dismiss()
}
addButton.setOnClickListener {
val itemName: String = itemEdt.text.toString()
val itemQuantity: String = itemQuantityEdt.text.toString()
if (itemName.isNotBlank() && itemQuantity.isNotBlank()) {
val items = ListItems(itemName, itemQuantity)
viewModel.insert(items)
Toast.makeText(applicationContext, "Item Added", Toast.LENGTH_SHORT).show()
RVAdapter.notifyDataSetChanged()
dialog.dismiss()
} else {
Toast.makeText(applicationContext, "Enter All Info To Add Item",
Toast.LENGTH_SHORT)
.show()
}
}
dialog.show()
}
override fun onItemClick(listItems: ListItems) {
viewModel.delete(listItems)
RVAdapter.notifyDataSetChanged()
Toast.makeText(applicationContext, "Item Deleted", Toast.LENGTH_SHORT).show()
}
}
HomeFragment.kt
package com.example.shoppinglist
import android.os.Build
import android.os.Bundle
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.annotation.RequiresApi
import androidx.navigation.fragment.findNavController
import androidx.preference.PreferenceManager
import kotlinx.android.synthetic.main.fragment_home.*
class HomeFragment : Fragment() {
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_home, container, false)
}
#RequiresApi(Build.VERSION_CODES.N)
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
idFABSettings.setOnClickListener {
findNavController().navigate(R.id.action_homeFragment_to_settingsFragment)
}
loadSettings()
}
#RequiresApi(Build.VERSION_CODES.N)
private fun loadSettings(){
val sp = PreferenceManager.getDefaultSharedPreferences(context)
val theme = sp.getBoolean("theme_switch",false)
}
}
SettingsFragment.kt
package com.example.shoppinglist
import android.os.Bundle
import androidx.preference.PreferenceFragmentCompat
class SettingsFragment : PreferenceFragmentCompat() {
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
setPreferencesFromResource(R.xml.root_preferences, rootKey)
}
}
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=".MainActivity">
<fragment
android:id="#+id/fragment_main"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:defaultNavHost="true"
app:navGraph="#navigation/navigation"
/>
</RelativeLayout>
fragment_home.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:background="?attr/colorPrimary"
tools:context=".MainActivity">
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:listitem="#layout/list_rv_item"/>
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="#+id/idFABAdd"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:layout_alignParentBottom="true"
android:layout_marginStart="20dp"
android:layout_marginTop="20dp"
android:layout_marginEnd="20dp"
android:layout_marginBottom="20dp"
android:backgroundTint="?attr/colorSecondary"
android:contentDescription="Add Item Button"
android:src="#drawable/ic_add"
android:tint="#android:color/white" />
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="#+id/idFABSettings"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:layout_alignParentBottom="true"
android:layout_marginStart="20dp"
android:layout_marginTop="20dp"
android:layout_marginEnd="20dp"
android:layout_marginBottom="20dp"
android:backgroundTint="?attr/colorSecondary"
android:contentDescription="Add Item Button"
android:src="#drawable/ic_settings"
android:tint="#android:color/white" />
</RelativeLayout>
navigation.xml
<?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/navigation"
app:startDestination="#id/homeFragment">
<fragment
android:id="#+id/settingsFragment"
android:name="com.example.shoppinglist.SettingsFragment"
android:label="Settings" >
<action
android:id="#+id/action_settingsFragment_to_homeFragment"
app:destination="#id/homeFragment" />
</fragment>
<fragment
android:id="#+id/homeFragment"
android:name="com.example.shoppinglist.HomeFragment"
android:label="Shopping List"
tools:layout="#layout/fragment_home" >
<action
android:id="#+id/action_homeFragment_to_settingsFragment"
app:destination="#id/settingsFragment" />
</fragment>
</navigation>
Not sure if any more info is required. Apologies in advance - I am new to android studio & kotlin.
You are trying to work with views that are specific to HomeFragment's layout through the MainActivity. This will not work correctly. The first time you start the activity, in onCreate you use findViewById to find the view with ID recyclerView, and it successfully finds it because at that time the view is part of the HomeFragment, which is in the layout.
However, when you change fragments, the original fragment view is detached and removed. When you return to the first fragment, Android creates a new instance of your HomeFragment and its layout. The MainActivity is still referencing the original RecyclerView from the first instance of the HomeFragment, so it will update that view that is no longer on screen and it won't touch the new view. You have actually created a memory leak where the MainActivity is preventing that first fragment's view from being destroyed.
Another issue that you haven't discovered yet possibly is that if you rotate the screen while the SettingsFragment is open, you'll crash with a NullPointerException. This is because a screen rotation will cause a new Activity to be created, so onCreate() will be called again, and when it tries to find recyclerView when the HomeFragment is not in the layout, it will fail.
It doesn't make sense to work with a Fragment's specific views from the hosting Activity. The Activity should not have to know any details about what is in a Fragment and what to do with the contents of that fragment. All your code that has to do with the RecyclerView should be in HomeFragment.

run app shows old XML layout that no longer exists in the project

I have a simple android project where I'm populating a list of items in a database. To do this I'm using RecyclerView showing in my activity_main.xml
These are my two (and only two that exist) xml files
activity_main.xml
package com.twocrows.foretoldapp;
import androidx.appcompat.app.AppCompatActivity;
import androidx.lifecycle.Observer;
import androidx.lifecycle.ViewModelProvider;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import android.os.Bundle;
import com.twocrows.foretoldapp.adapter.ChartAdapter;
import com.twocrows.foretoldapp.entity.Chart;
import com.twocrows.foretoldapp.viewmodel.ChartViewModel;
import java.util.List;
public class MainActivity extends AppCompatActivity {
private ChartViewModel chartViewModel;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
RecyclerView recyclerView = findViewById(R.id.recycler_view);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
recyclerView.setHasFixedSize(true);
final ChartAdapter adapter = new ChartAdapter();
recyclerView.setAdapter(adapter);
chartViewModel = new ViewModelProvider(this, ViewModelProvider.AndroidViewModelFactory.getInstance(this.getApplication())).get(ChartViewModel.class);
chartViewModel.getAllCharts().observe(this, new Observer<List<Chart>>() {
#Override
public void onChanged(List<Chart> charts) {
adapter.setCharts(charts);
}
});
}
}
which shows in the preview like this
chart_item.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginEnd="8dp"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp">
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="8dp">
<TextView
android:id="#+id/text_view_location"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:layout_alignParentRight="true"
android:text="location"
android:textAppearance="#style/TextAppearance.AppCompat.Medium" />
<TextView
android:id="#+id/text_view_name"
android:layout_width="139dp"
android:layout_height="38dp"
android:layout_alignParentEnd="true"
android:layout_alignParentRight="true"
android:layout_marginEnd="248dp"
android:layout_marginRight="248dp"
android:layout_below="#+id/text_view_name"
android:text="Chart Name"
android:textAppearance="#style/TextAppearance.AppCompat.Large"
tools:ignore="NotSibling" />
<TextView
android:id="#+id/text_view_dateTime"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="#+id/text_view_name"
android:text="MM/DD/YYYY"/>
</RelativeLayout>
</androidx.cardview.widget.CardView>
MainActivity.java
package com.twocrows.foretoldapp;
import androidx.appcompat.app.AppCompatActivity;
import androidx.lifecycle.Observer;
import androidx.lifecycle.ViewModelProvider;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import android.os.Bundle;
import com.twocrows.foretoldapp.adapter.ChartAdapter;
import com.twocrows.foretoldapp.entity.Chart;
import com.twocrows.foretoldapp.viewmodel.ChartViewModel;
import java.util.List;
public class MainActivity extends AppCompatActivity {
private ChartViewModel chartViewModel;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
RecyclerView recyclerView = findViewById(R.id.recycler_view);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
recyclerView.setHasFixedSize(true);
final ChartAdapter adapter = new ChartAdapter();
recyclerView.setAdapter(adapter);
chartViewModel = new ViewModelProvider(this, ViewModelProvider.AndroidViewModelFactory.getInstance(this.getApplication())).get(ChartViewModel.class);
chartViewModel.getAllCharts().observe(this, new Observer<List<Chart>>() {
#Override
public void onChanged(List<Chart> charts) {
adapter.setCharts(charts);
}
});
}
}
The issue is that whenever I try to run the app, it's showing me an old version of the main activity xml file. I no longer even have these components in the xml so I don't understand where they are coming from.
#Things I've tried
Invalidate cache/ restart
clean build
edit configuration, uncheck 'skip installation if apk has not changed'
Nothing so far has worked. Any help would be appreciated. Thanks!
The issue of your app showing an old version of the activity_main.xml, even though you no longer have those components in the file, may be due to having two different layout resource files for a single activity.
You can check your layout resource directory to see if you have two different versions of the main activity layout file, such as "main.xml" and "main.xml(v21)", which may be causing the confusion. You can see the reason for having multiple files in this answer.
In this case, the solution would be to make sure that you're editing the correct layout file. If you edited an XML file but your emulator is running the v21 file, you can copy your code and paste it into the other file.
If you've made changes to the correct file but are still seeing the old version in the emulator, you can try cleaning and rebuilding the project, or even deleting the app from the emulator and reinstalling it.
If you continue to experience the issue, you may also want to check the AndroidManifest.xml file to ensure that the correct layout file is being used for the main activity. This file can be found in the "app" directory of your project.

Unresolved references to an array and to simple_spinner_item layout

My layout includes
<Spinner
android:id="#+id/spinnerCategory"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginLeft="16dp"
app:layout_constraintBottom_toBottomOf="#+id/lblCategory"
app:layout_constraintStart_toEndOf="#+id/lblCategory"
app:layout_constraintTop_toTopOf="#+id/lblCategory" />
Strings.xml
<resources>
<string name="app_name">nearby</string>
<string-array name="categories">
<item>Any</item>
<item>Church</item>
<item>NT</item>
</string-array>
MainActivity.kt (only partially completed, so far)
package com.example.nearby
import android.os.Bundle
import android.widget.ArrayAdapter
import android.widget.Spinner
import androidx.appcompat.app.AppCompatActivity
import kotlinx.android.synthetic.main.temp_layout.*
class MainActivity : AppCompatActivity() {
var mCategoryFilter = ""
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.temp_layout)
getInputs()
}
fun getInputs() {
if (!txtLat.toString().equals("")) {
var temp = txtLat.text.toString().toDouble()
mLatitude = temp.toFloat()
}
if (!txtLong.toString().equals("")) {
mLongitude = txtLong.text.toString().toFloat()
}
val spinner: Spinner = findViewById(R.id.spinnerCategory)
val adapter = ArrayAdapter.createFromResource(
this,
R.array.categories, R.layout.simple_spinner_item
)
adapter.setDropDownViewResource(R.layout.simple_spinner_dropdown_item)
spinner.adapter = adapter
}
}
Android Studio marks the following as "unresolved references"
the word "array" in R.array.categories
"simple_spinner_item"
"simple_spinner_dropdown_item"
How do I resolve these references?
Solution
Mike M's suggestion that I use the Invalidate Caches/Restart option seems to have solved the reference to "array".
The simple_spinner layout references need to be prefixed with android (with lower case a), as in android.R.layout.simple_spinner_item.
Beware, if using Android Studio's automatic conversion of Java code to Kotlin. It seems to have been this that deleted "android" from the layout references.

Bottom Navigation View with activities not working in Kotlin

I am new to Kotlin, so I am having trouble on how to solve this.
I have created a bottom navigation view that I am using to switch between activities. When I call the BottomNavigationView.OnNavigationItemSelectedListener my app crashes and I dont know why. Can anyone please help?
I have searched, but I only find answers on fragments.
My MainActivity code:
class MainActivity : AppCompatActivity() {
private val navigasjonen = BottomNavigationView.OnNavigationItemSelectedListener { item ->
when (item.itemId) {
R.id.home -> {
return#OnNavigationItemSelectedListener false
}
R.id.leggTilNavigasjon -> {
val intent = Intent(this#MainActivity, AddRec::class.java)
startActivity(intent)
return#OnNavigationItemSelectedListener true
}
R.id.favoritter -> {
val intent = Intent(this#MainActivity, MyRecipes::class.java)
startActivity(intent)
return#OnNavigationItemSelectedListener true
}
R.id.utforsk -> {
return#OnNavigationItemSelectedListener true
}
}
false
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val bottomNavigation = findViewById<BottomNavigationView>(R.id.bottom_navigation)
//bottomNavigation.setSelectedItemId(R.id.home)
bottomNavigation.setOnNavigationItemSelectedListener(navigasjonen)
}
}
My xml code:
<?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"
android:background="#color/colorLys"
android:id="#+id/home">
<com.google.android.material.bottomnavigation.BottomNavigationView
android:id="#+id/navigationView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
android:background="?android:attr/windowBackground"
app:menu="#menu/navigasjon" />
</androidx.constraintlayout.widget.ConstraintLayout>
My error:
2020-01-27 14:20:06.197 20309-20309/com.example.foodleaks E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.foodleaks, PID: 20309
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.foodleaks/com.example.foodleaks.MainActivity}: java.lang.NullPointerException: Attempt to invoke virtual method 'void com.google.android.material.bottomnavigation.BottomNavigationView.setOnNavigationItemSelectedListener(com.google.android.material.bottomnavigation.BottomNavigationView$OnNavigationItemSelectedListener)' on a null object reference
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2913)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3048)
at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:78)
at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:108)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:68)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1808)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:193)
at android.app.ActivityThread.main(ActivityThread.java:6669)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)
Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'void com.google.android.material.bottomnavigation.BottomNavigationView.setOnNavigationItemSelectedListener(com.google.android.material.bottomnavigation.BottomNavigationView$OnNavigationItemSelectedListener)' on a null object reference
at com.example.foodleaks.MainActivity.onCreate(MainActivity.kt:39)
at android.app.Activity.performCreate(Activity.java:7136)
at android.app.Activity.performCreate(Activity.java:7127)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1271)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2893)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3048) 
at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:78) 
at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:108) 
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:68) 
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1808) 
at android.os.Handler.dispatchMessage(Handler.java:106) 
at android.os.Looper.loop(Looper.java:193) 
at android.app.ActivityThread.main(ActivityThread.java:6669) 
at java.lang.reflect.Method.invoke(Native Method) 
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493) 
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858) 
In your findViewById you are passing R.id.bottom_navigation:
val bottomNavigation = findViewById<BottomNavigationView>(R.id.bottom_navigation)
and in the layout it has the id:
android:id="#+id/navigationView"
You can either change the id on the layout:
android:id="#+id/bottom_navigation"
Or change it in the findViewById:
val bottomNavigation = findViewById<BottomNavigationView>(R.id.navigationView)
Be consistent so that it can find the BottomNavigationView element and it won't crash for a null object reference.
The error is present in the stacktrace. I recommend learning to read Java/Android stacktraces :)
The culprit in stacktrace:
Attempt to invoke virtual method 'void com.google.android.material.bottomnavigation.BottomNavigationView.setOnNavigationItemSelectedListener(com.google.android.material.bottomnavigation.BottomNavigationView$OnNavigationItemSelectedListener)' on a null object reference
Your BottomNavigationView is null. Why?
Look at your declaration in layout:
<com.google.android.material.bottomnavigation.BottomNavigationView
android:id="#+id/navigationView
And that's how you find the view:
findViewById<BottomNavigationView>(R.id.bottom_navigation)
You are using wrong view id.

Resources