Which lifecycle state called after BottomSheet close? - android

I am using BottomSheet Dialog from a fragment. I want to reload fragment data after bottomsheet close.
I am trying by adding reload code in onResume method. But it is not working.
Here My BottomSheet Dialog code.
class LoopResponseDialogueFragment : BottomSheetDialogFragment() {
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?) =
inflater.inflate(R.layout.fragment_loop_response_dialog, container, false)!!
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
var progressDialog = ProgressDialog(context)
acceptButton.setOnClickListener {
priyoLoopService.sendLoopResponse(LoopActionRequest(user.id, "accept"))
.enqueue(object : Callback<GenericLoopResponse> {
override fun onFailure(call: Call<GenericLoopResponse>, t: Throwable) {
}
override fun onResponse(
call: Call<GenericLoopResponse>,
response: Response<GenericLoopResponse>
) {
dismiss()
}
})
}
}

You can create an interface in your LoopResponseDialogueFragment class and use it inside your fragment. Override onDismiss() and onCancel() function and call the interface function.
LoopResponseDialogueFragment Code:
class LoopResponseDialogueFragment : BottomSheetDialogFragment() {
private lateinit var onBottomSheetCloseListener:OnBottomSheetCloseListener
interface OnBottomSheetCloseListener{
fun onBottomSheetClose()
}
fun setOnBottomSheetCloseListener(listener:OnBottomSheetCloseListener) {
onBottomSheetCloseListener = listener
}
// rest of the code
override fun onDismiss(dialog: DialogInterface)
{
super.dismiss(dialog)
listener.onBottomSheetClose()
}
}
Now in your fragment before calling show method, call setOnBottomSheetCloseListener()
In your Fragment:
dialog.setOnBottomSheetCloseListener(object: OnBottomSheetCloseListener{
override fun onBottomSheetClose()
{
//refresh your data here
}
})
You can add code to refresh the fragment data inside onBottomSheetClose method.

Related

java.lang.ClassCastException: when register Listener in android

This is my interface
interface R2OnClickFullListener {
fun onFullScreen(fullscreen: Boolean)
}
This is my fragment
class Rove2LiveVideoFragment : BaseFragment()
{
private lateinit var onFullScreenListener: R2OnClickFullListener
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
return inflater.inflate(R.layout.fragment_new_livevideo2, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
showBigView()
}
override fun onAttach(context: Context) {
inject(this)
super.onAttach(context)
if (activity is OnFullScreenListener) {
onFullScreenListener = activity as R2OnClickFullListener
} else {
throw ClassCastException(
activity.toString()
+ " must implement MyListFragment.OnItemSelectedListener"
)
}
}
private fun showBigView(){
onFullScreenListener.onFullScreen(true)
}
}
This is my activity
class Rove2MainActivity : BaseActivity(),R2OnClickFullListener{
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
}
override fun onFullScreen(fullscreen: Boolean) {
}
}
But i am getting class cast exception basically i am trying to pass data from fragment to activity so on attach fragment i am registering callback please help what i am doing wrong why the class cast exception is coming
below is error
Process: com.rovedashcam.android, PID: 31327
java.lang.ClassCastException:
com.rovedashcam.newmodeule.rove2dashcam.main.home.view.Rove2MainActivity#82ae1e0
must implement MyListFragment.OnItemSelectedListener
at
com.rovedashcam.newmodeule.rove2dashcam.main.livevideo.view.Rove2LiveVideoFragment.onAttach(Rove2LiveVideoFragment.kt:80)
it should be
if (activity is Rove2MainActivity ) {
onFullScreenListener = activity as R2OnClickFullListener
} else {
throw ClassCastException(
activity.toString()
+ " must implement MyListFragment.OnItemSelectedListener"
)
}

Is it okay to delete a CompanionObject on a fragment?

So I'm working with Android Studio, and I found a video on youtube on how to set tab layout. I'm trying to create a fragment with new>Fragment>Fragment(Blank) and I'm following youtube instructions to remove everything else except onCreate and onCreateView in Fragment class. But when i try to put everything together, i get this error:
Classifier 'PemasukanFragment' does not have a companion object, and thus must be initialized here
I use AddActivity class to hold my fragment, the code look like this:
class AddActicity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_add_acticity)
setUpTabs()
}
private fun setUpTabs(){
val adapter= Adapter_AddActivity(supportFragmentManager)
adapter.addFragment(PemasukanFragment,"Pemasukan")
}
}
I have 2 fragment pages. The code look like this:
class PemasukanFragment : Fragment() {
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
arguments?.let {
}
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_pemasukan, container, false)
}
}
The other fragment page have a similar code to this. I also have adapter that look like this:
class Adapter_AddActivity(supportFragmentManager: FragmentManager) :
FragmentPagerAdapter(supportFragmentManager, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT) {
private val mFragmentList = ArrayList<Fragment>()
private val mFragmentListTitle = ArrayList<String>()
override fun getCount(): Int {
return mFragmentList.size
}
override fun getItem(position: Int): Fragment {
return mFragmentList[position]
}
override fun getPageTitle(position: Int): CharSequence? {
return mFragmentListTitle[position]
}
fun addFragment(fragment: Fragment, title: String){
mFragmentList.add(fragment)
mFragmentListTitle.add(title)
}
}
I don't know if companion objects can be removed. But if it can, how to solve this error? Any help is appreciated

