How do i open fragment from fragment (kotlin) - android-fragments

I'm finding a way to move fragment to fragment by using ClickListener; but I have no idea how to move fragment to fragment.
I want move like this :
A fragment have 4 cardview
click 1 cardview : move to fragment B
click 2 cardview : move to fragment C
click 3 cardview : move to fragment D
click 4 cardview : move to fragment F
I have done fragment move to activity by using code below
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
power655Card.setOnClickListener {
val intent = Intent (getActivity(), Power655Activity::class.java)
getActivity()?.startActivity(intent)
}

In Kotlin, if you want to load various fragment inside activity, you can make one function which you call wherever required to load the fragment.
private fun loadFragment(fragment: Fragment){
val transaction = supportFragmentManager.beginTransaction()
transaction.replace(R.id.fl_main, fragment)
transaction.disallowAddToBackStack()
transaction.commit()
}
And if you want to load fragment from a fragment,
val transaction = activity.supportFragmentManager.beginTransaction()
transaction.replace(R.id.fl_main, SecondFragment())
transaction.disallowAddToBackStack()
transaction.commit()
In the above code spinnet, SecondFragment() is the instance of the fragment which you wish to load. So we can also pass the instance of the fragment as shown above.

You can use requireActivity().supportFragmentManager.beginTransaction() to make the fragments transactions you need to.

You can change fragment putting this in you listener:
val fragmentB = FragmentB()
activity.getSupportFragmentManager().beginTransaction()
.replace(R.id.layout_container, fragmentB, "fragmnetId")
.commit();
R.id.layout_container is the fragment container in you activity xml
fragmentId is the id of the fragment so you can refer to it later.

Related

Kotlin - Trying to populate spinner from Fragment using findViewById(), but context: this is throwing an error

Obligatory preface: I'm quite new to Kotlin and Android Studio. As the title states, I'm trying to populate a spinner in Android Studio from within a fragment. First, I had an issue with findViewById(R.id.spinner) but I believe I've resolved it by prefixing it with root..
Currently, the only error being thrown is the context: this line. Ultimately, I'd like to use this spinner to allow the user to filter by different NY boroughs (hence, boroughs_array. Here's my current code within the FilterFragment -- my attempt to populate the spinner begins below return root.
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
filtersViewModel =
ViewModelProviders.of(this).get(FiltersViewModel::class.java)
val root = inflater.inflate(R.layout.fragment_filters, container, false)
return root
val spinner: Spinner = root.findViewById(R.id.spinner)
// Create an ArrayAdapter using the string array and a default spinner layout
ArrayAdapter.createFromResource(
this,
R.array.boroughs_array,
android.R.layout.simple_spinner_item
).also { adapter ->
// Specify the layout to use when the list of choices appears
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item)
// Apply the adapter to the spinner
spinner.adapter = adapter
}
My current assumption is that this is not the right context, as I'm within a fragment. On the off-chance that this is correct, I'm not really sure how to handle this. If you can shine any sort of light on the issue, I will be eternally grateful.
You need to use use context!! instead of this. this refers to the current Fragment, which is not a Context. The current Fragment has a reference to the Context though, accessed via this.getContext(), or context for short.
The reason you need context!! is because getContext() is nullable (it may return null). It's safe in this case to 'force unwrap' (!!) because context will never be null inside onCreateView().
Another issue I've spotted, is you're returning from the onCreateView() function before you've set up the spinner.
Try this instead:
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
filtersViewModel = ViewModelProviders.of(this).get(FiltersViewModel::class.java)
val root = inflater.inflate(R.layout.fragment_filters, container, false)
val spinner: Spinner = root.findViewById(R.id.spinner)
// Create an ArrayAdapter using the string array and a default spinner layout
ArrayAdapter.createFromResource(
context!!,
R.array.boroughs_array,
android.R.layout.simple_spinner_item
).also { adapter ->
// Specify the layout to use when the list of choices appears
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item)
// Apply the adapter to the spinner
spinner.adapter = adapter
return root
}
Also, just for further clarification - you've probably seen some examples where this is passed in for context. This is often done inside of an Activity, since Activity does extend Context.
You can access context like this:
context?.let { context ->
ArrayAdapter.createFromResource(
context,
R.array.boroughs_array,
android.R.layout.simple_spinner_item
).also { adapter ->
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item)
spinner.adapter = adapter
}
}

