0

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>
scapegoat
  • 71
  • 2
  • 9
  • Maybe crashing at this line: `lvfrag.isVisible()` but hard to tell without the stack trace. – stkent Oct 21 '15 at 21:31
  • when i test rotating the screen on emulator it works ok, but on my mobile it doesnt. so i don't know how to show a stack trace. i'll try what you said. – scapegoat Oct 21 '15 at 21:45

3 Answers3

3

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>
sanastasiadis
  • 1,182
  • 1
  • 15
  • 23
Vishal Pawar
  • 1,447
  • 8
  • 10
2

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.

Kalininskaya
  • 138
  • 9
1

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).

adelphus
  • 10,116
  • 5
  • 36
  • 46
  • i understand but if everything on my activity will be set to null, how do i know which fragment was used last so i can show it? – scapegoat Oct 21 '15 at 21:50
  • @scapegoat You use onSaveInstanceState() to record the information in a Bundle which Android then passes back to you in onCreate(). It's all explained in detail on the [Android developer site](http://developer.android.com/training/basics/activity-lifecycle/recreating.html) – adelphus Oct 21 '15 at 21:53
  • i already tried this solution earlier passing a boolean to onSaveInstanceState then retrieving it using onRestoreInstanceState but it didn't work either. – scapegoat Oct 21 '15 at 21:59
  • i've updated my code. i put a boolean to check which one was used last and saved it with onSaveInstanceState but it still crashes. – scapegoat Oct 21 '15 at 22:12
  • You shouldn't edit your question like that - it completely invalidates my answer (as well as stkent's comment) and will now confuse people who read it. If your App is crashing, you need to be looking at [logcat](http://developer.android.com/tools/help/logcat.html) to solve it - there are plenty of examples on SO of how to analyze logcat - I gave someone else an [example here](http://stackoverflow.com/questions/32024305/android-share-to-facebook-messenger-error/32029965#32029965). – adelphus Oct 21 '15 at 22:21
  • i apologize for that. i posted the original code again. – scapegoat Oct 21 '15 at 22:28