Android - I can access ViewModel method from fragment but the method does not return the list

I recently started studying android kotlin and I am expecting this to have a very simple answer but I have a ViewModel which has a method called getDataComment and I want to call the method from my fragment and provide the needed argument for it. But when I try to call it, there's no build error, it just doesn't show the list.
My method in view model:
fun getDataComment(postId: Int) {
PostRepository().getDataComment(postId).enqueue(object : Callback<List<Comment>>{
override fun onResponse(call: Call<List<Comment>>, response: Response<List<Comment>>) {
val comments = response.body()
comments?.let {
mPostsComment.value = comments!!
}
}
override fun onFailure(call: Call<List<Comment>>, t: Throwable) {
Log.e(TAG, "On Failure: ${t.message}")
t.printStackTrace()
}
})
}
Fragment Class
class PostDetailFragment : Fragment() {
var param2: Int = 0
private lateinit var binding: FragmentPostDetailBinding
private val viewModel by viewModels<PostCommentViewModel>()
private val gson: Gson by lazy {
Gson()
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View {
binding =
DataBindingUtil.inflate(inflater, R.layout.fragment_post_detail, container, false)
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
checkArguments()
}
private fun checkArguments() {
arguments?.let { bundle ->
if (bundle.containsKey("POST")) {
val postString = bundle.getString("POST", "")
val post: Post = gson.fromJson(postString, Post::class.java)
binding.postDetailstvTitle.text = post.title
binding.postDetailstvBody.text = post.body
param2 = post.id
viewModel.getDataComment(param2)
}
}
}
}
Here's what it's supposed to look like: 1
Here's what I'm getting: 2
Sorry in advance if It's messy this is my first time asking here and let me know if you need more information. Thank you!
observe mPostsComment inside fragment from viewmodel
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
checkArguments()
viewModel.mPostsComment.observe(viewLifecycleOwner, { collectionList ->
// do whatever you want with collectionList
})
}

Why is my Viewpager not showing any fragments after opening the second time and why can childfragmentmanager not be used?