android fragment running in the background

i have the following chain of call
in a fragment i call zxing integrator to scan qr code which returns the result in
onActivityResult(int requestCode,int resultCode,Intent data)
of the fragment
The onActivityResult calls an Asynctask,
new getStaffIdTask(choosen_schema_for_scanning,userid).execute((Void)null);
whose onPostExecute(final Boolean success) calls the fragments listener as..
if(mListener!=null)
mListener.onScannedStaff(tableName,Integer.parseInt(id),Integer.parseInt(userid));
Back on the host activity the onScannedStaff function is called and in it replaces a fragment
#Override
public void onScannedStaff(String tableName, int staffid,int staffUid)
{
getSupportActionBar().setTitle("Staff Profile");
Fragment fragment= StaffProfileFragment.newInstance(tableName,staffid,staffUid);
FragmentTransaction transaction=getSupportFragmentManager().beginTransaction();
transaction.replace(R.id.home_boss_base,fragment,"scannedstaff");
transaction.addToBackStack(null);
transaction.commit();
}
The problem is that this fragment runs in the background and its not showing any UI at all. I cant figure out how to show it
I have also faced the same issue. Use LinearLayout in the fragment. Background color should be white and it should be clickable.
And don't call UI element from OnPostExecute().that will give you some major memory leaks or errors.

In Kotlin ..How I can return from fragment to MainActivity

in my program I have MainActivity and many fragments..
I try the following code to return from fragment to MainActivity by
onBackpressed() method
override fun onBackPressed() {
if(drawer_layout.isDrawerOpen(GravityCompat.START)) {
drawer_layout.closeDrawer(GravityCompat.START)
}
else if (fragment != null) {
val intent = Intent(applicationContext, MainActivity::class.java)
intent.flags = Intent.FLAG_ACTIVITY_CLEAR_TOP
startActivity(intent)
}
else {
super.onBackPressed()
}
}
My first problem is:
it working good with Drawer and also open MainActivity
but program not closed ..these main that
super.onBackPressed()
not working ..why
My second problem is:
after else If I need to use
getActivity().onBackpressed()
instead of the old one..
Thanks All
Activities navigate to Activities via onBackPressed(). Fragments have to reside in an Activity (They are basically sub-Activities), so it doesn't make sense to navigate from a Fragment to an Activity via super.onBackPressed(). You should be navigating from Fragment to Fragment, or if you forgo Fragments then Activity to Activity.
To navigate back to the previous Fragment:
activity?.fragmentManager?.popBackStack()
To navigate to the previous activity:
activity?.finish()
or
onBackPressed()
or, from the activity if you have overriden the onBackPressed() method:
super.onBackPressed()
Without more context to your code I can't say either why it seems your final else statement is never called. It seems like you've got a bug with your if else statement as super.onBackPressed() would provide the desired result of closing whatever activity you were in (MainActivity?).
else if (fragment != null) {
val intent = Intent(applicationContext, MainActivity::class.java)
intent.flags = Intent.FLAG_ACTIVITY_CLEAR_TOP
startActivity(intent)
}
My guess is it has something to do with you creating another instance of MainActivity. On first back pressed you close the drawer. On the second you create another instance of MainActivity and navigate to it. On the third, even if super.onBackPressed() gets called it will navigate back to the first instance of MainActivity where fragment will probably never be null unless you're specifically assigning such, so on the fourth you create another instance of MainActivity and navigate to it. This is a loop that will never navigate back from the first MainActivity.
Suggestions: However you're displaying MainActivity, convert it to a Fragment and handle it accordingly. Another approach is instead of creating another instance of MainActivity hide the fragmentView and show the MainActivity view. I don't suggest setting your fragment to null as the fragmentManager may throw and error, so you should also change your if else logic to check for something else. Say maybe fragment.view.visibility == View.Visible if you go the route described.
For your first question as far as I can understand you should use
val activity = activity as MainActivity
activity.onBackPressed()
because super for your fragment is not MainActivity.
The easiest and most concise way (Kotlin):
requireActivity().addOnBackPressedCallback(viewLifecycleOwner,
OnbackPressedCallback{
startMainActivity() // Your action here...
true
}
)

Pass bundle from adapter to tab fragment

I have fragment1 with recycler view that displays list if cardviews
When I click on a card it goes to tabfragment which contains different tabs of which one is a detail tab with detail info of the selected card view.
In the adapter of the recycler where I listen for the onClick of the card view I grab all the detail info of the selected cardview and put it in a bundle.
I think I have to pass this to the main activity and retrieve it from the main activity with the detail fragment with an interface, but I can't seem to figure this out.
Where do I create the interface in the adapter? can someone give me some sample code and how do I send the bundle to Main Activity and retrieve it in the detail fragment? If you need me to post some part of the code let me know not sure what to post.
Thanks!
So I finally figured it out from notes all over.
Essentially I created a separate Interface.
package com.tiretire.apps.salesapp.Util;
import android.os.Bundle;
public interface OnClickProductItem {
public void onClickProductItem(Bundle bundle);
}
Send the bundle from the Adapter Class of the Recycler View via the interface to the Main Activity
private OnClickProductItem sendBundle;
sendBundle.onClickProductItem(bundle);
Then in the MainActivity Receive and have ready to send to DetailFragment:
#Override
public void onClickProductItem(Bundle bundle){
ProductBundle = bundle;
}
public Bundle SendProductBundle(){
return ProductBundle;
}
Last step retrieve from MainActivity into DetailFragment:
MainActivity mainActivity = (MainActivity)getActivity();
productBundle = mainActivity.SendProductBundle();
Hope this helps someone.

How to deal with FragmentPagerAdapter reusing Fragments?

So, I'm trying to use a ViewPager from Android's support v4 library, but there's some serious issues with how it (or FragmentPagerAdapter) deals with Fragments. For instance, I subclassed FragmentPagerAdapter to do the following:
public class MyPagerAdapter extends FragmentPagerAdapter
{
private ArrayList<Fragment> fragments = null;
private ArrayList<Data> data = null;
public MyPagerAdapter(FragmentManager fragmentManager, ArrayList<Data> data)
{
super(fragmentManager);
this.data = data;
fragments = new ArrayList<Fragment>();
for(Data datum : data)
{
MyDataFragment fragment = new MyDataFragment();
fragment.setData(datum);
fragments.add(fragment);
}
}
#Override
public Fragment getItem(int i)
{
return fragments.get(i);
}
#Override
public int getCount()
{
return fragments.size();
}
}
Now, I thought this would be sufficient, and that I could go on and implement MyDataFragment using the onCreateView method that Fragments typically implement. But I ran into an interesting problem. When I would navigate away from the Activity, and then back to it, the ViewPager would appear blank. Somehow, it was reusing Fragments by calling findFragmentByTag, then simply not even calling getItem, etc. What's worse, the Fragment would get no onCreateView event. So I figured I could utilize the ViewPager's Fragment caching by moving my onCreateView code, which primarily grabs references to the various Views the fragment inflates, to onAttach. The only problem is, that during onAttach, MyDataFragment's getView method always returns null. All of the examples for Fragments online describe that onCreateView should have all of your view setup code. Ok, fine. But then, when I create a method like MyDataFragment.setSomeField(String value), I need to use a reference to a TextView. Since onCreateView doesn't always get called (like, when Fragments are magically recycled by FragmentPagerAdapter, for instance), it's better to grab that reference in onAttach. However, during onAttach, the root view for the Fragment is still null (probably because onCreateView wasn't called in the first place)! No additional events happen after that (with the exception of onActivityCreated, which has nothing to do with the Fragment itself), so there's no place to do setup code. How is this supposed to work? Am I missing something important here, or was the Fragment system designed by a monkey?
I'm not sure that this is the right use case for a FragmentPagerAdapter (it sounds more like something you'd want to do with a ListAdapter).
From the FragmentPagerAdapter docs:
Implementation of PagerAdapter that represents each page as a Fragment
that is persistently kept in the fragment manager as long as the user
can return to the page.
This version of the pager is best for use when there are a handful of
typically more static fragments to be paged through, such as a set of
tabs. The fragment of each page the user visits will be kept in
memory, though its view hierarchy may be destroyed when not visible.
This can result in using a significant amount of memory since fragment
instances can hold on to an arbitrary amount of state. For larger sets
of pages, consider FragmentStatePagerAdapter.
I'd consider switching to the FragmentStatePagerAdapter or perhaps a ListAdapter.
If you want the createView to be called it will have to be recreated each time (destroy the old fragment and create new ones), but again I don't think that's quite what you want.

Resources