0

I have implemented a method that launches the BottomSheetDialog but I am facing this error

 android.view.WindowManager$BadTokenException: Unable to add window -- token null is not valid; is your activity running?
    at android.view.ViewRootImpl.setView(ViewRootImpl.java:907)
    at android.view.WindowManagerGlobal.addView(WindowManagerGlobal.java:387)
    at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:95)
    at android.app.Dialog.show(Dialog.java:342)
    at com.example.moveapplication.adapter.PostAdapter.openBottomSheet(PostAdapter.kt:136)
    at com.example.moveapplication.adapter.PostAdapter.onBindViewHolder$lambda-2(PostAdapter.kt:53)
    at com.example.moveapplication.adapter.PostAdapter.$r8$lambda$Ya4NMbtCP1ASbfWIkCscOWrPyOw(Unknown Source:0)
    at com.example.moveapplication.adapter.PostAdapter$$ExternalSyntheticLambda2.onClick(Unknown Source:4)
    at android.view.View.performClick(View.java:7125)
    at android.view.View.performClickInternal(View.java:7102)
    at android.view.View.access$3500(View.java:801)
    at android.view.View$PerformClick.run(View.java:27336)
    at android.os.Handler.handleCallback(Handler.java:883)
    at android.os.Handler.dispatchMessage(Handler.java:100)
    at android.os.Looper.loop(Looper.java:214)
    at android.app.ActivityThread.main(ActivityThread.java:7356)
    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:930)

Here is method called after an item click

private fun openBottomSheet(publisher: String) {
     val inflater = mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater
     val view = inflater.inflate(R.layout.bottom_sheet_dialog, null)
     val uImage = view.findViewById<ImageView>(R.id.sheetIvProfileImage)
     val uNumber = view.findViewById<TextView>(R.id.sheetTvOwnerNumber)
     val uEmail = view.findViewById<TextView>(R.id.tvOwnerEmail)
     val uAbout = view.findViewById<TextView>(R.id.tvOwnerAbout)
     val uTitle = view.findViewById<TextView>(R.id.sheetTvOwnerTitle)

     val ownersRef = FirebaseFirestore.getInstance().collection("owners").document(publisher)
     ownersRef.get().addOnSuccessListener { document ->
         val ownerModel = document.toObject(Owner::class.java)
         Glide.with(mContext)
             .load(ownerModel!!.profileImage)
             .into(uImage)
         uTitle.text = ownerModel.username
         uNumber.text = ownerModel.phoneNumber
         uEmail.text = ownerModel.email
         uAbout.text = ownerModel.about
     }

    val bottomSheetDialog = Dialog(mContext)
    bottomSheetDialog.apply {
        setContentView(view)
        setCancelable(true)
        window?.setLayout(
            LinearLayout.LayoutParams.MATCH_PARENT,
            LinearLayout.LayoutParams.WRAP_CONTENT)
        window?.setGravity(Gravity.BOTTOM)
        show()
    }

 }

I am not familiar with another way of doing inflating the bottomsheetdialog. Using the method was a trial to see if it could work.

on my onBindViewHolder the item responsible for click i've implemented it this way

 holder.publisher.setOnClickListener {
        openBottomSheet(post.publisher)
    }
Sam Kabiru
  • 75
  • 8
  • Create a interface and add to RecyclerView Adapter. Send your string to Fragment with this interface and create/call bottomSheetDialog in interface function in Fragment. – Crebain Jun 15 '22 at 08:01

3 Answers3

0

To do that you can easily use material design bottom sheet. first you need to add material dependency to your build.gradle:

dependencies {
    // ...
    implementation 'com.google.android.material:material:<version>'
    // ...
}

then you should create a kotlin file/class and extend BottomSheetDialogFragment()

class ModalBottomSheet : BottomSheetDialogFragment() {

    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? = inflater.inflate(R.layout.modal_bottom_sheet_content, container, false)
}

you can also set different styles to your custom bottomsheet

you can see the basic usage below:

class MainActivity : AppCompatActivity() {
    ...
    val modalBottomSheet = ModalBottomSheet()
    modalBottomSheet.show(supportFragmentManager, TAG)
    ...
}

Update

you can create an interface and use it in your adapter constructor to return the callback to the parent(where you create that adapter)

interface PostAdapterCallback{
    onPublisherClicked(publisher : String)
    //or
    onOwnerClicked(owner: Owner)
}

class PostAdapter(private val publisherList: List<String>, val callback:PostAdapterCallback){}

now you can take your model inside adapter and pass the Owner model as callback or you can pass your publisher to your Activity and call your FirebaseFirestore.getInstance() there.

in your activity:

override fun onOwnerClicked(owner : Owner){
    //you can call you bottomsheet here and pass you model as a bundle if you need
}
Payam Monsef
  • 296
  • 3
  • 6
  • The issue is not creating the bottomsheet but rather making it infalte with data from my recycler view. I cannot see clearly how this will be called from my recycler view – Sam Kabiru Jun 16 '22 at 05:42
  • @SamKabiru Creating bottom sheet in adapter is not best practice. you can create an interface for your adapter and return the callback to your fragment or activity. you have all the information you need in your adapter, so you can pass them with your callback to fragment – Payam Monsef Jun 19 '22 at 13:58
0

Create a interface

interface RecyclerClickListeners {
fun onRecyclerViewItemClick(view: View, model:Model) }

Add interface to RecyclerAdapter and Fragment

Fragment:

class TestFragment :
Fragment(),    
RecyclerClickListeners {
private val recyclerAdapter = TestRecyclerAdapter(arrayListOf(),this)... }

Recycler Adapter:

class TestRecyclerAdapter(private val modelList: ArrayList<Model>, val listener: RecyclerClickListeners) ...

Send your model in onBindViewHolder to Fragment

       holder.binding.root.setOnClickListener {
        listener.onRecyclerViewItemClick(it, modelList[position])
    }

In Fragment call or create bottomsheetdialog

override fun onRecyclerViewItemClick(view: View, model: Model) { openBottonSheetFragment(model) }

Now you can work with ownerModel in Bottom Sheet Fragment

Crebain
  • 180
  • 1
  • 8
  • And how will I be able to load data of that particular clicked item with its data from the recycler view? The Bottomesheet I'm tryig to implement involves loading data of the clicked item onto the bottomsheet. – Sam Kabiru Jun 16 '22 at 05:44
  • This is about ViewHolder Class of RecyclerView but i'm using viewBinding and call views with binding variable. holder.binding.root.setOnClickListener { listener.onRecyclerViewItemClick(it,modelList[position]) } Ok ? – Crebain Jun 16 '22 at 08:21
  • I am not using fragment rather an activity(Main activity) or what are you implying when you involve fragment in you example? – Sam Kabiru Jun 16 '22 at 17:14
0
private void showBottomSheetDialog() {

    final BottomSheetDialog bottomSheetDialog = new BottomSheetDialog(this);
    bottomSheetDialog.setContentView(R.layout.bottom_sheet_dialog);

    ...

    bottomSheetDialog.show();
}

call above function on recycler item click

Vasily Kabunov
  • 6,511
  • 13
  • 49
  • 53