I have a Fragment (InnerFragment) placed inside a Viewpager (MainViewPager).
This Fragment (InnerFragment) does also contain a ViewPager (NestedViewPager) with multiple Fragments. When I swipe or open the InnerFragment everything works fine and the NestedViewPager shows all Fragments the way it should.
When I leave the InnerFragment after swiping the MainViewPager and go back to the InnerFragment it is blank and nothing shows up.
One solution as described in the internet is using the childfragmentmanager. Unfortunately this doesn't work because if I do so following exception is thrown.
java.lang.IllegalStateException: Fragment ProductImageFragment{c458f99 (1213d869-3715-4541-8nab-f87cyc350630) id=0x8f093165 android:switcher:2111xxxxxx:0} declared target fragment ProductImagesFragment{4b4f25e (99a6aaf6-5500-4821-902f-7bf30f87554c) id=0x7f090126 android:switcher:2131296550:2} that does not belong to this FragmentManager!
at androidx.fragment.app.FragmentManagerImpl.moveToState(FragmentManagerImpl.java:805)
Maybe it is also important to note, that the MainFragment is implementing an Interface of the Innerfragment.
MainFragment
class ProductImagesFragment : Fragment(),
ProductImageFragment.IProductImageHandler,
ProductImageUploadDialog.ProductImageUploadDialogEventListener {
private lateinit var viewPager: ViewPager
interface IProductImageUploadHandler{
fun onImageUploadToServerFinished(bitmap: Bitmap, imageData: ProductImage)
}
override fun onCreate(savedInstanceState: Bundle?)
{
super.onCreate(savedInstanceState)
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View?
{
return layoutInflater.inflate(R.layout.fragment_product_images,container,false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
viewPager = view.findViewById(R.id.viewPagerImages)
setViewPagerAdapter()
}
private fun setViewPagerAdapter(){
val manager = fragmentManager
if(manager!=null){
viewPager.adapter = product?.let {product ->
ImageAdapter(this,
product,productImageList,manager)
}
}
}
class ImageAdapter(private val productImagesFragment: ProductImagesFragment, private val product: Product, private val imagesList:ArrayList<ProductImage>, fragmentManager: FragmentManager) : FragmentPagerAdapter(fragmentManager) {
override fun getCount(): Int {
return imagesList.size
}
override fun getItem(position: Int): Fragment {
val fragment = ProductImageFragment()
val bundle = Bundle()
val image = imagesList[position]
bundle.putInt("productId",product.id)
bundle.putParcelable("productImage",image)
bundle.putInt("maxImages",imagesList.size)
fragment.setTargetFragment(productImagesFragment,1)
fragment.arguments = bundle
return fragment
}
}
}
InnerFragment
class ProductImageFragment : Fragment() {
private lateinit var productImageHandler: IProductImageHandler
interface IProductImageHandler{
fun onImageDeleted(id: Int)
fun onOrderChanged(url: String, newValue: Int, oldValue: Int)
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
}
override fun onAttach(context: Context) {
super.onAttach(context)
try {
productImageHandler = targetFragment as IProductImageHandler
}catch (exception: Exception){
}
}
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
return inflater.inflate(R.layout.fragment_product_image, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
}
private fun setValues(view: View){
}
}
You must use the childFragmentManager in order for the state to be restored properly.
You shouldn't be using the target fragment API at all. In fact, if you're using the childFragmentManager, your child fragments already have a reference to the parent via requireParentFragment() - just use that instead of targetFragment.
override fun onAttach(context: Context) {
super.onAttach(context)
try {
productImageHandler = requireParentFragment() as IProductImageHandler
}catch (exception: Exception){
}
}

How to handle API calls in fragments while using navGraph?

I'm using Navigation component in one of project which is having bottom navigation view with three menu items(for example home,profile and about). Landing page of my app is home fragment(for example) at which one API is called(in onCreateView() method) to get user lists; its working fine but whenever user navigates to some other page like profile and come back means again API gets called in home fragment.
I referred this link - https://github.com/googlesamples/android-architecture-components.git
class Home : Fragment() {
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?): View? {
// Inflate the layout for this fragment
val view = inflater.inflate(R.layout.fragment_home, container, false)
view.findViewById<Button>(R.id.signup_btn).setOnClickListener {
findNavController().navigate(R.id.action_home_to_registered)
}
callUserListApi()
return view
}
private fun callUserListApi() {
val client = ServiceGenerator.getApiService(requireContext()).getJsonbyWholeUrl("http://dummy.restapiexample.com/api/v1/employees")
client.enqueue(object : Callback<JsonArray> {
override fun onFailure(call: Call<JsonArray>, t: Throwable) {
println("callUserListApi onFailure ${t.message}")
}
override fun onResponse(call: Call<JsonArray>, response: Response<JsonArray>) {
println("callUserListApi onResponse ${response.isSuccessful}")
}
})
}
}
Using navigation componentthe fragment were recreate every time when you select the tab. So here i've inflate fragment if my view is null when come back to those fragment at that moment view is not null so fragment should not recreate.
private var homeFragment: View? = null
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
if (view == null){
homeFragment = inflater.inflate(R.layout.fragment_home, container, false)
callUserListApi()
}
return view
}
Using the Navigation component, the Fragment were recreated each time the it was selected on the navigation, meaning the onCreateView() is called that includes youre callUserListApi()
Since you are using AAC, you can create a ViewModel on your activity and initialize it, then re-initializing it from the Home(Fragment). Add a MutableLiveData() variable which you can check if you alread called callUserListApi().
Dont forget to call it inside onActivityCreated()
On Home
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
mainActivityViewModel.calledUserList.observe(viewLifecycleOwner, Observer {
if(it != true) {
callUserListApi()
}
})
}
private fun callUserListApi() {
val client = ServiceGenerator.getApiService(requireContext()).getJsonbyWholeUrl("http://dummy.restapiexample.com/api/v1/employees")
client.enqueue(object : Callback<JsonArray> {
override fun onFailure(call: Call<JsonArray>, t: Throwable) {
println("callUserListApi onFailure ${t.message}")
}
override fun onResponse(call: Call<JsonArray>, response: Response<JsonArray>){
println("callUserListApi onResponse ${response.isSuccessful}")
mainActivityViewModel.setCalledUserList(true)
}
})
}
Inside youre MainActivityViewModel
val _calledUserList = MutableLiveData<Boolean?>()
val calledUserList = _calledUserList
fun setCalledUserList(bool: Boolean?) {
_calledUserList.value = bool
}

Categories

Resources