简体   繁体   中英

fragment crashing on screen rotation

Using the FAB button the app alternates between two fragments. I am trying to make the current fragment persist when rotating the screen but everytime the screen rotates the app crashes. I tried many solutions but none worked. Why is it crashing? I am using NetBeans so I'm not sure who to post logcat.

       public class agendaFalante extends AppCompatActivity
{
    /** Called when the activity is first created. */
    private Toolbar toolbar;
    private FloatingActionButton fab ;
    private listViewFrag lvfrag;
    private newEventFrag nef;
    private FragmentManager fragmentManager;
    private FragmentTransaction fragmentTransaction;

    @Override
    public void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        toolbar = (Toolbar) findViewById (R.id.toolbar);
        setSupportActionBar(toolbar);
        fragmentManager = getSupportFragmentManager();
        fragmentTransaction = fragmentManager.beginTransaction();
        if (savedInstanceState == null) {
            lvfrag = new listViewFrag();
            fragmentTransaction.replace(R.id.ll, lvfrag, "lvfrag");
            fragmentTransaction.commit();
        }else{
            if(lvfrag!=null && lvfrag.isVisible()){
                fragmentTransaction.replace(R.id.ll, lvfrag);
                fragmentTransaction.commit();
            }else if(nef!=null && nef.isVisible()){
                fragmentTransaction.replace(R.id.ll, nef);
                fragmentTransaction.commit();
            }
        }
        fab = (FloatingActionButton)  findViewById(R.id.fab);
        fab.setOnClickListener(new View.OnClickListener() {
        public void onClick(View v) {
            fragmentTransaction = fragmentManager.beginTransaction();
            if(nef!=null && nef.isVisible()){
                lvfrag = (listViewFrag) getSupportFragmentManager().findFragmentByTag("lvfrag");
                fragmentTransaction.replace(R.id.ll,lvfrag);
            }else{
                if(lvfrag.isVisible()){
                    nef = (newEventFrag) getSupportFragmentManager().findFragmentByTag("nef");
                    if(nef==null){
                        nef = new newEventFrag();
                        fragmentTransaction.replace(R.id.ll,nef,"nef");
                    }else{
                        fragmentTransaction.replace(R.id.ll,nef);
                    }                    
                }
            }
            fragmentTransaction.addToBackStack(null);
            fragmentTransaction.commit();
        }
    });
    }
    public boolean OnCreateOptionsMenu(Menu menu){
        getMenuInflater().inflate(R.menu.menu_layout,menu);
        return true;
    }

}

main xml

<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:id="@+id/root"
    tools:context=".agendaFalante">
<LinearLayout android:layout_width="match_parent"
              android:layout_height="match_parent"
              android:id="@+id/ll"
              android:orientation="vertical">
    <android.support.v7.widget.Toolbar
        android:id="@+id/toolbar"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentTop="true"
        android:background="?attr/colorPrimary"
        android:elevation="6dp"
        android:minHeight="?attr/actionBarSize"
        android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
        app:popupTheme="@style/ThemeOverlay.AppCompat.Light"
    />

</LinearLayout>
<android.support.design.widget.FloatingActionButton
        android:id="@+id/fab"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_margin="16dp"
        android:clickable="true"
        android:src="@drawable/ic_done"
         app:layout_anchor="@id/ll"
          app:backgroundTint="#CE93D8"
        app:layout_anchorGravity="bottom|right|end"/>

</android.support.design.widget.CoordinatorLayout>

Fragment 1 xml

public class listViewFrag extends Fragment{

    private ListView atividadesView;
    private ArrayList<String> alist;
    private ArrayAdapter<String> aDapter;


    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.listviewfrag, container, false);
        atividadesView = (ListView) view.findViewById(R.id.listView);
        alist = new ArrayList<String>();
        alist.add("oi");
        aDapter = new ArrayAdapter<String>(getActivity(), android.R.layout.simple_list_item_1,alist);
        atividadesView.setAdapter(aDapter);
        return view;
    }
    public void addText(String text){
        alist.add(text);
        aDapter.notifyDataSetChanged();
    }
}

Fragment xml:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
>

    <ListView
        android:id="@+id/listView"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" >
    </ListView>

</LinearLayout>

Fragment 2:

public class newEventFrag extends Fragment{

    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.neweventfrag, container, false);
        return view;
    }

}

Fragment xml

<TableLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fillViewport="true"
    >
    <TableRow
        android:layout_height="0dp"
        android:layout_weight="1">
        <EditText
                android:text="Insira o título"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_weight="0.8"
            >
        </EditText>
        <Button
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="0.2"
            android:id="@+id/record"
            android:src="@drawable/ic_mic"
        >
        </Button>
    </TableRow>
    <TableRow
        android:layout_height="0dp"
        android:layout_weight="1">
        <DatePicker
            android:id="@+id/dpResult"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:datePickerMode="spinner"
            android:calendarViewShown="false"
        />
    </TableRow>
</TableLayout>

Fragments are not destroyed when the screen is rotated, onlt the activity. However, the field lvfrag will not be the fragment you created prior to rotation until you find the fragment and assign it to the field. So you should firstly "find" the fragment when savedInstanceState is not null. ---

if (savedInstanceState == null) {
        lvfrag = new listViewFrag();
        fragmentTransaction.replace(R.id.ll, lvfrag, "lvfrag");
        fragmentTransaction.commit();
    }else{
        lvfrag = (listViewFrag)this.getSupportFragmentManager().findFragmentByTag("lvfrag");  
        if(lvfrag!=null)

.... you will need to reset any of the fragment's fields and then replace and commit again here }

I show here for lvfrag only but you can do the code to include for nef as well. Your mainActivity needs to know which fragment was visible when the activity was destroyed. You should overwrite an onSaveInstanceState method to send back which frag is visible in the bundle when the activity is destroyed on rotation and then capture that when replacing the fragment.

When the screen is rotated, the savedInstanceState parameter in onCreate() will contain a Bundle allowing you to return your Activity to the state it was in. But you still need to treat it as a brand new Activity and load up all the controls again:

if (savedInstanceState == null) {
            lvfrag = new listViewFrag();
            fragmentTransaction.replace(R.id.ll, lvfrag, "lvfrag");
            fragmentTransaction.commit();
        } else {
           // even though savedInstanceState is not null
           // lvfrag still needs to be created
            if(lvfrag.isVisible()){

I've shown a portion of your code above - in it, you are assuming that lvfrag is already created if savedInstanceState is not null - this is wrong.

Every time the screen is rotated, Android recreates your Activity from new - you must recreate any fragments (and any other controls) and reinitialize all the fields in your Activity. The most likely reason your App is crashing is because you are attempting to call lvfrag.isVisible() when lvfrag hasn't been initialized (and so, is null).

Write this line:: android:configChanges="orientation|screenSize|keyboardHidden" on your AndroidManifest.xml on which activity where you added fragment.

<activity
    android:name=".MainActivity"
    android:label="@string/title_activity_main"
    android:configChanges="orientation|screenSize|keyboardHidden">
    <intent-filter>
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.DEFAULT" />
    </intent-filter>
</activity>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM