I want to create an app to download a song from an URL.
I made a Alertbox with EditText for the URL. This seems to work fine, but as soon as I want to assign the functions to the buttons inside the Alertbox, the app crashes as soon as I click on the Button to open the alertbox and I get a Nullpointer error.
See my cod below:
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:orientation="vertical"
android:padding="10dp">
<EditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/url"
android:hint="Enter URL"
android:inputType="textPersonName"
/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/downloadbtn"
android:text="Download"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/pastebtn"
android:text="Paste"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/cancelbtn"
android:text="Cancel"/>
</LinearLayout>
Kotlin:
package com.example.mymusicapp
import android.annotation.SuppressLint
import android.content.Intent
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.os.CancellationSignal
import android.view.LayoutInflater
import android.widget.Button
import android.widget.EditText
import android.widget.TextView
import androidx.appcompat.app.AlertDialog
//import the button didnt fix it: import com.example.mymusicapp.R.id.downloadbtn
class MainActivity : AppCompatActivity() {
#SuppressLint("MissingInflatedId")
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val songbtn = findViewById<Button>(R.id.btnsong)
val downloadbtn = findViewById<Button>(R.id.downloadbtn)
val pastebtn = findViewById<Button>(R.id.pastebtn)
val cancelbtn = findViewById<Button>(R.id.cancelbtn)
songbtn.setOnClickListener{
val mDialogView = LayoutInflater.from (this). inflate(R.layout.url_dialog, null)
val mBuilder = AlertDialog.Builder(this)
.setView(mDialogView)
.setTitle("Download MP3")
val mAlertDialog = mBuilder.show()
/* as soon as I use this code, the app crashes after clicking the "btnsong":
downloadbtn.setOnClickListener {
mAlertDialog.dismiss()
}
}
}
}
You cannot access a button inside a dialog directly using findviewbyid.
val btn=mAlertDialog.findViewById<Button>(R.id.downloadbtn)
or
val builder = AlertDialog.Builder(this)
val view = layoutInflater.inflate(R.layout.custom_dialog, null)
builder.setView(view)
val dialog = builder.create()
dialog.show()
val button = dialog.findViewById<Button>(R.id.my_button)
button.setOnClickListener {
Log.d("TAG", "Clicked")
dialog.dismiss()
}
Related
I am making a truth or dare app and let players before they start the game take a photo of the group they're playing it with. It's a simple take picture functionality and imageview above displaying the taken image by the user's camera.
I would like this picture to be displayed on another screen/activity. I was looking for ways to save the file locally so I could retrieve it in different activities but this didn't work. I'm not sure how to proceed with this as I've been looking all day for approaches to get it to work. Help is appreciated.
CameraActivity.KT
package com.example.test
import android.content.Intent
import android.net.Uri
import android.os.Bundle
import android.os.Environment
import android.provider.MediaStore
import android.widget.Button
import android.widget.ImageView
import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.FileProvider
import kotlinx.android.synthetic.main.activity_camera.*
import java.io.File
class CameraActivity : AppCompatActivity() {
lateinit var imgView: ImageView
lateinit var btnChange: Button
lateinit var imageUri: Uri
private val contract = registerForActivityResult(ActivityResultContracts.TakePicture()){
/*imgView.setImageURI(null)*/
imgView.setImageURI(imageUri)
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_camera)
val actionBar = supportActionBar
actionBar!!.title = "Take a picture of your group!"
actionBar.setDisplayHomeAsUpEnabled(true)
imgView = findViewById(R.id.imageViewId)
btnChange = findViewById(R.id.captureBtn)
imageUri = createImageUri()!!
captureBtn.setOnClickListener {
contract.launch(imageUri)
}
val PlayTruthOrDareGame = findViewById<Button>(R.id.playTruthOrDareGameBtn);
PlayTruthOrDareGame.setOnClickListener {
val intent = Intent(this, TruthOrDareActivity::class.java)
startActivity(intent)
}
}
private fun createImageUri():Uri?{
val image= File(applicationContext.filesDir, "camera_photo.png")
return FileProvider.getUriForFile(applicationContext,
"com.example.test.fileProvider",
image)
}
}
/layout/activity_camera.xml
It's able to convert android:src="#drawable/ic_baseline_image_24" to the image taken and I don't quite understand that. But trying this on DareActivity.xml doesn't work
<?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=".CameraActivity"
android:orientation="horizontal">
<ImageView
android:id="#+id/imageViewId"
android:layout_width="400dp"
android:layout_height="300dp"
android:src="#drawable/ic_baseline_image_24"
tools:ignore="MissingConstraints"
tools:layout_editor_absoluteX="5dp"
tools:layout_editor_absoluteY="66dp" />
<com.google.android.material.button.MaterialButton
android:id="#+id/captureBtn"
style="#style/Widget.MaterialComponents.Button.OutlinedButton"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Take picture"
app:layout_constraintTop_toBottomOf="#+id/imageViewId"
tools:ignore="MissingConstraints" />
<Button
android:id="#+id/playTruthOrDareGameBtn"
android:layout_width="410dp"
android:layout_height="wrap_content"
android:text="Play Game"
android:textSize="16dp"
android:textStyle="bold"
app:layout_constraintTop_toBottomOf="#+id/captureBtn"
tools:ignore="MissingConstraints" />
<TextView
android:id="#+id/errorMessage"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Error: Take a picture first!"
android:textSize="16dp"
android:textStyle="bold"
android:paddingTop="70dp"
android:layout_marginLeft="110dp"
android:visibility="invisible"
tools:ignore="MissingConstraints" />
</androidx.constraintlayout.widget.ConstraintLayout>
Manifest.xml
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<provider android:name="androidx.core.content.FileProvider"
android:authorities="com.example.test.fileProvider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="#xml/file_paths"/>
</provider>
/xml/file_paths
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<files-path
name="camera_photos"
path="." />
</paths>
I would like to display the image here and continiously throughout the players returning on this page
activity_daregame.xml
<ImageView
android:id="#+id/imageViewId"
android:layout_width="400dp"
android:layout_height="300dp"
android:src="#drawable/ic_baseline_image_24"
tools:ignore="MissingConstraints"
tools:layout_editor_absoluteX="5dp"
tools:layout_editor_absoluteY="66dp" />
DareActivity.KT
package com.example.test
import android.content.Context
import android.content.Intent
import android.net.Uri
import android.os.Build
import android.os.Bundle
import android.os.VibrationEffect
import android.os.Vibrator
import android.view.View
import android.widget.ImageView
import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.FileProvider
import kotlinx.android.synthetic.main.activity_camera.*
import kotlinx.android.synthetic.main.activity_daregame.*
import java.io.File
class DareActivity : AppCompatActivity() {
private var currentPosition:Int=1
private var questionList:ArrayList<DareQuestionData> ? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_daregame)
val actionBar = supportActionBar
actionBar!!.title = "You chose Dare!"
actionBar.setDisplayHomeAsUpEnabled(true)
questionList=DareData.getDareQuestion()
setQuestion()
acceptDare.setOnClickListener {
resultAcceptView.setVisibility(View.VISIBLE);
nextDare.setVisibility(View.VISIBLE)
acceptDare.setClickable(false)
rejectDare.setClickable(false)
val v = getSystemService(VIBRATOR_SERVICE) as Vibrator
// Vibrate for 500 milliseconds
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
v.vibrate(VibrationEffect.createOneShot(500, VibrationEffect.DEFAULT_AMPLITUDE))
} else {
//deprecated in API 26
v.vibrate(500)
}
}
rejectDare.setOnClickListener {
resultRejectView.setVisibility(View.VISIBLE);
nextDare.setVisibility(View.VISIBLE)
acceptDare.setClickable(false)
rejectDare.setClickable(false)
}
nextDare.setOnClickListener {
val intent = Intent(this, TruthOrDareActivity::class.java)
startActivity(intent)
}
}
fun setQuestion(){
val question = questionList!![currentPosition-1]
question_text.text=question.dareQuestion
}
}
How to make my recicle view visible on search field click in fragment and how to set search in this View?
Logcat shows, that "No adapter attached; skipping layout"
Code of home_fragment.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
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:layout_margin="8dp">
<LinearLayout
android:id="#+id/linearLayout"
android:layout_width="330dp"
android:layout_height="30dp"
android:gravity="center_vertical"
android:orientation="horizontal"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<ImageView
android:layout_width="62dp"
android:layout_height="match_parent"
android:src="#drawable/ic_baseline_search_24" />
<EditText
android:id="#+id/searchField"
android:layout_width="270dp"
android:layout_height="60dp"
android:ems="10"
android:hint="Поиск"
android:inputType="textPersonName"
tools:ignore="SpeakableTextPresentCheck" />
<ListView
android:id="#+id/listSearch"
android:layout_width="fill_parent"
android:layout_height="wrap_content" />
</LinearLayout>
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="30dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:listitem="#layout/list_item" />
</androidx.constraintlayout.widget.ConstraintLayout>
Code of HomeFragment
package com.example.booksh
import android.os.Bundle
import android.view.View
import androidx.fragment.app.Fragment
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.example.booksh.databinding.FragmentHomeBinding
class HomeFragment: Fragment(R.layout.fragment_home) {
private lateinit var binding: FragmentHomeBinding
private lateinit var newRecyclerView: RecyclerView
private lateinit var newArrayList: ArrayList<Books>
lateinit var imageId: Array<Int>
lateinit var heading: Array<String>
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
binding = FragmentHomeBinding.inflate(layoutInflater)
super.onViewCreated(binding.root, savedInstanceState)
// Поисковой список
imageId = arrayOf(
R.drawable.a,
R.drawable.b,
R.drawable.c,
R.drawable.d,
R.drawable.e,
R.drawable.f,
R.drawable.h,
R.drawable.i,
R.drawable.j
)
heading = arrayOf(
"Война и мир",
"Капитанская дочка",
"Раковый корпус",
"Мастер и маргарита",
"Муму",
"О дивный новый мир",
"Скотный двор",
"Портрет Дориана Грея",
"Отель с привидениями"
)
//Переменные для выпадающего списка на главной странице - поиск книг
newRecyclerView = binding.recyclerView
newRecyclerView.layoutManager = LinearLayoutManager(this.context)
newRecyclerView.setHasFixedSize(true)
newArrayList = arrayListOf()
getUserData()
}
//Заносим в список данные о книгах
private fun getUserData() {
for (i in imageId.indices){
val book = Books(imageId[i], heading[i])
newArrayList.add(book)
}
newRecyclerView.adapter = MyAdapter(newArrayList)
}
}
Code of adapter
package com.example.booksh
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView
import com.google.android.material.imageview.ShapeableImageView
class MyAdapter(private var booksList: ArrayList<Books>) : RecyclerView.Adapter<MyAdapter.MyViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
val itemView = LayoutInflater.from(parent.context).inflate(R.layout.list_item,
parent, false)
return MyViewHolder(itemView)
}
override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
val currentItem = booksList[position]
holder.titleImage.setImageResource(currentItem.titleImage)
holder.tvHeading.text = currentItem.heading
}
override fun getItemCount(): Int {
return booksList.size
}
class MyViewHolder(itemView: View): RecyclerView.ViewHolder(itemView){
val titleImage : ShapeableImageView = itemView.findViewById(R.id.list_item_icon)
val tvHeading: TextView = itemView.findViewById(R.id.list_item_text)
}
}
I made a ricycle view for main activity without visibility change, but it was shown in every fragment of my app. Then I copied all code connected with recyclerView to fragment home (xml, kt), but it became invisible whether I click on the search field or not.
I made a dialogue box and I put radio group in it and I add three radio button 1)male 2)female 3)others if user select male so the selected radio button male should be shown in text View
Here, I would like to share you here a simple app with both the activity and layout code. I hope this will help you.
First the layout
<?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="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical"
android:padding="100dp"
tools:context=".TestActivity">
<TextView
android:id="#+id/textView3"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingBottom="20dp"
android:text="What is your gender?"
android:textSize="20sp"
android:textStyle="bold" />
<TextView
android:id="#+id/txtViewGender"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingBottom="20dp"
android:text="-- Selected Gender --"
android:textSize="16sp" />
<Button
android:id="#+id/button"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Select" />
</LinearLayout>
Second the Main Activity code
import android.os.Bundle
import android.widget.Button
import android.widget.TextView
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import com.google.android.material.dialog.MaterialAlertDialogBuilder
class GenderActivity: AppCompatActivity() {
private lateinit var selectedGender: String
private var selectedGenderIndex: Int = 0
private val gender = arrayOf("Male", "Female", "Others")
private lateinit var txtViewGender: TextView
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_test4)
txtViewGender = findViewById<TextView>(R.id.txtViewGender)
var androidButton: Button = findViewById<Button>(R.id.button)
androidButton.setOnClickListener {
showRadioDialog()
}
}
private fun showRadioDialog() {
selectedGender = gender[selectedGenderIndex]
MaterialAlertDialogBuilder(this)
.setTitle("Select your gender")
.setSingleChoiceItems(gender, selectedGenderIndex) { dialog, which ->
selectedGenderIndex = which
selectedGender = gender[which]
}
.setPositiveButton("Ok") { dialog, which ->
Toast.makeText(this, "Selected --> $selectedGender ", Toast.LENGTH_SHORT)
.show()
txtViewGender.text = selectedGender
}
.setNegativeButton("Cancel") { dialog, which ->
dialog.dismiss()
}
.show()
}
}
When you run the code, you will get the following two screens.
Screen 1
Screen 2
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.
i have been facing this issue from 3-4 days and i still can't resolve this error. i have also gone through this a solution of the same problem
but i didn't understand enough. i got that, that this error occurs when we didn't attach our adapter but i have attached.
below i have attached my fragment file, adapter file and RecyclerView file-
this is a code where i declared my adapter
import android.content.Context
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.example.chumonsuru.R
import com.example.chumonsuru.model.Resturant
import com.squareup.picasso.Picasso
class DashboardRecyclerAdapter(val context : Context , val resturantInfoList : ArrayList<Resturant>) : RecyclerView.Adapter<DashboardRecyclerAdapter.DashboardViewHolder>(){
class DashboardViewHolder(view:View): RecyclerView.ViewHolder(view){
val txtResturantid : TextView = view.findViewById(R.id.txtResturantid)
val txtResturantName : TextView = view.findViewById(R.id.txtResturantName)
val txtPerPrice : TextView = view.findViewById(R.id.txtPerPrice)
val txtResturantRating : TextView = view.findViewById(R.id.txtResturantRating)
val imgResturantImage : ImageView = view.findViewById(R.id.imgResturantImage)
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): DashboardViewHolder {
val view = LayoutInflater.from(parent.context).inflate(R.layout.recycler_dashboard_row_one , parent , false)
return DashboardViewHolder(view)
}
override fun getItemCount(): Int {
return resturantInfoList.count()
}
override fun onBindViewHolder(holder: DashboardViewHolder, position: Int) {
val resturant = resturantInfoList[position]
holder.txtResturantid.text = resturant.id
holder.txtResturantName.text = resturant.name
holder.txtPerPrice.text = resturant.cost_for_one
holder.txtResturantRating.text = resturant.rating
Picasso.get().load(resturant.image_url).into(holder.imgResturantImage)
}
}
and here is my dashboard fragment file-
import android.content.Context
import android.os.Bundle
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.recyclerview.widget.DividerItemDecoration
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.android.volley.Request
import com.android.volley.Response
import com.android.volley.toolbox.JsonObjectRequest
import com.android.volley.toolbox.Volley
import com.example.chumonsuru.R
import com.example.chumonsuru.adapter.DashboardRecyclerAdapter
import com.example.chumonsuru.model.Resturant
import kotlin.collections.HashMap
class DashFrag : Fragment() {
lateinit var recyclerView: RecyclerView
lateinit var linearLayoutManager: LinearLayoutManager
lateinit var recyclerAdapter: DashboardRecyclerAdapter
val resturantInfoList = arrayListOf<Resturant>()
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
val view = inflater.inflate(R.layout.dash_frag, container, false)
linearLayoutManager = LinearLayoutManager(activity)
recyclerView = view.findViewById(R.id.recyclerView)
val queue = Volley.newRequestQueue(activity as Context)
val url = "http://13.235.250.119/v1/book/fetch_books/"
val jsonObjectRequest = object : JsonObjectRequest(Request.Method.GET, url, null, Response.Listener {
val success = it.getBoolean("success")
if (success != null) {
val data = it.getJSONArray("data")
for (i in 0 until data.length()) {
val resturantJsonObject = data.getJSONObject(i)
val resturantObject = Resturant(
resturantJsonObject.getString("id"),
resturantJsonObject.getString("name"),
resturantJsonObject.getString("rating"),
resturantJsonObject.getString("cost_for_one"),
resturantJsonObject.getString("image_url")
)
resturantInfoList.add(resturantObject)
recyclerAdapter = DashboardRecyclerAdapter(activity as Context, resturantInfoList)
recyclerView.adapter = recyclerAdapter
recyclerView.layoutManager = linearLayoutManager
recyclerView.addItemDecoration(DividerItemDecoration(recyclerView.context,
(linearLayoutManager)
.orientation))
}
}
},
Response.ErrorListener {
/////ERROR/////
}) {
override fun getHeaders(): MutableMap<String, String> {
val headers = HashMap<String, String>()
headers["Content-type"] = "application/json"
headers["token"] = "xyz"
return headers
}
}
queue.add(jsonObjectRequest)
return view
}
}
and
my restaurant class-
data class Resturant(
val id: String,
val name: String,
val rating: String,
val cost_for_one : String,
val image_url: String
)
my dashboard fragment xml file-
<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"
tools:context=".fragments.DashFrag">
<!-- TODO: Update blank fragment layout -->
<TextView
android:id="#+id/txtHelloFrag"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="#string/hello_blank_fragment"
android:textSize="50sp"
android:textColor="#color/colorAccent"
android:padding="20dp"
android:background="#drawable/gradient"/>
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="#+id/txtHelloFrag"
android:layout_margin="10dp"
android:padding="5dp"
/>
</RelativeLayout>
and the layout of the row of the recycler view
<?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="140dp"
android:orientation="horizontal"
android:background="#ffffff"
android:weightSum="6">
<ImageView
android:layout_weight="1.5"
android:id="#+id/imgResturantImage"
android:layout_width="0dp"
android:layout_height="110dp"
android:src="#mipmap/ic_launcher1"
android:padding="5dp"/>
<RelativeLayout
android:layout_weight="3.3"
android:layout_width="0dp"
android:layout_height="match_parent">
<TextView
android:padding="8dp"
android:id="#+id/txtResturantid"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="id"
android:layout_toLeftOf="#id/txtResturantName"
android:textSize = "18sp"
/>
<TextView
android:id="#+id/txtResturantName"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Name of the Resturant"
android:paddingTop="8dp"
android:textSize="18sp"
android:textColor="#000000"/>
<TextView
android:id="#+id/txtBookAuthor"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="#id/txtResturantName"
android:text="Name of the Author"
android:padding="8dp"
android:textSize="15sp"/>
<TextView
android:id="#+id/txtPerPrice"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:text="Rs. 299"
android:paddingTop="8dp"
android:paddingLeft="8dp"
android:layout_below="#id/txtBookAuthor"
android:textSize="15sp"
android:textStyle="bold"
android:textColor="#357a38"/>
<TextView
android:id="#+id/txtPerPerson"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="/person"
android:layout_toRightOf="#id/txtPerPrice"
android:textSize="15sp"
android:layout_below="#id/txtBookAuthor"
android:textColor="#357a38"
android:paddingTop="8dp"
android:textStyle="bold"/>
</RelativeLayout>
<TextView
android:id="#+id/txtResturantRating"
android:layout_weight="1.2"
android:layout_width="0dp"
android:padding="6dp"
android:layout_height="wrap_content"
android:drawableLeft="#drawable/star_foreground"
android:textColor="#ffca28"
android:text="4.5"
android:textSize="15sp"
android:textStyle="bold">
</TextView>
</LinearLayout>
i think i have already attached the adapter to my recycler view. if i didn't please help me to do this.
Please help me to get rid of this problem
I think something that you need to check.
return view
Instead of this, you have to use
return view;
second,
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="#+id/txtHelloFrag"
android:layout_margin="10dp"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
android:padding="5dp"
/>
You try to put app:layoutManager into that.
or
val layoutManager = LinearLayoutManager(this)
recyclerView_main.setLayoutManager(layoutManager)
As above, LayoutManager is set in the setLayoutManager and it processes as code.
LinearLayoutManager manager = new LinearLayoutManager(this);
recyclerView.setLayoutManager(manager);
this is related above, you have set the layout manager for RecyclerView
I hope that It will be work.