I want to add more Fragment page in my adapt but I do not know how to do.
here is my code adpater with a single Fragment that works without problem.
thank you in advance for your help
class TabAdapter(fragmentManager: FragmentManager) : FragmentPagerAdapter(fragmentManager) {
override fun getItem(position: Int) = SampleFragment() //SampleFragment() is my fragment
override fun getCount() = 4
override fun getPageTitle(position: Int) = when (position) {
0 -> "Music"
1 -> "Market"
2 -> "Films"
else -> "Books"
}
}
And this is the code for my SampleFragment()
class SampleFragment : Fragment() {
override fun onCreateView(inflater: LayoutInflater?, container: ViewGroup?,
savedInstanceState: Bundle?): View? {
return inflater!!.inflate(R.layout.fragment_sample, container, false)
}
}
Please help me to add each different Fragment for each Pagetitle in Adapter
Here's how to quickly add fragments into your adapter.
You require a ViewPager to hold all fragments you want to display.
Firstly edit your xml as follows.
<RelativeLayout
android:id="#+id/main_layout"
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="wrap_content"
tools:context=".MainActivity">
<ViewPager
android:id="#+id/pager"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="#id/tab_layout" />
<android.support.design.widget.TabLayout
android:id="#+id/tab_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/colorPrimary"
android:elevation="6dp"
android:minHeight="?attr/actionBarSize"
android:theme="#style/ThemeOverlay.AppCompat.Dark.ActionBar"/>
</RelativeLayout>
Next Create new fragment and name it Fragment_one.java. Inside here you can do whatever you want like an activity. Create Fragment_two.java or as many as you want and instantiate it in your adapter.
Next create fragmentAdapter.Java and add these code (This is for your custom adapter)
public class fragmentAdapter extends FragmentStatePagerAdapter {
int mNumOfTabs;
public fragmentAdapter(FragmentManager fm, int NumOfTabs){
super(fm);
this.mNumOfTabs = NumOfTabs;
}
#Override
public Fragment getItem(int position) {
// Add as many fragment in this method
switch (position){
case 0:
Fragment_one frag_one = new Fragment_one ();
return frag_one;
case 1:
Fragment_two frag_two = new Fragment_two ();
return frag_two;
default:
return null;
}
}
#Override
public int getCount() {
return mNumOfTabs;
}
}
Next add this inside onCreate() method in your MainActivity.java
TabLayout tabLayout = (TabLayout) view.findViewById(R.id.tab_layout);
//add as many fragments you want to add the "fragment 1" & "fragment 2" is
//the title for your fragments, it starts for '0','1','2'...
tabLayout.addTab(tabLayout.newTab().setText("fragment 1"));
tabLayout.addTab(tabLayout.newTab().setText("fragment 2"));
tabLayout.setTabGravity(TabLayout.GRAVITY_FILL);
ViewPager viewPager = (ViewPager) findViewById(R.id.pager);
final fragmentAdapter adapter = new Adapter(getActivity(),tablayout.geTabCount());
viewPager.setAdapter(adapter);
Related
I'm new in Android Studio and having trouble opening fragment on click CardView in other fragment. I have Navigation View in layout and navigate to other fragment (fragment_home, fragment_gallery, fragment_slideshow, and other fragment layout.). But I have to create CardView in fragment_home to click for open some fragment layout (Gallery and Slideshow).
I have layout:
1. fragment_home.xml
<?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="match_parent"
android:layout_height="match_parent"
tools:context=".ui.home.HomeFragment">
<androidx.cardview.widget.CardView
android:id="#+id/cardOpenGallery"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:layout_margin="20dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="80dp"
android:background="#ccc">
<TextView
android:id="#+id/textOpenGallery"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="15dp"
android:textAlignment="center"
android:textSize="30sp"
android:textColor="#000"
android:text="Open Gallery"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</LinearLayout>
</androidx.cardview.widget.CardView>
</LinearLayout>
2. fragment_gallery.xml
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout 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=".ui.gallery.GalleryFragment">
<!-- other layout element here -->
</FrameLayout>
3. fragment_slideshow.xml
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout 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=".ui.gallery.SlideshowFragment">
<!-- other layout element here -->
</FrameLayout>
And Kotlin code,
1. MainActivity.kt
import ...
class MainActivity : AppCompatActivity() {
private lateinit var appBarConfiguration: AppBarConfiguration
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val toolbar: Toolbar = findViewById(R.id.toolbar)
setSupportActionBar(toolbar)
val fab: FloatingActionButton = findViewById(R.id.fab)
fab.setOnClickListener { view ->
Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
.setAction("Action", null).show()
}
val drawerLayout: DrawerLayout = findViewById(R.id.drawer_layout)
val navView: NavigationView = findViewById(R.id.nav_view)
val navController = findNavController(R.id.nav_host_fragment)
// Passing each menu ID as a set of Ids because each
// menu should be considered as top level destinations.
appBarConfiguration = AppBarConfiguration(setOf(
R.id.nav_home, R.id.nav_gallery, R.id.nav_slideshow), drawerLayout)
setupActionBarWithNavController(navController, appBarConfiguration)
navView.setupWithNavController(navController)
}
override fun onCreateOptionsMenu(menu: Menu): Boolean {
// Inflate the menu; this adds items to the action bar if it is present.
menuInflater.inflate(R.menu.main, menu)
return true
}
override fun onSupportNavigateUp(): Boolean {
val navController = findNavController(R.id.nav_host_fragment)
return navController.navigateUp(appBarConfiguration) || super.onSupportNavigateUp()
}
}
2. HomeFragment.kt
import ...
class HomeFragment : Fragment() {
private lateinit var homeViewModel: HomeViewModel
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
homeViewModel =
ViewModelProviders.of(this).get(HomeViewModel::class.java)
val root = inflater.inflate(R.layout.fragment_home, container, false)
//I have problem here-----
val myCard1 = root.findViewById(R.id.cardOpenGallery) as CardView
myCard1.setOnClickListener(object : View.OnClickListener {
override fun onClick(v: View?) {
inflater.inflate(R.layout.fragment_gallery, container, false)
}
})
return root
}
}
3. GalleryFragment.kt
import ...
class GalleryFragment : Fragment() {
private lateinit var galleryViewModel: GalleryViewModel
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
galleryViewModel =
ViewModelProviders.of(this).get(GalleryViewModel::class.java)
val root = inflater.inflate(R.layout.fragment_gallery, container, false)
val textView: TextView = root.findViewById(R.id.text_gallery)
galleryViewModel.text.observe(viewLifecycleOwner, Observer {
textView.text = it
})
return root
}
}
4. SlideshowFragment.kt
import ...
class SlideshowFragment : Fragment() {
private lateinit var slideshowViewModel: SlideshowViewModel
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
slideshowViewModel =
ViewModelProviders.of(this).get(SlideshowViewModel::class.java)
val root = inflater.inflate(R.layout.fragment_slideshow, container, false)
val textView: TextView = root.findViewById(R.id.text_slideshow)
slideshowViewModel.text.observe(viewLifecycleOwner, Observer {
textView.text = it
})
return root
}
}
How to implement action for CardView click to open other fragment?, Please help and Thank for your any solution. Thanks.
You need to open another fragment here. For this you need to replace the fragment container in MainActivity with the desired fragment.
Replace this
myCard1.setOnClickListener(object : View.OnClickListener {
override fun onClick(v: View?) {
inflater.inflate(R.layout.fragment_gallery, container, false)
}
})
with this
myCard1.setOnClickListener(object : View.OnClickListener {
override fun onClick(v: View?) {
((Activity) getContext).supportFragmentManager.beginTransaction()
.replace(R.id.fragment_container, GalleryFragment())
.commit()
}
})
I hope this will work for you.
Happy Coding :)
You're just trying to inflate the fragment_gallery inside your homeFragment. I don't think it's the right way to do it. Although, I'll suggest the approach I use.
Inside your activity_main.xml add the FrameLayout. which will be useful to add/replace the desired fragment into it.
<FrameLayout
android:id="#+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
Now in your Activity, create the following function. It will help you to replace the desired fragment.
private fun replaceFragment(fragmentInstance: Fragment) {
supportFragmentManager
.beginTransaction()
.addToBackStack(fragmentInstance.javaClass.canonicalName)//optional
.replace(R.id.container, fragmentInstance)
.commit()
}
Now, inside onCreate load the homeFragment (as it is your first fragment to show)
override fun onCreate(savedInstanceState: Bundle?) {
val fragment = HomeFragment()
replaceFragment(fragment)
}
At this stage, you'll be able to load homeFragment successfully. Now next step is to create a callback interface. Every time you click on any card from the homeFragment you just have to provide the required information back to the mainActivity. It is good practice to leaving the responsibility of loading fragments on the activity.
interface OnCardClickListener {
fun onCardClick(fragment: Fragment)
}
implement this listener in MainActivity.
class MainActivity: OnCardClickListener{
It will override the onCardClick. now inside onCardClick call the replace method.
override onCardClick(fragment: Fragment){
replaceFragment(fragment)
}
Inside HomeFragment, Create an instance of OnCardClickListener
var listener: OnCardClickListener? = null
then in onAttach.
override fun onAttach(context: Context) {
super.onAttach(context)
listener = context as OnCardClickListener
}
Till this point, we have implemented the mechanism required to load fragment. Now only one final step is pending which is opening the desired fragment onClick of cardView. for that do as follow:
myCard1.setOnClickListener{
listener.onCardClick(GalleryFragment())
}
//If there's one more card available.
myCard2.setOnClickListener{
listener.onCardClick(SlideshowFragment())
}
Description
I have one activity in the vertical orinentation with two tabs (TabLayout) and fragments, which change with Viewpager.
MainActivity.java
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ViewPager viewPager = (ViewPager) findViewById(R.id.pager);
// Assign created adapter to viewPager
viewPager.setAdapter(new TabsExamplePagerAdapter(getSupportFragmentManager()));
TabLayout tabLayout = (TabLayout) findViewById(R.id.tab_layout);
// This method setup all required method for TabLayout with Viewpager
tabLayout.setupWithViewPager(viewPager);
}
public class TabsExamplePagerAdapter extends FragmentPagerAdapter {
// As we are implementing two tabs
private static final int NUM_ITEMS = 2;
public TabsExamplePagerAdapter(FragmentManager fm) {
super(fm);
}
#Override
// For each tab different fragment is returned
public Fragment getItem(int position) {
switch (position) {
case 0:
return new TabOneFragment();
case 1:
return new TabTwoFragment();
default:
return null;
}
}
#Override
public int getCount() {
return NUM_ITEMS;
}
#Override
public CharSequence getPageTitle(int position) {
return "Tab " + (position + 1);
}
}
}
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"
android:paddingBottom="#dimen/activity_vertical_margin"
tools:context=".MainActivity">
<android.support.design.widget.TabLayout
android:id="#+id/tab_layout"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
app:tabTextColor="#ffffff"
app:tabIndicatorColor="#fbff3a"
app:tabSelectedTextColor="#fbff3a"
app:tabIndicatorHeight="5dp"
android:elevation="4dp"
app:tabGravity="fill"
app:tabMaxWidth="0dp" />
<android.support.v4.view.ViewPager
android:id="#+id/pager"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</RelativeLayout>
In each tabs i have for one fragments.
TabOneFragment.java (TabTwoFragment is similar ):
public class TabOneFragment extends Fragment {
// Required empty public constructor
public TabOneFragment() { }
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_tab_one, container, false);
}
}
fragment_one_tab.xml (fragment_one_tab.xml is similar)
<FrameLayout 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="innovatecode.com.tabexample.TabOneFragment">
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:textSize="18dp"
android:text="#string/tab_one" />
</FrameLayout>
And i have simply result:
My problem
When my device is rotated to the horizontal position, I want to get the following result:
I create xml for horizontal markup (land):
active_main.xml (land)
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/root"
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
<FrameLayout
android:id="#+id/fragment_left"
android:layout_weight="2"
android:layout_width="0dp"
android:layout_height="match_parent" />
<FrameLayout
android:id="#+id/fragment_right"
android:layout_weight="2"
android:layout_width="0dp"
android:layout_height="match_parent" />
</LinearLayout>
But I don't know how to change my code to get this result. I'm not very strong in working with fragments.
First, you can improve your landscape layout by adding your fragments directly to the layout file (under "res/layout-land"):
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/root"
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
<fragment
android:name="innovatecode.com.tabexample.TabOneFragment"
android:id="#+id/fragment_left"
android:layout_weight="1"
android:layout_width="0dp"
android:layout_height="match_parent" />
<fragment
android:name="innovatecode.com.tabexample.TabTwoFragment"
android:id="#+id/fragment_right"
android:layout_weight="1"
android:layout_width="0dp"
android:layout_height="match_parent" />
</LinearLayout>
You can read move on the topic here.
For the code part, you could make use of distinct features of your landscape and portrait layouts to switch between the corresponding logic in code. For example:
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if (findViewById(R.id.tab_layout) != null) {
setUpPortraitLayout();
} else {
setUpLandscapeLayout();
}
}
private void setUpPortraitLayout() {
ViewPager viewPager = findViewById(R.id.pager);
// Assign created adapter to viewPager
viewPager.setAdapter(new TabsExamplePagerAdapter(getSupportFragmentManager()));
TabLayout tabLayout = findViewById(R.id.tab_layout);
// This method setup all required method for TabLayout with Viewpager
tabLayout.setupWithViewPager(viewPager);
}
private void setUpLandscapeLayout() {
// Note: with the layout definition suggested above you don't
// need any manual processing to set-up your layout for landscape
// but you still may have some extra set-up (initial binding, etc).
tabOneFragment = (TabOneFragment) getSupportFragmentManager().findFragmentById(R.id.fragment_left);
tabTwoFragment = (TabTwoFragment) getSupportFragmentManager().findFragmentById(R.id.fragment_right);
// ...
}
}
You can pass saved parameters to your fragments via "setArguments()" method. Alternatively consider using "onSaveInstanceState()" methods of your fragments (as opposed to activity, which you use now).
Alternative approach: dynamically add fragments in both landscape and portrait cases. It is based on your code. I think some aspects are arguable (I may be wrong), but changing direction would mean rewriting the whole thing. But it should work eventually.
res/layout-land/active_main.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/root"
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
<FrameLayout
android:id="#+id/fragment_left"
android:layout_weight="1"
android:layout_width="0dp"
android:layout_height="match_parent" />
<FrameLayout
android:id="#+id/fragment_right"
android:layout_weight="1"
android:layout_width="0dp"
android:layout_height="match_parent" />
</LinearLayout>
MainActivity.java (based off the code you shared via gist)
public class MainActivity extends AppCompatActivity {
private Fragment tabOneFragment;
private Fragment tabTwoFragment;
private ViewPager viewPager;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if (savedInstanceState != null) {
//Restore the fragment's instance
tabOneFragment = (TabOneFragment) getSupportFragmentManager().getFragment(
savedInstanceState, "tabOneFragment");
tabTwoFragment = (TabTwoFragment) getSupportFragmentManager().getFragment(
savedInstanceState, "tabTwoFragment");
} else {
tabOneFragment = new TabOneFragment();
tabTwoFragment = new TabTwoFragment();
}
if (findViewById(R.id.tab_layout) != null) {
setUpPortraitLayout();
} else {
setUpLandscapeLayout();
}
}
#Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
getSupportFragmentManager().putFragment(outState, "tabOneFragment", tabOneFragment);
getSupportFragmentManager().putFragment(outState, "tabTwoFragment", tabTwoFragment);
}
private void setUpPortraitLayout() {
viewPager = (ViewPager) findViewById(R.id.pager);
// Assign created adapter to viewPager
viewPager.setAdapter(new TabsPagerAdapter(getSupportFragmentManager()));
TabLayout tabLayout = (TabLayout) findViewById(R.id.tab_layout);
// This method setup all required method for TabLayout with Viewpager
tabLayout.setupWithViewPager(viewPager);
}
private void setUpLandscapeLayout() {
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
transaction.replace(R.id.fragment_left, tabOneFragment);
transaction.replace(R.id.fragment_right, tabTwoFragment);
transaction.addToBackStack(null);
transaction.commit();
}
private class TabsPagerAdapter extends FragmentPagerAdapter {
// As we are implementing two tabs
private static final int NUM_ITEMS = 2;
public TabsPagerAdapter(FragmentManager fragmentManager) {
super(fragmentManager);
}
#Override
// For each tab different fragment is returned
public Fragment getItem(int position) {
switch (position) {
case 0:
return tabOneFragment;
case 1:
return tabTwoFragment;
default:
throw new IllegalStateException("Invalid tab index");
}
}
#Override
public int getCount() { return NUM_ITEMS; }
#Override
public CharSequence getPageTitle(int position) { return "Tab " + (position + 1); }
// NOTE: I think you do not really need to override "instantiateItem()", therefore I removed it.
}
}
My ViewPager does not show any fragments even though it load the fragment for my "Review section". I used the same code with my "rating section" and it work, even tried redo the ViewPager and adapter but still no progress. By the way i'm doing this within a fragment.
I put a log in the adapter to show whether the fragment is working and also change my Viewpager's background color to check if it's visible or not. Even though the ViewPager is visible but the fragment still does not show.
UPDATE: I found out that the problem caused by the activity i use to replace with the fragments.
Here the code snippet (in my activity which hold both "Rating Section" and "review Section".
SubSectionFragment_Rating subSectionFragment_rating = new SubSectionFragment_Rating();
manager = getSupportFragmentManager();
manager.beginTransaction().replace(R.id.ratingSection,subSectionFragment_rating, subSectionFragment_rating.getTag()).commit();
SubSectionFragment_ReviewAndInstructions subSectionFragment = new SubSectionFragment_ReviewAndInstructions();
manager = getSupportFragmentManager();
manager.beginTransaction().replace(R.id.subTab,subSectionFragment, subSectionFragment.getTag()).commit();
ViewPager is visible
Should display this fragment in ViewPager
Review.xml
<FrameLayout 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="com.hybridelements.openchef.fragment_activities.fragment_subs.SubSectionFragment_ReviewAndInstructions">
<RelativeLayout
android:id="#+id/main_layout"
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">
<android.support.design.widget.TabLayout
android:id="#+id/tab_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/colorPrimary"
android:elevation="6dp"
android:minHeight="?attr/actionBarSize"
android:theme="#style/ThemeOverlay.AppCompat.Dark.ActionBar"/>
<android.support.v4.view.ViewPager
android:id="#+id/pager"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="#id/tab_layout"
android:background="#android:color/holo_green_dark"/>
</RelativeLayout>
Review.java (part of the code)
viewPager = (ViewPager) rootView.findViewById(R.id.pager);
final SubPagerAdapter_ReviewAndInstructions adapter = new SubPagerAdapter_ReviewAndInstructions(getActivity().getSupportFragmentManager(), tabLayout.getTabCount());
viewPager.setAdapter(adapter);
viewPager.addOnPageChangeListener(new TabLayout.TabLayoutOnPageChangeListener(tabLayout));
SubPagerAdapter_ReviewAndInstructions.java
public SubPagerAdapter_ReviewAndInstructions(FragmentManager fm, int NumOfTabs){
super(fm);
this.mNumOfTabs = NumOfTabs;
}
#Override
public Fragment getItem(int position) {
switch (position){
case 0:
ReviewsFragment subTab1 = new ReviewsFragment();
Log.d("ReviewAndInstruction","ReviewsFragment loaded");
return subTab1;
default:
return null;
}
}
#Override
public int getCount() {
return mNumOfTabs;
}
Problem solved thanks to #Yupi for the suggestion to change from getActivity().getSupportFragmentManager() to getChildFragment(). during the problem occurred, when change to getChildFragment() got an error
java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.Object android.util.SparseArray.get(int)' on a null object reference
To fix this error, i need to change my activity that start the fragment transaction, so here's the solution to the problem for nested fragments.
ViewItem.Java (BEFORE)
FragmentManager manager;
manager = getSupportFragmentManager();
ViewItem.Java (AFTER)
FragmentTransaction manager;
manager = getSupportFragmentManager().beginTransaction();
SubPagerFragment_ReviewAndInstructions.java (BEFORE)
final SubPagerAdapter_ReviewAndInstructions adapter = new SubPagerAdapter_ReviewAndInstructions(getActivity().getSupportFragmentManager(), tabLayout.getTabCount());
SubPagerFragment_ReviewAndInstructions.java (AFTER)
final SubPagerAdapter_ReviewAndInstructions adapter = new SubPagerAdapter_ReviewAndInstructions(getChildFragmentManager(), tabLayout.getTabCount());
Result
Fragment correctly displayed
In my case, the childFragmentManager and addToBackStack still not fixed my issue, this solution might work instead. With combination from #burning-violet solution.
childFragmentManager used to construct the ViewPager
Using FragmentStatePageAdapter
override restoreState()
Without using addToBackStack(null) // this optional, if you don't want to add to backstack
The restoreState() try catch will only silence the error (NPE), it must be fixed accordingly.
I recently started coding and have been following tutorials. I'm trying to learn how to use a tab activity right now and followed a tutorial to do it by swiping pages. Here's what I've come up with
public class MainActivity extends FragmentActivity {
ViewPager pager;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button btn1 = (Button) findViewById(R.id.btn1);
Button btn2 = (Button) findViewById(R.id.btn2);
pager = (ViewPager) findViewById(R.id.viewPager);
pager.setAdapter(new MyPagerAdapter(getSupportFragmentManager()));
}
public void onClickBtn1(View v) {
//when clicked, take to Main2Activity.java
}
public void onClickBtn2(View v) {
//when clicked, take to Main3Activity.java
}
private class MyPagerAdapter extends FragmentPagerAdapter {
public MyPagerAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int pos) {
switch(pos) {
case 0: return Main2Activity.newInstance("FirstFragment, Instance 1");
case 1: return Main3Activity.newInstance("SecondFragment, Instance 1");
case 2: return Main4Activity.newInstance("ThirdFragment, Instance 1");
default: return Main4Activity.newInstance("ThirdFragment, Default");
}
}
#Override
public int getCount() {
return 3;
}
}
}
Can someone please explain to me what's going on in the MyPageAdapter class please?
Also, is it possible that instead of swiping pages that I use a button? For instance, onClickBtn1 will take me to Main2Activity and onClickBtn2 will take me to Main3Activity. I'd like to continue using the tabs instead of creating a new intent.
Thanks in advance!
Your MyPageAdapter will have as many childs as of your tabs.
For example if you select 1st tab ie position will be 0.
Now in below code new instance of fragment is created for pos 0(First Fragment).
public Fragment getItem(int pos) {
switch(pos) {
case 0: return Main2Activity.newInstance("FirstFragment, Instance 1");
case 1: return Main3Activity.newInstance("SecondFragment, Instance 1");
case 2: return Main4Activity.newInstance("ThirdFragment, Instance 1");
default: return Main4Activity.newInstance("ThirdFragment, Default");
}
}
Switching the tabs on button click is not a cool idea as per user experience.You are using view pager which will help swiping the tabs easily.Execute the code & you will get to know more about the functionality of the code.
if you want to use tabs, you could use 4 fragments in an activity and manage them with ViewPager, by this you can go from one to another by clicking on the tabs and swipe left and right
private void initPager() {
ViewPager pager = (ViewPager) findViewById(R.id.pager);
mAdapter = new MyPagerAdapter(getSupportFragmentManager());
mAdapter.addFragment(firstFragment.newInstance(), getString(R.string.first_fragment_Title));
mAdapter.addFragment(secondFragment.newInstance(), getString(R.string.second_fragment_title));
pager.setAdapter(mAdapter);
TabLayout tabs = (TabLayout) findViewById(R.id.tabs);
tabs.setupWithViewPager(pager);
TextView firstFragmentTabTitle = (TextView) getLayoutInflater().inflate(R.layout.tab_indicator, null);
firstFragmentTabTitle.setText(mAdapter.getPageTitle(0).toString());
TextView secondFragmentTabTitle = (TextView) getLayoutInflater().inflate(R.layout.tab_indicator, null);
secondFragmentTabTitle.setText(mAdapter.getPageTitle(1).toString());
tabs.getTabAt(0).setCustomView(firstFragmentTabTitle);
tabs.getTabAt(1).setCustomView(secondFragmentTabTitle);
pager.setCurrentItem(mAdapter.getCount());
}
and the main activity XML add view pager and tab layout like this :
<?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="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:orientation="vertical"
tools:context=".fragments.BankCounterFragment">
<android.support.design.widget.AppBarLayout
android:id="#+id/app_bar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layoutDirection="ltr"
android:theme="#style/AppTheme.AppBarOverlay">
<android.support.v7.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
app:contentInsetEnd="16dp"
app:popupTheme="#style/AppTheme.PopupOverlay">
<TextView
android:id="#+id/toolbar_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="start|center_vertical"
android:gravity="center|start"
android:text="#string/app_name"
android:textAppearance="#style/TextAppearance.AppCompat.Title"/>
</android.support.v7.widget.Toolbar>
<android.support.design.widget.TabLayout
android:id="#+id/tabs"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/colorPrimary"
android:layoutDirection="ltr"
app:tabGravity="fill"
app:tabIndicatorColor="#android:color/white"
app:tabIndicatorHeight="3dp"
app:tabMode="fixed"/>
</android.support.design.widget.AppBarLayout>
<android.support.v4.view.ViewPager
android:id="#+id/pager"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
The Problem:
In my onCreate() on my main activity, I am trying to set the text value of a TextView in my fragment which is displayed by a viewpager. When I try to get my fragment instance, It always returns null.
Solutions I Tried:
Almost every solution related to this problem on SO gives me the same result(NPE).
My Code is below as well as some explanation...
Home.java Activity (My Main Activity):
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Show the home layout
setContentView(R.layout.home);
// Setup the toolbar
Toolbar toolbar = (Toolbar)findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
// Now setup our tab bar
TabLayout tabLayout = (TabLayout)findViewById(R.id.homeTabs);
tabLayout.setTabGravity(TabLayout.GRAVITY_FILL);
// Setup the view pager
ViewPager viewPager = (ViewPager)findViewById(R.id.viewPager);
PagerAdapter pagerAdapter = new PagerAdapter(getSupportFragmentManager());
viewPager.setAdapter(pagerAdapter);
tabLayout.setupWithViewPager(viewPager);
// Start our service controller
Intent startServiceController = new Intent(this, ServiceController.class);
startService(startServiceController);
Fragment viewFragment = pagerAdapter.getRegisteredFragment(viewPager.getCurrentItem());
if(viewFragment == null){
Log.v("Fragment", "NULL");
}
}
After setting up the pageAdapter and viewpager, I try to access the fragment thats being shown. The code for my PagerAdapter is below...
PagerAdapter:
public class PagerAdapter extends SmartFragmentStatePagerAdapter {
public PagerAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int position) {
switch (position) {
case 0:
return new ParkListFragment();
case 1:
return new MapFragment();
default:
return null;
}
}
#Override
public int getCount() {
return 2;
}
#Override
public CharSequence getPageTitle(int position) {
CharSequence title;
switch (position){
case 0:
title = "Spaces Near You";
break;
case 1:
title = "Map";
break;
default:
title = "N/A";
break;
}
return title;
}
}
SmartFragmentStatePagerAdapter:
public abstract class SmartFragmentStatePagerAdapter extends FragmentStatePagerAdapter {
// Sparse array to keep track of registered fragments in memory
private SparseArray<Fragment> registeredFragments = new SparseArray<>();
public SmartFragmentStatePagerAdapter(FragmentManager fragmentManager) {
super(fragmentManager);
}
// Register the fragment when the item is instantiated
#Override
public Object instantiateItem(ViewGroup container, int position) {
Fragment fragment = (Fragment) super.instantiateItem(container, position);
registeredFragments.put(position, fragment);
return fragment;
}
// Unregister when the item is inactive
#Override
public void destroyItem(ViewGroup container, int position, Object object) {
registeredFragments.remove(position);
super.destroyItem(container, position, object);
}
// Returns the fragment for the position (if instantiated)
public Fragment getRegisteredFragment(int position) {
return registeredFragments.get(position);
}
}
I really don't understand what the issue is. I have tried many things. What I don't want to use is this:
String tag="android:switcher:" + viewId + ":" + index;
ParkListFragment.java:
public class ParkListFragment extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.park_list_fragment, container, false);
}
}
ParkList Fragment Layout:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="0.5">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_centerInParent="true">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/confidenceText"
android:textAlignment="center"
android:textSize="24sp"
android:textColor="#android:color/primary_text_light"
android:padding="10dp"/>
</LinearLayout>
</RelativeLayout>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="0.5">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_centerInParent="true">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/activityText"
android:textAlignment="center"
android:textSize="24sp"
android:textColor="#android:color/primary_text_light"
android:padding="10dp"/>
</LinearLayout>
</RelativeLayout>
</LinearLayout>
Stack Trace: Pastebin
So after hours of trial and error, the only thing that worked for me was this SO post:
ViewPager Fragments are not initiated in onCreate