I have a very simple app with just one activity and a FrameLayout in it. I have two layout A and B and I am loading them as fragments one at a time thus replacing the current fragment. The problem is that when I press the back button the app crashes. The fragment change is triggered by a button in the first fragment
MainActivity.java
import android.os.Bundle;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentTransaction;
import android.view.View;
public class MainActivity extends FragmentActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Check that the activity is using the layout version with
// the fragment_container FrameLayout
if (findViewById(R.id.fragment_container) != 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;
}
else {
// Create a new Fragment to be placed in the activity layout
SelectLogInFragment firstFragment = new SelectLogInFragment();
// In case this activity was started with special instructions from an
// Intent, pass the Intent's extras to the fragment as arguments
firstFragment.setArguments(getIntent().getExtras());
// Add the fragment to the 'fragment_container' FrameLayout
getSupportFragmentManager().beginTransaction().add(R.id.fragment_container, firstFragment).commit();
}
}
}
public void login_email(View view)
{
// Create fragment and give it an argument specifying the article it should show
Log_In_form newFragment = new Log_In_form();
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
// Replace whatever is in the fragment_container view with this fragment,
// and add the transaction to the back stack so the user can navigate back
transaction.replace(R.id.fragment_container, newFragment);
transaction.addToBackStack(null);
// Commit the transaction
transaction.commit();
}
}
SelectLogInFragment.java
import android.support.v4.app.Fragment;
import android.os.Bundle;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentTransaction;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
public class SelectLogInFragment extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.select_log_in, container, false);
}
}
LogInForm is very similar to SelectLogInFragment
select_log_in.xml
<?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">
<fragment android:name="com.badass.david.mynewapplication.Top_Log"
android:id="#+id/top_log"
android:layout_weight="2"
android:layout_width="match_parent"
android:layout_height="0dp" />
<fragment android:name="com.badass.david.mynewapplication.Bottom_Log"
android:id="#+id/bottom_log"
android:layout_weight="2"
android:layout_width="match_parent"
android:layout_height="0dp" />
</LinearLayout>
Top_Log.java
public class Top_Log extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.top_log, container, false);
}
}
Bottom_Log is very similar
top_log.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="match_parent"
android:gravity="center"
android:background="#color/white" >
<TextView
android:id="#+id/logo_message"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Put Logo here" />
</LinearLayout>
Errors
06-20 12:00:06.773 20327-20327/com.badass.david.mynewapplication
E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.badass.david.mynewapplication, PID: 20327
android.view.InflateException: Binary XML file line #6: Error
inflating class fragment
at
android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:770)
at android.view.LayoutInflater.rInflate(LayoutInflater.java:813)
at android.view.LayoutInflater.inflate(LayoutInflater.java:511)
at android.view.LayoutInflater.inflate(LayoutInflater.java:415)
at
com.badass.david.mynewapplication.SelectLogInFragment.onCreateView(SelectLogInFragment.java:16)
at
android.support.v4.app.Fragment.performCreateView(Fragment.java:1974)
at
android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1067)
at
android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1252)
at
android.support.v4.app.BackStackRecord.popFromBackStack(BackStackRecord.java:979)
at
android.support.v4.app.FragmentManagerImpl.popBackStackState(FragmentManager.java:1670)
at
android.support.v4.app.FragmentManagerImpl.popBackStackImmediate(FragmentManager.java:586)
at
android.support.v4.app.FragmentActivity.onBackPressed(FragmentActivity.java:188)
at android.app.Activity.onKeyUp(Activity.java:2576)
at android.view.KeyEvent.dispatch(KeyEvent.java:3171)
at android.app.Activity.dispatchKeyEvent(Activity.java:2831)
at
com.android.internal.policy.impl.PhoneWindow$DecorView.dispatchKeyEvent(PhoneWindow.java:2438)
at
android.view.ViewRootImpl$ViewPostImeInputStage.processKeyEvent(ViewRootImpl.java:4582)
at
android.view.ViewRootImpl$ViewPostImeInputStage.onProcess(ViewRootImpl.java:4537)
at
android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:4068)
at
android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:4121)
at
android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:4087)
at
android.view.ViewRootImpl$AsyncInputStage.forward(ViewRootImpl.java:4201)
at android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:4095)
at
android.view.ViewRootImpl$AsyncInputStage.apply(ViewRootImpl.java:4258)
at
android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:4068)
at
android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:4121)
at
android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:4087)
at android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:4095)
at
android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:4068)
at
android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:4121)
at
android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:4087)
at
android.view.ViewRootImpl$AsyncInputStage.forward(ViewRootImpl.java:4234)
at
android.view.ViewRootImpl$ImeInputStage.onFinishedInputEvent(ViewRootImpl.java:4421)
at
android.view.inputmethod.InputMethodManager$PendingEvent.run(InputMethodManager.java:2480)
at
android.view.inputmethod.InputMethodManager.invokeFinishedInputEventCallback(InputMethodManager.java:2074)
at
android.view.inputmethod.InputMethodManager.finishedInputEvent(InputMethodManager.java:2065)
at
android.view.inputmethod.InputMethodManager$ImeInputEventSender.onInputEventFinished(InputMethodManager.java:2457)
at
android.view.InputEventSender.dispatchInputEventFinished(InputEventSender.java:141)
at android.os.MessageQueue.nativePollOnce(Native Method)
at android.os.MessageQueue.next(MessageQueue.java:143)
at android.os.Looper.loop(Looper.java:130)
at android.app.ActivityThread.main(ActivityThread.java:5951)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at
com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1388)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1183)
Caused by: java.lang.IllegalArgumentException: Binary XML file line
6: Duplicate id 0x7f0c0089, tag null, or parent id 0xffffffff with another fragment for com.badass.david.mynewapplication.Top_Log
at
android.support.v4.app.FragmentManagerImpl.onCreateView(FragmentManager.java:2293)
at android.support.v4.view.LayoutInflaterCompatHC$Factory
To me it seems like it is trying to create a fragment that already exists so there is an ID conflict.. Is it the problem? How can I solve it?
you should replace file select_log_in.xml by:
<?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">
<FrameLayout
android:id="#+id/top_log"
android:layout_weight="2"
android:layout_width="match_parent"
android:layout_height="0dp" />
<FrameLayout
android:id="#+id/bottom_log"
android:layout_weight="2"
android:layout_width="match_parent"
android:layout_height="0dp" />
</LinearLayout>
and in the onCreateView method of SelectLogInFragment:
public View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState) {
return inflater.inflate(R.layout.select_log_in,null);
}
and in the onViewCreated method of SelectLogInFragment:
public void onViewCreated(View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
ViewGroup topLogView = findViewById(R.id.top_log);
ViewGroup bottomLogView = findViewById(R.id.bottom_log);
if(topLogView != null){
topLogView.removeAllViews();
}
if(bottomLogView != null){
bottomLogView.removeAllViews();
}
getChildFragmentManager().beginTransaction().add(R.id.top_log,TopLogFragment,"top_log").commit();
getChildFragmentManager().beginTransaction().add(R.id.bottom_log,BottomLogFragment,"bottom_log").commit();
}
Related
Hey guys I am a beginner in Android Develpoment. I am currently learning Navigation Components, but stuck in this app. I am setting listener to the button present in the activity_main.xml inside the FirstFragment.java and SecondFragment.java but my app crashes. I don't know what I am doing wrong.
Main Activity.java
package com.ahstore.inventory;
import android.os.Bundle;
import com.google.android.material.snackbar.Snackbar;
import androidx.appcompat.app.AppCompatActivity;
import android.view.View;
import androidx.navigation.NavController;
import androidx.navigation.Navigation;
import androidx.navigation.fragment.NavHostFragment;
import androidx.navigation.ui.AppBarConfiguration;
import androidx.navigation.ui.NavigationUI;
import com.ahstore.inventory.databinding.ActivityMainBinding;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.Button;
public class MainActivity extends AppCompatActivity {
private AppBarConfiguration appBarConfiguration;
private ActivityMainBinding binding;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
binding = ActivityMainBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot());
setSupportActionBar(binding.toolbar);
NavController navController = Navigation.findNavController(this, R.id.nav_host_fragment_content_main);
appBarConfiguration = new AppBarConfiguration.Builder(navController.getGraph()).build();
NavigationUI.setupActionBarWithNavController(this, navController, appBarConfiguration);
binding.fab.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
.setAction("Action", null).show();
}
});
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
#Override
public boolean onSupportNavigateUp() {
NavController navController = Navigation.findNavController(this, R.id.nav_host_fragment_content_main);
return NavigationUI.navigateUp(navController, appBarConfiguration)
|| super.onSupportNavigateUp();
}
}
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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:id="#+id/coordinatorLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<com.google.android.material.appbar.AppBarLayout
android:id="#+id/appBarLayout"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:theme="#style/Theme.Inventory.AppBarOverlay"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<androidx.appcompat.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/colorPrimary"
app:popupTheme="#style/Theme.Inventory.PopupOverlay" />
</com.google.android.material.appbar.AppBarLayout>
<HorizontalScrollView
android:id="#+id/horizontalScrollView"
android:layout_width="409dp"
android:layout_height="50dp"
android:layout_marginStart="10dp"
android:layout_marginEnd="10dp"
android:scrollIndicators="none"
android:scrollbarAlwaysDrawHorizontalTrack="false"
android:scrollbarAlwaysDrawVerticalTrack="false"
android:scrollbars="none"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/appBarLayout">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:orientation="horizontal">
<Button
android:id="#+id/button1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginRight="5dp"
android:layout_weight="1"
android:text="Button" />
<Button
android:id="#+id/button2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginRight="5dp"
android:layout_weight="1"
android:text="Button" />
</LinearLayout>
</HorizontalScrollView>
<fragment
android:id="#+id/nav_host_fragment_content_main"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="0dp"
android:layout_height="0dp"
app:defaultNavHost="true"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/horizontalScrollView"
app:navGraph="#navigation/nav_graph" />
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="#+id/fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="16dp"
android:layout_marginBottom="16dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:srcCompat="#android:drawable/ic_input_add"
tools:ignore="SpeakableTextPresentCheck,SpeakableTextPresentCheck" />
</androidx.constraintlayout.widget.ConstraintLayout>
FirstFragment.java
package com.ahstore.inventory;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import androidx.navigation.fragment.NavHostFragment;
import com.ahstore.inventory.databinding.FragmentFirstBinding;
public class FirstFragment extends Fragment {
private FragmentFirstBinding binding;
#Override
public View onCreateView(
LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState
) {
View view=inflater.inflate(R.layout.fragment_first,container,false);
return view;
}
public void onViewCreated(#NonNull View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
Button button1=view.findViewById(R.id.button1);
button1.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
NavHostFragment.findNavController(FirstFragment.this)
.navigate(R.id.action_FirstFragment_to_SecondFragment);
}
});
}
#Override
public void onDestroyView() {
super.onDestroyView();
binding = null;
}
}
fragment_first.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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=".FirstFragment">
<ScrollView
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:id="#+id/textView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="First" />
</LinearLayout>
</ScrollView>
</androidx.constraintlayout.widget.ConstraintLayout>
SecondFragment.java
package com.ahstore.inventory;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import androidx.navigation.fragment.NavHostFragment;
import com.ahstore.inventory.databinding.FragmentSecondBinding;
public class SecondFragment extends Fragment {
private FragmentSecondBinding binding;
#Override
public View onCreateView(
LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState
) {
View view=inflater.inflate(R.layout.fragment_second,container,false);
return view;
}
public void onViewCreated(#NonNull View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
Button button=view.findViewById(R.id.button2);
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
NavHostFragment.findNavController(SecondFragment.this)
.navigate(R.id.action_SecondFragment_to_FirstFragment);
}
});
}
#Override
public void onDestroyView() {
super.onDestroyView();
binding = null;
}
}
fragment_second.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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:id="#+id/cl"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".SecondFragment">
<TextView
android:id="#+id/textview_second"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="am second"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
Error
2022-03-04 16:54:11.473 2392-2392/com.ahstore.inventory E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.ahstore.inventory, PID: 2392
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.ahstore.inventory/com.ahstore.inventory.MainActivity}: android.view.InflateException: Binary XML file line #79 in com.ahstore.inventory:layout/activity_main: Binary XML file line #79 in com.ahstore.inventory:layout/activity_main: Error inflating class fragment
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3800)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3976)
at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:85)
at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2315)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:246)
at android.app.ActivityThread.main(ActivityThread.java:8550)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:602)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1130)
Caused by: android.view.InflateException: Binary XML file line #79 in com.ahstore.inventory:layout/activity_main: Binary XML file line #79 in com.ahstore.inventory:layout/activity_main: Error inflating class fragment
Caused by: android.view.InflateException: Binary XML file line #79 in com.ahstore.inventory:layout/activity_main: Error inflating class fragment
Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'void android.widget.Button.setOnClickListener(android.view.View$OnClickListener)' on a null object reference
at com.ahstore.inventory.FirstFragment.onViewCreated(FirstFragment.java:35)
at androidx.fragment.app.Fragment.performViewCreated(Fragment.java:2987)
at androidx.fragment.app.FragmentStateManager.createView(FragmentStateManager.java:546)
at androidx.fragment.app.FragmentStateManager.moveToExpectedState(FragmentStateManager.java:282)
at androidx.fragment.app.FragmentStore.moveToExpectedState(FragmentStore.java:112)
at androidx.fragment.app.FragmentManager.moveToState(FragmentManager.java:1647)
at androidx.fragment.app.FragmentManager.dispatchStateChange(FragmentManager.java:3128)
at androidx.fragment.app.FragmentManager.dispatchViewCreated(FragmentManager.java:3065)
at androidx.fragment.app.Fragment.performViewCreated(Fragment.java:2988)
at androidx.fragment.app.FragmentStateManager.ensureInflatedView(FragmentStateManager.java:392)
at androidx.fragment.app.FragmentStateManager.moveToExpectedState(FragmentStateManager.java:281)
at androidx.fragment.app.FragmentLayoutInflaterFactory.onCreateView(FragmentLayoutInflaterFactory.java:140)
at androidx.fragment.app.FragmentController.onCreateView(FragmentController.java:135)
at androidx.fragment.app.FragmentActivity.dispatchFragmentsOnCreateView(FragmentActivity.java:319)
at androidx.fragment.app.FragmentActivity.onCreateView(FragmentActivity.java:298)
at android.view.LayoutInflater.tryCreateView(LayoutInflater.java:1067)
at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:995)
at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:959)
at android.view.LayoutInflater.rInflate(LayoutInflater.java:1121)
at android.view.LayoutInflater.rInflateChildren(LayoutInflater.java:1082)
at android.view.LayoutInflater.inflate(LayoutInflater.java:680)
at android.view.LayoutInflater.inflate(LayoutInflater.java:532)
at com.ahstore.inventory.databinding.ActivityMainBinding.inflate(ActivityMainBinding.java:75)
at com.ahstore.inventory.databinding.ActivityMainBinding.inflate(ActivityMainBinding.java:69)
at com.ahstore.inventory.MainActivity.onCreate(MainActivity.java:32)
at android.app.Activity.performCreate(Activity.java:8198)
2022-03-04 16:54:11.474 2392-2392/com.ahstore.inventory E/AndroidRuntime: at android.app.Activity.performCreate(Activity.java:8182)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1309)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3773)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3976)
at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:85)
at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2315)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:246)
at android.app.ActivityThread.main(ActivityThread.java:8550)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:602)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1130)
Here are a few points that will help you understand your issue better
Your activity and fragments have their own respective layout files (xmls)
View are bound within their layout files. Simply put, if an element with id, say A, is present in activity_main.xml, then it can only be accessed when the layout being inflated is activity_main.xml. If the contentView of your Activity is activity_main.xml, it will be able to access all Views inside the layout file.
In fragments, the layout is inflated in the onCreateView method, which returns the resulting View for the Fragment. The findViewById(id) method is called against that View object. The method will look for the View with the given id inside that View only. If it is able to find the View it will return it, else it will return null. Same goes for finding a View inside an Activity (you do not need to specify the View for an Activity as it will automatically reference the layout that is specified in setContentView).
Now that we have the above points cleared, we can see the issue that you are facing. Firstly, the buttons with ids button1 and button2 are in your activity_main.xml layout file. However you are trying to access these from your Fragment1 and Fragment2 classes. But your Fragment1 and Fragment2 classes have their own layout files which do not have the two buttons. So, when you try to retrieve the buttons (using findViewById), it returns null because the buttons are not present in the layout. You then try to set a click listener. Since, the button object is null, calling any method on it will result in a Null Pointer Exception being throw.
We now understand what you are doing wrong. Now, how do we fix this. First you need to understand what it is you want to achieve. In this case I would suggest that you move both buttons to the respective Fragment layouts i.e. the View with id button1 will go to Fragment1 and the View with id button2 will go to Fragment2. This should help resolve the NPE that you are facing.
Still there are some cases where a Fragment might want to access a View that is present in its parent Activity. One of the ways to do this would be to
Create a public method in your Activity class which returns a View with the given id.
public View getViewById(int id) {
return findViewById(id);
}
Use this method in your Fragment by doing so
((MainActivity) getActivity()).getViewById(R.id.button1)
Other approaches involve using Interfaces which I am sure you will learn about as you continue learning more.
Just to wrap things up, you have two ways to go about fixing your issue. Either move the buttons to the fragment layout files or create a public method to retrieve those views.
My Android app crashes when resuming after being killed by OS due to low memory.
So I have built the smallest possible app to reproduce the bug.
My app is composed of a MainActivity, which contains 1 page in a viewPager2, which contains a fragment.
This fragment is added dynamically by replacing "structure_placeholder" (in the real app, the type of fragment depends on some parameters)
MainActivity.java:
public class MainActivity extends AppCompatActivity
{
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
SectionsPagerAdapter sectionsPagerAdapter = new SectionsPagerAdapter(this);
ViewPager2 viewPage = findViewById(R.id.viewpager);
viewPage.setAdapter(sectionsPagerAdapter);
}
/***************************************************************************/
class SectionsPagerAdapter extends FragmentStateAdapter
{
private SectionsPagerAdapter(FragmentActivity fa)
{
super(fa);
}
#NonNull #Override
public Fragment createFragment(int position)
{
return new MyPageFragment();
}
#Override
public int getItemCount()
{
return 1;
}
}
}
activity_main.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"
tools:context=".MainActivity">
<androidx.viewpager2.widget.ViewPager2
android:id="#+id/viewpager"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
MyPageFragment.java:
public class MyPageFragment extends Fragment
{
public MyPageFragment()
{ /* Required empty public constructor*/}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
return inflater.inflate(R.layout.my_page_fragment, container, false);
}
#Override
public void onStart()
{
super.onStart();
Fragment listFragment = SubFragment.newInstance();
FragmentTransaction ft = requireActivity().getSupportFragmentManager().beginTransaction();
ft.replace(R.id.structure_placeholder, listFragment);
ft.commit();
}
}
my_page_fragment.xml:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content"
tools:context=".MyPageFragment">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#string/hello_blank_fragment" />
<FrameLayout
android:id="#+id/structure_placeholder"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
tools:layout_width="100dp"
tools:layout_height="150dp"
tools:background="#color/design_default_color_secondary"
>
</FrameLayout>
</LinearLayout>
SubFragment.java:
public class SubFragment extends Fragment
{
public SubFragment()
{ /* Required empty public constructor*/ }
public static SubFragment newInstance()
{
SubFragment fragment = new SubFragment();
Bundle args = new Bundle();
fragment.setArguments(args);
return fragment;
}
#Override
public View onCreateView(#NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
return inflater.inflate(R.layout.sub_fragment, container, false);
}
}
sub_fragment.xml:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#string/line1" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#string/line2" />
</LinearLayout>
Here is the error log when resuming the app after it has been killed:
2021-11-19 15:46:55.739 8298-8298/com.delrocq.mytestapp E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.delrocq.mytestapp, PID: 8298
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.delrocq.mytestapp/com.delrocq.mytestapp.MainActivity}: java.lang.IllegalArgumentException: No view found for id 0x7f0801db (com.delrocq.mytestapp:id/structure_placeholder) for fragment SubFragment{9eb5496} (ada1c808-c885-49ed-9cd3-f4de1855c6af id=0x7f0801db)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2957)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3032)
at android.app.ActivityThread.-wrap11(Unknown Source:0)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1696)
at android.os.Handler.dispatchMessage(Handler.java:105)
at android.os.Looper.loop(Looper.java:164)
at android.app.ActivityThread.main(ActivityThread.java:6944)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:327)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1374)
Caused by: java.lang.IllegalArgumentException: No view found for id 0x7f0801db (com.delrocq.mytestapp:id/structure_placeholder) for fragment SubFragment{9eb5496} (ada1c808-c885-49ed-9cd3-f4de1855c6af id=0x7f0801db)
I tried to put some logs to understand the lifecycle of the activity/fragments, but it did not help.
What am I doing wrong?
I finally found the solution after hours of searching and many wrong tracks.
Inside a fragment, getChildFragmentManager() shall be used instead of getSupportFragmentManager().
It is so easy when you know it :)
I'm trying to create a tabHost inside a Fragment, so I can create a tabs inside that fragment I've tried changing the extends to android.support.v4.app.Fragment but then the complete app won't build. This issue I have is the following:
wrong 2nd argument type. found'android.app.fragment' required 'android.support.v4.app.fragment'
This is the code I wrote:
public class TimeTableFragment extends Fragment {
FragmentNameFactory nameFactory = new FragmentNameFactory();
String body;
String major;
String status;
private FragmentTabHost mTabHost;
public TimeTableFragment(){
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceStatus){
((MainActivity) getActivity()).setFragmentName(nameFactory.getNameNL(7));
View view = inflater.inflate(R.layout.ftimetable, container, false);
mTabHost = (FragmentTabHost) view.findViewById(android.R.id.tabhost);
mTabHost.setup(getActivity(), getChildFragmentManager(), R.id.realtabcontent);
mTabHost.setup();
mTabHost.addTab(mTabHost.newTabSpec("fragmentb").setIndicator("Fragment B"));
mTabHost.addTab(mTabHost.newTabSpec("fragmentc").setIndicator("Fragment C"));
mTabHost.addTab(mTabHost.newTabSpec("fragmentd").setIndicator("Fragment D"));
return view;
}
#Override
public void onViewCreated(View view, Bundle savedInstance){
super.onViewCreated(view, savedInstance);
}
#Override
public void onActivityCreated(Bundle savedInstance){
super.onActivityCreated(savedInstance);
}}
The .xml (ftimetables):
<?xml version="1.0" encoding="utf-8"?>
<TabHost
android:id="#android:id/tabhost"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:android="http://schemas.android.com/apk/res/android">
<LinearLayout
android:layout_width="match_parent"
android:id="#+id/linearLayout1"
android:layout_height="match_parent"
android:orientation="vertical">
<TabWidget
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#android:id/tabs">
</TabWidget>
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#android:id/tabcontent">
</FrameLayout>
</LinearLayout>
</TabHost>
I hope someone can help me fix this issue!
change your TimeTableFragment import code
import android.app.fragment(x)
import android.support.v4.app.fragment(o)
What I am trying to achieve is to have a fragment that on tablet it shows as a DialogFragment, while on smartphone it would be shown as a regular fragment. I am aware there is already a similar post, but I am not able to make that work - apply the style to fragment.
To show things top down, MainActivity.java:
public class MainActivity extends ActionBarActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
if (item.getItemId() == R.id.action_next) {
decideToNext();
return true;
}
return super.onOptionsItemSelected(item);
}
private void decideToNext() {
String device = getString(R.string.device);
if ("normal".equalsIgnoreCase(device)) {
Intent intent = new Intent(this, DetailedActivity.class);
startActivity(intent);
} else if ("large".equalsIgnoreCase(device)) {
Log.d("SOME_TAG", "Yes, I am seeing this line on tablet only");
DetailedFragment fragment = DetailedFragment.newInstance();
getSupportFragmentManager().beginTransaction().add(fragment, "MAGIC_TAG").commit();
}
}
}
DetailedActivity is nothing much:
public class DetailedActivity extends ActionBarActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.detailed_activity);
}
}
its layout:
<fragment xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/root_container"
android:name="com.myapps.sampleandroid.DetailedFragment"
android:layout_width="match_parent"
android:layout_height="match_parent" />
and the interesting DetailedFragment:
public class DetailedFragment extends Fragment {
public static DetailedFragment newInstance() {
return new DetailedFragment();
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
Context contextThemeWrapper = new ContextThemeWrapper(getActivity(), R.style.MyDialogTheme);
LayoutInflater localInflater = inflater.cloneInContext(contextThemeWrapper);
return localInflater.inflate(R.layout.detailed_fragment, container, false);
}
}
... and its layout:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<TextView
android:id="#+id/textView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Regular Text" />
<TextView
android:id="#+id/textView2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Large Text"
android:textAppearance="?android:attr/textAppearanceLarge" />
<Button
android:id="#+id/button1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Button Dummy" />
</LinearLayout>
In onCreateView I've tried to set the custom styling but it doesn't seem to work for tablet.
Styling
res/values/styles.xml contains:
<resources>
<style name="AppTheme" parent="#style/Theme.AppCompat.Light.DarkActionBar">
</style>
<style name="MyDialogTheme" />
</resources>
while res/values-large/styles.xml:
<resources>
<!-- Is there anything I should add here? -->
<style name="MyDialogTheme" parent="#android:style/Theme.Dialog"/>
</resources>
I've nested MyDialogTheme from Theme.Dialog, but it doesn't seem to help.
On smartphone when tapping on "NEXT" action bar menu item I am seeing the detailed activity (snapshot from an SG2):
while tapping on the same "NEXT" menu item from the tablet it doesn't do anything (except viewing the message on Logcat: Yes, I am seeing this line).
What should I add more in styles.xml or in code in order to see DetailedFragment as a dialog for tablet?
EDIT
I've tried the solution Little Child proposed (to have a DialogFragment contain my initial fragment and show it). So, I've added a WrapperDetailedFragment:
public class WraperDetailedFragment extends DialogFragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.wrap_detailed_fragment, container, false);
}
}
its layout:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/root_container_dialog"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<fragment
android:id="#+id/wrapped_fragment_id"
android:layout_width="match_parent"
android:layout_height="match_parent"
class="com.myapps.sampleandroid.DetailedFragment" />
</LinearLayout>
The code from MainActivity changes to:
private void decideToNext() {
String device = getString(R.string.device);
if ("normal".equalsIgnoreCase(device)) {
Intent intent = new Intent(this, DetailedActivity.class);
startActivity(intent);
} else if ("large".equalsIgnoreCase(device)) {
Log.d("SOME_TAG", "Yes, I am seeing this line ...");
WraperDetailedFragment fragment = new WraperDetailedFragment();
fragment.show(getSupportFragmentManager(), "MAGICAL_TAG");
}
}
but when I'm trying to add this DialogFragment I am getting the following crash:
android.view.InflateException: Binary XML file line #8: Error inflating class fragment
at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:704)
at android.view.LayoutInflater.rInflate(LayoutInflater.java:746)
at android.view.LayoutInflater.inflate(LayoutInflater.java:489)
at android.view.LayoutInflater.inflate(LayoutInflater.java:396)
at com.myapps.sampleandroid.WraperDetailedFragment.onCreateView(WraperDetailedFragment.java:12)
at android.support.v4.app.Fragment.performCreateView(Fragment.java:1478)
at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:927)
at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1082)
at android.support.v4.app.FragmentActivity.onCreateView(FragmentActivity.java:304)
at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:676)
at android.view.LayoutInflater.rInflate(LayoutInflater.java:746)
at android.view.LayoutInflater.inflate(LayoutInflater.java:489)
at android.view.LayoutInflater.inflate(LayoutInflater.java:396)
at com.myapps.sampleandroid.WraperDetailedFragment.onCreateView(WraperDetailedFragment.java:12)
at android.support.v4.app.Fragment.performCreateView(Fragment.java:1478)
at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:927)
at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1104)
at android.support.v4.app.BackStackRecord.run(BackStackRecord.java:682)
at android.support.v4.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:1460)
at android.support.v4.app.FragmentManagerImpl$1.run(FragmentManager.java:440)
at android.os.Handler.handleCallback(Handler.java:615)
at android.os.Handler.dispatchMessage(Handler.java:92)
at android.os.Looper.loop(Looper.java:137)
at android.app.ActivityThread.main(ActivityThread.java:4745)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:511)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:786)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:553)
at dalvik.system.NativeStart.main(Native Method)
Caused by: java.lang.IllegalArgumentException: Binary XML file line #8: Duplicate id 0x7f050047, tag null, or parent id 0x0 with another fragment for com.myapps.sampleandroid.DetailedFragment
at android.support.v4.app.FragmentActivity.onCreateView(FragmentActivity.java:290)
at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:676)
... 28 more
This issue can be easily fixed if instead of trying to make a Fragment look like a DialogFragment I would look from the opposite angle: make a DialogFragment look like a Fragment - after all, a DialogFragment is a Fragment!
The key of this fix is to call or not DialogFragment.setShowsDialog();
So changing the DetailedFragment to:
public class DetailedFragment extends DialogFragment {
private static final String ARG_SHOW_AS_DIALOG = "DetailedFragment.ARG_SHOW_AS_DIALOG";
public static DetailedFragment newInstance(boolean showAsDialog) {
DetailedFragment fragment = new DetailedFragment();
Bundle args = new Bundle();
args.putBoolean(ARG_SHOW_AS_DIALOG, showAsDialog);
fragment.setArguments(args);
return fragment;
}
public static DetailedFragment newInstance() {
return newInstance(true);
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Bundle args = getArguments();
if (args != null) {
setShowsDialog(args.getBoolean(ARG_SHOW_AS_DIALOG, true));
}
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.detailed_fragment, container, false);
}
}
its layout remains as it was, DetailedActivity changes to:
public class DetailedActivity extends ActionBarActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.detailed_activity);
if (savedInstanceState == null) {
DetailedFragment fragment = DetailedFragment.newInstance(false);
getSupportFragmentManager().beginTransaction().add(R.id.root_layout_details, fragment, "Some_tag").commit();
}
}
}
its layout as well:
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/root_layout_details"
android:layout_width="match_parent"
android:layout_height="match_parent" />
and the caller activity does only:
private void decideToNext() {
String device = getString(R.string.device);
if ("normal".equalsIgnoreCase(device)) {
Intent intent = new Intent(this, DetailedActivity.class);
startActivity(intent);
} else if ("large".equalsIgnoreCase(device)) {
DetailedFragment fragment = DetailedFragment.newInstance();
fragment.show(getSupportFragmentManager(), "Tablet_specific");
}
}
To make a DialogFragment show as a regular Fragment, call add() or replace() using a resource ID for the fragment container, e.g
beginTransaction().add(R.id.fragment_container, fragment)
But to make the DialogFragment display as a dialog, call add(fragment, "Fragment Tag"). Behind the scenes this results in a call to add(resId, fragment), setting the resource ID for the fragment container to 0, which causes the DialogFragment to set its showAsDialog option to true.
As a consequence you can use a dialog fragment as a dialog or a regular fragment - depending on your needs - without needing to create any special logic to do it.
OK, I have been there and done that. To make a DialogFragment you need a layout defined in XML. Say, for this you have LinearLayout as root. In this LinearLayout you can add a fragment class="...." and when you display your DialogFragment, it will be the same Fragment you displayed side by side on the tablet now displayed in a DialogFragment.
<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">
<fragment class="com.example.tqafragments.FeedFragment" android:id="#+id/feedFragment" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_weight="1"/>
</LinearLayout>
Like so. And inflate this in your DialogFragment
It's taken me some time to wrap my head around fragments, but this should be my last question on fragments, since I think I just about have them down. I know this is a huge mess of code to go through. But I'd appreciate the help, to make sure I'm not breaking any fundamental rules with fragments.
I am going to post all of my code just to see if someone can "look over it" to see if I'm making any major mistakes or if I should go a simpler route. Lastly, as stated in the title, my fragment is NOT being replaced... it'd being added on top.
File Tree:
MainActivity.java:
package com.example.learn.fragments;
import android.app.Activity;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentTransaction;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.View;
import android.view.ViewGroup;
public class MainActivity extends FragmentActivity{
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.activity_main, menu);
return true;
}
/* Add a class to handle fragment */
public static class SSFFragment extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View v = inflater.inflate(R.layout.choose_pill_frag, container,
false);
return v;
}
}
public void red(View view) {
// Create new fragment and transaction
ExampleFragments newFragment = new ExampleFragments();
android.support.v4.app.FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
// Replace whatever is in the fragment_container view with this fragment,
// and add the transaction to the back stack
transaction.replace(R.id.frag, newFragment);
transaction.addToBackStack(null);
// Commit the transaction
transaction.commit();
}
public void blue(View view) {
//Figure out code for "red" first
}
}
ExampleFragments.java:
package com.example.learn.fragments;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
public class ExampleFragments extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.red_pill_frag, container, false);
}
}
ActivityMain.xml:
<RelativeLayout 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" >
<fragment
android:id="#+id/frag"
android:layout_width="match_parent"
android:layout_height="match_parent"
class="com.example.learn.fragments.MainActivity$SSFFragment" />
</RelativeLayout>
choose_pill_frag.xml
<RelativeLayout 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" >
<ImageButton
android:id="#+id/imageButton1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:onClick="blue"
android:src="#drawable/blue" />
<ImageButton
android:id="#+id/imageButton2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_alignParentTop="true"
android:onClick="red"
android:src="#drawable/red" />
</RelativeLayout>
red_pill_frag.xml
<RelativeLayout 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" >
<TextView
android:id="#+id/textView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_centerHorizontal="true"
android:text="You stay in Wonderland and I show you how deep the rabbit-hole goes."
android:textAppearance="?android:attr/textAppearanceLarge" />
</RelativeLayout>
The application should show two buttons. The two buttons exist in a single fragment, and then if you hit a button, the fragment gets replaced with a new fragment that shows the proper text. As of right now, it should replace, but it only seems to add it on top.
Instead of <fragment> use <FrameLayout> in layout xml for activity.
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/container_id"
android:layout_width="match_parent"
android:layout_height="match_parent" />
Then in FragmentActivity in onCreate add initial fragment (in your case SSFFragment):
FragmentA fragmentA = new FragmentA();
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
transaction.add(R.id.container_id, fragmentA);
transaction.commit();
From inside fragment you can replace fragment in container.
class FragmentA extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
Button button = new Button(getActivity());
button.setText("Replace");
button.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
FragmentB fragmentB = new FragmentB();
transaction.replace(R.id.container_id, fragmentB);
transaction.commit();
}
});
return button;
}
}
Here is the answer to your real question...since this was your second question resulting from your original post, I've modified the solution to get at that frag in another way:
Fragment details = (Fragment)getSupportFragmentManager().findFragmentById(R.id.details);
details = new ExamplesFragment();
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.replace(R.id.details, details);
ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
ft.commit();
Also, the android.support.v4.app part is just not necessary, and frankly leads to possible hours of "going down the wrong road" type efforts by adding and removing it all over your code (as long as you're using:)
import android.support.v4.app.FragmentTransaction;
In this my example, you don't need to import the support for FragmentManager. However, if you're getting errors, make sure you've imported the library itself into your "libs" folder.
This solution will fix the overlapping fragment problem, and hopefully save people hours of tinkering around with replacing frags.
well i was facing the same problem and i just replace the fragment from main layout with linear lay out and guess what its working.. its strange dont know how but its working. i am using actionbar to switch between fragments
for replacing my code is :
protected class MyTabsListener1 implements ActionBar.TabListener{
private Fragment frag ;
public MyTabsListener1 ( Fragment frag){
this.frag = frag;
}
#Override
public void onTabReselected(Tab tab, FragmentTransaction ft) {
// TODO Auto-generated method stub
}
#Override
public void onTabSelected(Tab tab, FragmentTransaction ft) {
switch (tab.getPosition()){
case 0:
ft.replace(R.id.replace, homeFrag);
break;
case 1:
ft.replace(R.id.replace, createFrag);
break;
case 2:
ft.replace(R.id.replace, ioListFrag);
break;
case 3:
ft.replace(R.id.replace, settingFrag);
break;
default:
break;
}
}
and my main layout is this :
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
<LinearLayout
android:id="#+id/replace"
android:layout_width="wrap_content"
android:layout_height="match_parent" >
</LinearLayout>
</LinearLayout>
In short, you CAN NOT replace fragment if u defined it in XML with fragment tag. Instead, as #pawelzieba adviced add Frame tag in your layout, find it and add,remove, replace fragments there.. Hope it helped. Cheers
The main benefit of using fragments is to be able to make them take up portions of the screen rather than the whole screen, which is what Activities do.
If you're just making an app for a small screen that will function like an Activity, but is coded in Fragments, just make a separate FragmentActivity for each of your Fragments.
Make this the onCreate of your FragmentActivity:
public void onCreate(Bundle savedInstanceState) {
setContentView(R.layout.emptylayout);
FragmentManager fragmentManager = getSupportFragmentManager(); //Or getFragmentManager() if you're not using the support library
FragmentTransaction fragmentTransaction = fragmentManager
.beginTransaction();
YourFragment fragment = new YourFragment();
fragmentTransaction.add(R.id.emptyview, fragment);
fragmentTransaction.commit();
}
Where layout/emptylayout is an XML layout file with a FrameLayout. id/emptyview is that FrameLayout.
If you want to use XML for your fragment's actual layout, make a separate XML layout for the actual fragment, and inflate it in the fragment's `onCreateView':
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.files, container, false);
// Do stuff here
return view;
}
Then just use startActivity(new Intent(getActivity(), YourFragmentActivity.class)) to launch a FragmentActivity from a Fragment.
It seems redundant, yeah, but if you're going to be targeting larger screens later (if not, why are you bothering with fragments?), it'll make it easier in the long run.