So I am developing a project with view pager that has 2 tabs with 2 different fragments. There's a card view in both of the fragments. When I click on one of the item in the card view, it should go to another fragment to load the web view with URLs that are passed from the recycler view adapter. I tried to pass the URLs from the adapter to the fragment to load the web view but the app keep on crashing in the emulator. I might be using the wrong method for this or there's something I didn't include in the program. I really need help!
main_activty.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"
android:orientation="vertical"
tools:context=".MainActivity" >
<androidx.viewpager.widget.ViewPager
android:id="#+id/view_pager"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<com.google.android.material.tabs.TabLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<com.google.android.material.tabs.TabItem
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="CYBERSECURITY" />
<com.google.android.material.tabs.TabItem
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="AI" />
</com.google.android.material.tabs.TabLayout>
</androidx.viewpager.widget.ViewPager>
</LinearLayout>
fragment_web.xml
<?xml version="1.0" encoding="utf-8"?>
<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"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="#+id/webView_Frame"
tools:context=".FragmentWeb">
<!-- TODO: Update blank fragment layout -->
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<WebView
android:id="#+id/web_view"
android:layout_width="match_parent"
android:layout_margin="10dp"
android:layout_height="match_parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent">
</WebView>
<ProgressBar
android:id="#+id/progress_bar"
style="?android:attr/progressBarStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
/>
</androidx.constraintlayout.widget.ConstraintLayout>
</FrameLayout>
MainActivity.java
import androidx.appcompat.app.AppCompatActivity;
import androidx.viewpager.widget.ViewPager;
import android.os.Bundle;
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ViewPager viewPager = findViewById(R.id.view_pager);
MyFragmentPagerAdapter adapter = new MyFragmentPagerAdapter(getSupportFragmentManager());
viewPager.setAdapter(adapter);
}
}
MyRecyclerViewAdapter.java
final String URLs = news.getURLs();
Log.d("here",URLs);
myViewHolder.cardView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Bundle bundle = new Bundle();
bundle.putString(KEY, URLs);
FragmentWeb fragmentWeb = new FragmentWeb();
fragmentWeb.setArguments(bundle);
fragmentWeb.getActivity().getSupportFragmentManager()
.beginTransaction()
.replace(R.id.webView_Frame, fragmentWeb)
.commit();
}
});
Above are the codes I tried to pass the URLs to the FragmentWeb class. I tried with log.d to check and the URLs variable already contain all the URLs. I've also tried with fragmentWeb.getChildFragmentManager or even fragmentWeb.getFragmentManager but neither of them work and keep giving me different errors.
FragmentWeb.java
public class FragmentWeb extends Fragment{
private static final String KEY = "URLS";
private String URLs;
private ProgressBar progressBar;
private WebView webView;
public FragmentWeb() {
// Required empty public constructor
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getArguments() != null) {
URLs = getArguments().getString(KEY);
}
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_web, container, false);
progressBar = view.findViewById(R.id.progress_bar);
webView = view.findViewById(R.id.web_view);
return view;
}
public void loadWebPage()
{
webView.loadUrl(URLs);
webView.setWebViewClient(new WebViewClient(){
#Override
public void onPageStarted(WebView view, String URLs, Bitmap favicon) {
progressBar.setVisibility(View.VISIBLE);
webView.setVisibility(View.GONE);
}
#Override
public void onPageFinished(WebView view, String URLs) {
progressBar.setVisibility(View.GONE);
webView.setVisibility(View.VISIBLE);
}
});
}
#Override
public void onStart() {
super.onStart();
loadWebPage();
}
}
Above are the codes to load the web page with the URLs passed from the adapter.
E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.assignment4_task1, PID: 6803
java.lang.NullPointerException: Attempt to invoke virtual method 'androidx.fragment.app.FragmentManager androidx.fragment.app.FragmentActivity.getSupportFragmentManager()' on a null object reference at com.example.assignment4_task1.MyRecyclerViewAdapter$1.onClick(MyRecyclerViewAdapter.java:66)
at android.view.View.performClick(View.java:6294)
at android.view.View$PerformClick.run(View.java:24770)
at android.os.Handler.handleCallback(Handler.java:790)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:164)
at android.app.ActivityThread.main(ActivityThread.java:6494)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:438)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:807)
Here:
FragmentWeb fragmentWeb = new FragmentWeb();
fragmentWeb.setArguments(bundle);
fragmentWeb.getActivity().getSupportFragmentManager()
You're calling 'getActivity()' on fragmentWeb, but you've just created fragmentWeb above. That fragment is not loaded in any activity yet, so getActivity() returns null.
Get the current activity from the surrounding context, such as the RecyclerView's context or, if you declare the Adapter as an inner class of your Fragment, by using Fragment's getActivity().
Related
This question already has answers here:
What is a NullPointerException, and how do I fix it?
(12 answers)
findViewByID returns null
(33 answers)
Closed 2 years ago.
I am designing an Onboarding screen with the help of ViewPager. The ViewPager sits inside a fragment underlying my MainActivity class. The error arises when I pass the ViewPager adapter class to the ViewPager inside my fragment! It throws NullPointerException and after breakpoint debugging I find that the inflater inside my PagerAdapter class is null.
I have tried some alternatives to get the inflater working but no luck! I ll post my codes below:
ViewPager Fragment class:
public class ViewPagerFragment extends Fragment {
ViewPager viewpager;
LinearLayout dotsLayout;
SliderAdapter sliderAdapter;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_view_pager, container, false);
viewpager = (ViewPager) view.findViewById(R.id.viewPagerFragment);
dotsLayout = (LinearLayout) view.findViewById(R.id.dotsLayout);
sliderAdapter = new SliderAdapter(view.getContext());
viewpager.setAdapter(sliderAdapter); //The error is thrown here
// Inflate the layout for this fragment
return view;
}
#Override
public void onViewCreated(#NonNull View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
//Toast.makeText(view.getContext(),"Here",Toast.LENGTH_LONG).show();
}}
ViewPager Adapter Class:
public class SliderAdapter extends PagerAdapter {
Context context1;
LayoutInflater inflater;
public int[] slide_images = {
R.drawable.band,
R.drawable.studio,
R.drawable.videoshoot
};
public String[] slide_headings = {
"REHEARSAL PAD", "RECORDING STUDIO", "SESSION VIDEOSHOOT"
};
public String[] slide_desc ={
String.valueOf(R.string.rehearsal_desc),
String.valueOf(R.string.studio_desc),
String.valueOf(R.string.videoshoot_desc)
};
public SliderAdapter(Context context){
context1 = context;
}
#Override
public int getCount() {
return slide_headings.length;
}
#Override
public boolean isViewFromObject(#NonNull View view, #NonNull Object object) {
return view== (ConstraintLayout)object;
}
#NonNull
#Override
public Object instantiateItem(#NonNull ViewGroup container, int position) {
//ViewPager Sliding Images and Desc
inflater = (LayoutInflater)context1.getSystemService(context1.LAYOUT_INFLATER_SERVICE);
//inflater = LayoutInflater.from(context1);
View view = inflater.inflate(R.layout.slider_layout,container,false);
ImageView slideImageView = (ImageView) view.findViewById(R.id.SliderImageView);
TextView slideHeading = (TextView) view.findViewById(R.id.SliderTextView1);
TextView slideDesc = (TextView) view.findViewById(R.id.SliderTextView2);
slideImageView.setImageResource(slide_images[position]);
slideHeading.setText(slide_headings[position]);
slideDesc.setText(slide_desc[position]);
container.addView(view);
return view;
}
#Override
public void destroyItem(#NonNull ViewGroup container, int position, #NonNull Object object) {
container.removeView((ConstraintLayout)object);
}}
And the Exception Logs are given below:
E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.soundflixstudios, PID: 13363
java.lang.NullPointerException: Attempt to invoke virtual method 'void androidx.viewpager.widget.ViewPager.setAdapter(androidx.viewpager.widget.PagerAdapter)' on a null object reference
at com.example.soundflixstudios.onboarding.ViewPagerFragment.onCreateView(ViewPagerFragment.java:43)
at androidx.fragment.app.Fragment.performCreateView(Fragment.java:2698)
at androidx.fragment.app.FragmentStateManager.createView(FragmentStateManager.java:320)
at androidx.fragment.app.FragmentManager.moveToState(FragmentManager.java:1187)
at androidx.fragment.app.FragmentManager.addAddedFragments(FragmentManager.java:2224)
at androidx.fragment.app.FragmentManager.executeOpsTogether(FragmentManager.java:1997)
at androidx.fragment.app.FragmentManager.removeRedundantOperationsAndExecute(FragmentManager.java:1953)
at androidx.fragment.app.FragmentManager.execPendingActions(FragmentManager.java:1849)
at androidx.fragment.app.FragmentManager$4.run(FragmentManager.java:413)
at android.os.Handler.handleCallback(Handler.java:873)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:224)
at android.app.ActivityThread.main(ActivityThread.java:7099)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:536)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:876)
Any help is appreciated, and yes I have gone through multiple post in stackoverflow but didnt find any solutionhence reaching out with a new question!
Thanks in advance!
Edit: I have added the xml for "view_pager_fragment" layout
enter code here<?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:background="#color/white"
android:orientation="vertical"
tools:context=".onboarding.ViewPagerFragment">
<androidx.viewpager2.widget.ViewPager2
android:id="#+id/sliderViewPager"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center"
android:layout_weight="1">
</androidx.viewpager2.widget.ViewPager2>
<LinearLayout
android:id="#+id/dotsLayout"
android:layout_width="wrap_content"
android:layout_height="66dp"
android:layout_gravity="center"
android:layout_weight="1"
android:orientation="horizontal">
</LinearLayout>
Root cause
In view_pager_fragment.xml file, you declare a ViewPager2 with id sliderViewPager but in ViewPagerFragment class, you use a ViewPager variable and assign a view with id viewPagerFragment to it.
Solution
Step 1. Change fragment_view_pager.xml to:
<?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:background="#color/white"
android:orientation="vertical">
<androidx.viewpager.widget.ViewPager
android:id="#+id/sliderViewPager"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center"
android:layout_weight="1">
</androidx.viewpager.widget.ViewPager>
<LinearLayout
android:id="#+id/dotsLayout"
android:layout_width="wrap_content"
android:layout_height="66dp"
android:layout_gravity="center"
android:layout_weight="1"
android:orientation="horizontal">
</LinearLayout>
</LinearLayout>
Step 2. In ViewPagerFragment class, change your code from
viewpager = (ViewPager) view.findViewById(R.id.viewPagerFragment);
to
viewpager = (ViewPager) view.findViewById(R.id.sliderViewPager);
Can you add your xml file ( viewPagerFragment). In normal case, nullPointerException will show up when you missing references to your xml, or missing create xml tag( different screen- landscape/portrait)
I'm trying to replace one fragment with another following a button click (onClick) event. I'm new to fragments so if I'm going about this the wrong way please let me know.
At run time a frame layout (container) is loaded. A fragment is then added to it dynamically. This works fine. If I add in the setOnClickListener I get a NullPointerException. Here's the Java:
public class WelcomeActivity extends ActionBarActivity {
FrameLayout container;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_welcome);
//setContentView(R.layout.welcome_fragment);
container = (FrameLayout)findViewById(R.id.mainContainer);
// Check that the activity is using the layout version with
// the fragment_container FrameLayout
if (findViewById(R.id.mainContainer) != null) {
// However, if we're being restored from a previous state,
// then we don't need to do anything and should return or else
// we could end up with overlapping fragments.
if (savedInstanceState != null) {
return;
}
addWelcomeFragment();
}
//NPE at the below line
Button submitUser = (Button) findViewById(R.id.submitUser);
submitUser.setOnClickListener(new OnClickListener(){
#Override
public void onClick(View view){
addExpedFragment();
}
});
}
Through researching fragments I'm using static class within the WelcomeActivity class to load the fragments. They are here:
public static class WelcomeFragment extends Fragment {
public static Fragment newInstance(){
Fragment wFrag = new WelcomeFragment();
return wFrag;
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState){
View v = inflater.inflate(R.layout.welcome_fragment, null);
return v;
}
}
//-----------------------------------------------------------------------------------------------------//
public static class ExpedFragment extends Fragment {
public static Fragment secondInstance(){
Fragment eFrag = new ExpedFragment();
return eFrag;
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState){
View v = inflater.inflate(R.layout.exped_fragment, null);
return v;
}
}
And the methods to invoke these are also with WelcomeActivity here:
private void addWelcomeFragment(){
Fragment welcome = WelcomeFragment.newInstance();
FragmentTransaction fTrans = getSupportFragmentManager().beginTransaction();
fTrans.add(R.id.mainContainer, welcome);
fTrans.addToBackStack(null);
fTrans.commit();
}
private void addExpedFragment(){
Fragment exped = ExpedFragment.secondInstance();
getSupportFragmentManager().beginTransaction().replace(R.id.mainContainer, exped).commit();
}
I have a feeling that the problem is to do with trying to find the button view id "submitUser" from the first fragment. My xmls look like this.
The first empty FrameLayout:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
>
<FrameLayout
android:id="#+id/mainContainer"
android:layout_width="wrap_content"
android:layout_height="match_parent" >
</FrameLayout>
</RelativeLayout>
The first fragment loaded in at runtime:
<?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:id="#+id/welcome_fragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="10dp"
android:paddingLeft="10dp"
android:paddingRight="10dp"
tools:context=".WelcomeActivity" >
<TextView
android:id="#+id/welcome"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="#string/welcome1"
android:textAppearance="?android:attr/textAppearanceLarge" />
<EditText
android:id="#+id/userName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignLeft="#+id/welcome"
android:layout_alignRight="#+id/welcome"
android:layout_below="#+id/welcome"
android:layout_marginTop="32dp"
android:ems="10"
android:hint="#string/userHint"
android:inputType="textPersonName" >
<requestFocus />
</EditText>
<Button
android:id="#+id/submitUser"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignLeft="#+id/userName"
android:layout_alignRight="#+id/userName"
android:layout_below="#+id/userName"
android:layout_marginTop="16dp"
android:text="#string/Done" />
<FrameLayout
android:id="#+id/mainContainer"
android:layout_width="wrap_content"
android:layout_height="match_parent" >
</FrameLayout>
</RelativeLayout>
The second fragment to replace the first with the onClick event:
<?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:id="#+id/exped_fragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="10dp"
android:paddingLeft="10dp"
android:paddingRight="10dp"
tools:context=".WelcomeActivity" >
<TextView
android:id="#+id/expedText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="#string/exped"
android:textAppearance="?android:attr/textAppearanceLarge">
</TextView>
<FrameLayout
android:id="#+id/mainContainer"
android:layout_width="wrap_content"
android:layout_height="match_parent" >
</FrameLayout>
</RelativeLayout>
IF I forget loading the first fragment at runtime and setContentView(first fragment) there is no NullPointerException but the two fragments overlay each other when the button is pressed rather than replacing.
So my question is, how do I reference the active fragment to properly set the OnClickListener and avoid the NullPointerException?
Button submitUser = (Button) findViewById(R.id.submitUser);
gives the NPE
Problem:
Button submitUser = (Button) findViewById(R.id.submitUser);
The submitUser is located in your WelcomeFragment's layout not in your Activity's layout that is why it is null.
solution:
Instead of initializing it in your activity class you need to initialize it within your Welcome fragment view.
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState){
View v = inflater.inflate(R.layout.welcome_fragment, null);
Button submitUser = (Button) v.findViewById(R.id.submitUser);
submitUser.setOnClickListener(new OnClickListener(){
#Override
public void onClick(View view){
addExpedFragment();
}
});
return v;
}
EDIT:
private void addExpedFragment(){
Fragment exped = ExpedFragment.secondInstance();
getActivity().getSupportFragmentManager().beginTransaction().replace(R.id.mainContainer, exped).commit();
}
I have an activity with two ViewPagers both working with a FragmentStatePagerAdapter. But when the ViewPagers have no id, or both have the same id, they will not work correctly.
Activity layout (activity.xml):
<LinearLayout 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"
android:orientation="vertical"
tools:context="com.example.app.MainActivity">
<FrameLayout
android:id="#+id/frame1"
android:layout_width="match_parent"
android:layout_weight="1"
android:layout_height="0dp">
<include layout="#layout/merge_pager" />
</FrameLayout>
<FrameLayout
android:id="#+id/frame2"
android:layout_width="match_parent"
android:layout_weight="1"
android:layout_height="0dp">
<include layout="#layout/merge_pager" />
</FrameLayout>
</LinearLayout>
Merge layout (merge_pager.xml):
<merge xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v4.view.ViewPager
android:id="#+id/view_pager"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</merge>
Activity:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity);
FrameLayout frame1 = (FrameLayout) findViewById(R.id.frame1);
FrameLayout frame2 = (FrameLayout) findViewById(R.id.frame2);
ViewPager vp1 = (ViewPager) frame1.getChildAt(0);
ViewPager vp2 = (ViewPager) frame2.getChildAt(0);
if (vp1 == null | vp2 == null) {
throw new NullPointerException();
}
vp1.setAdapter(new ColorAdapter(getSupportFragmentManager()));
vp2.setAdapter(new ColorAdapter(getSupportFragmentManager()));
}
private class ColorAdapter extends FragmentStatePagerAdapter {
public ColorAdapter(FragmentManager fragmentManager) {
super(fragmentManager);
}
#Override
public Fragment getItem(int i) {
return new ColorFragment();
}
#Override
public int getCount() {
return Integer.MAX_VALUE;
}
}
public static class ColorFragment extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
TextView tv = new TextView(container.getContext());
Drawable d = new ColorDrawable(randomColor());
tv.setBackgroundDrawable(d);
return tv;
}
public static int randomColor() {
return Color.rgb(random255(), random255(), random255());
}
public static int random255() {
return
(int) (Math.random() * (double) 255);
}
Using this code, the second ViewPager won't work. I suspected it might be due to clashing ids (R.id.view_pager), so I removed the id from the merge file. However, this results in a fatal exception:
FATAL EXCEPTION: main
android.content.res.Resources$NotFoundException: Unable to find resource ID #0xffffffff
What is up with this?
It says in the docs:
When using FragmentPagerAdapter the host ViewPager must have a valid ID set.
So at least it's documented that the adapter won't work without an id for its pager. I suppose you can then take 'valid' to mean 'unique in the activity view hierarchy'.
I have a ViewPager which holds multiple base fragments, each base fragment have four more nested fragments and each nested fragment is a combination of 5 imageViews and textView.
(This is what I intended to do)
I have created a sample application but I am not able to implement that properly. I cannot see any view in the nested fragment or the base fragment.
Here's the code for the sample application
main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<fragment android:name="com.example.nestedfragments.BaseFragment"
android:id="#+id/left_fragment"
android:layout_weight="1"
android:layout_width="0dp"
android:layout_height="match_parent"/>
</LinearLayout>
MainActivity.java
package com.example.nestedfragments;
import android.os.Bundle;
import android.support.v4.app.FragmentActivity;
public class MainActivity extends FragmentActivity {
/**
* Called when the activity is first created.
*/
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
}
base_fragment.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center">
<Button
android:id="#+id/button1"
android:text="Launch Nested Fragment"
android:gravity="center"
android:layout_alignParentBottom="true"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:paddingBottom="10dp"/>
</RelativeLayout>
BaseFragment.java
public class BaseFragment extends Fragment {
Button doNestingButton;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// set the view
View root = inflater.inflate(R.layout.base_fragment, container, false);
doNestingButton = (Button) root.findViewById(R.id.button1);
doNestingButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Fragment videoFragment = new NestedFragment();
// we get the 'childFragmentManager' for our transaction
FragmentTransaction transaction = getChildFragmentManager().beginTransaction();
// make the back button return to the main screen
// and supply the tag 'left' to the backstack
transaction.addToBackStack("left");
// add our new nested fragment
transaction.add(getId(), videoFragment, "left");
// commit the transaction
transaction.commit();
}
});
return root;
}
}
nested_fragment.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:layout_width="154dp"
android:layout_height="154dp"
android:id="#+id/imageView" android:layout_gravity="left|center_vertical"
android:src="#drawable/ic_splash"/>
</LinearLayout>
NestedFragment.java
public class NestedFragment extends Fragment {
public NestedFragment() {
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View root = inflater.inflate(R.layout.nested_fragment, container, false);
ImageView doNestingButton = (ImageView) root.findViewById(R.id.imageView);
return root;
}
Once again this is a sample application, please guide me.
From your above code, you have not used the fragment container layout such as FrameLayout in base_fragment.xml .So add the frame layout for nested fragment inbase_fragment.xml
I would like to use one Activity which holds several fragments and navigate among the fragments. For example, in the activity, there is a list view which is a fragment, when user select one item from the list, the view will navigate to another fragment, How could this be implemented?
I know there is a nice tutorial on the developer site, but it handles the tablet screen in which two pane layout with one list fragment and one detailed fragment showing in one screen. I only want to navigate among fragments without show two fragments in one screen.
Are there tutorials can teach me how to do it?
In the nutshell the answer to your question is to notify your host activity and then have your host activity replace your current fragment container using FragmentManager.
One of the approach is to make an interface in your first fragment, have your host activity register/listen (implement) to this interface and then have your FragmentManager to replace the container content with the second fragment on listener callback.
I'm not sure about tutorial but here is my snippet:
First Fragment
public class First extends Fragment{
private static onMySignalListener listener;
//call this function from whatever you like i.e button onClickListener
public void switchWindow() {
if(listener != null){
listener.onMySignal();
}
}
public interface onMySignalListener {
//customize this to your liking
//plain without argument
void onMySignal();
//with argument
void onMySignalWithNum(int mNum);
}
public static void setOnMySignalListener(onMySignalListener listener) {
First.listener = listener;
}}
Host Activity
public class HostActivity extends FragmentActivity implements onMySignalListener{
private final String ADD_TAG_IF_NECESSARY = "mTag";
#Override
public void onCreate(Bundle ssi) {
setContentLayout(R.layout.main);
FirstFragment.setOnMySignalListener(this);
}
#Override
public void onMySignal() {
//if you're using compat library
FragmentManager manager = getSupportFragmentManager();
FragmentTransaction transaction = manager.beginTransaction();
//initialize your second fragment
sfragment = SecondFragment.newInstance(null);
//replace your current container being most of the time as FrameLayout
transaction.replace(R.id.container, fragment, ADD_TAG_IF_NECESSARY);
transaction.commit();
}
#Override
public void onMySignalWithNum(int mNum) {
//you can do the same like the above probably with your own customization
}}
This is only an example on how you'd implement interface, kindly tidy it up by yourself. And please be noted though that this is not effective if you have a lot of fragment wanting to notify your host activity about something. doing so will lead you to implement various listener to your host activity.
I think this will be useful for you. It is example of two fragments in one screen works independently.
MainActivity :
public class MainActivity extends Activity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main_activity);
Fragment newFragment = new Test();
FragmentTransaction transaction = getFragmentManager().beginTransaction();
transaction.add(R.id.UprLayout, newFragment);
// transaction.addToBackStack(null);
transaction.commit();
Fragment newFragment2 = new TestRight();
FragmentTransaction transaction2 = getFragmentManager().beginTransaction();
transaction2.add(R.id.dwnLayout, newFragment2);
// transaction.addToBackStack(null);
transaction2.commit();
}
}
main_activity.xml :
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/LinearLayout2"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center|center_horizontal"
android:orientation="vertical" >
<LinearLayout
android:id="#+id/UprLayout"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:orientation="vertical" />
<LinearLayout
android:id="#+id/dwnLayout"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:orientation="vertical" />
</LinearLayout>
Fragment Test :
public class Test extends Fragment {
TextView tv;
#Override
public void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.test, container, false);
return view;
}
}
Fragment TestRight :
public class TestRight extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.test_right, container, false);
return view;
}
#Override
public void onStart() {
super.onStart();
Button button = (Button)getActivity().findViewById(R.id.button1);
button.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
Fragment newFragment = new Right2nd();
FragmentTransaction transaction = getFragmentManager()
.beginTransaction();
transaction.replace(R.id.dwnLayout, newFragment);
transaction.addToBackStack("aa");
transaction.commit();
//transaction.add(R.id.frag, newFragment).commit();
}
});
}
}
test.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:gravity="center"
android:orientation="vertical" >
<TextView
android:id="#+id/textView1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_horizontal"
android:text="test"
android:textAppearance="?android:attr/textAppearanceLarge"
android:textSize="50sp" />
</LinearLayout>
test_right.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:gravity="center"
android:orientation="vertical" >
<Button
android:id="#+id/button1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Click" />
<TextView
android:id="#+id/textView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Test right"
android:textAppearance="?android:attr/textAppearanceLarge"
android:textSize="45sp" />
</LinearLayout>
Fragment Right2nd :
public class Right2nd extends Fragment{
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View vw = inflater.inflate(R.layout.right_2nd, container, false);
return vw;
}
}
right_2nd.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:gravity="center"
android:orientation="vertical" >
<TextView
android:id="#+id/textView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Right 2nd"
android:textAppearance="?android:attr/textAppearanceLarge"
android:textSize="50sp" />
</LinearLayout>
I know this is quite old question but this is currently implemented in Navigation Component https://developer.android.com/guide/navigation/
Here is a very nice tutorial about it. MULTIPLE FRAGMENTS STACK IN EACH VIEWPAGER TAB
I think ChildFragment
would do the job for you. Ignore the Tab ViewPager. It's performing the same thing in multiple tabs. Hope this helps a bit.