Search code examples
javaandroidandroid-listfragment

setListNavigationCallbacks crashes the app after switching to landscape


I'm creating a simple app manager to train myself for developing android apps. I want my action bar ( actionbarcompat ) to have drop down navigation + title + subtitle, and I managed to achieve that by creating a custom adapter, but I didn't know how to make my action bar use that spinner adapter. so I did a simple research and I finally managed to achieve my goal through "setListNavigationCallbacks" with passing my adapter as the first argument and "OnNavigationListener" as the second. but I have two questions :

  1. I am not familiar with listeners and how they work and I was wondering if it is possible to set the adapter to my actionbar ( getSupportActionBar ) and capture the callback later?

  2. even though this code works, it crashes every time I switch the layout ( i.e. when I switch from portrait to landscape or vice versa ), I know the problem is with the setListNavigationCallbacks method because when I remove it the app runs in portrait or landscape with no problem but my styles doesn't get applied.

and here is my code ( I use a fragment to show installed apps ) :

MainActivity.java

public class MainActivity extends ActionBarActivity {

private FragmentTransaction fragmentTransaction = getSupportFragmentManager ( ).beginTransaction ( );

@Override
protected void onCreate ( Bundle savedInstanceState ) {

    super.onCreate ( savedInstanceState );

    setContentView ( R.layout.activity_main );

    getSupportActionBar ( ).setNavigationMode(ActionBar.NAVIGATION_MODE_LIST);
    getSupportActionBar ( ).setTitle("");

    if ( findViewById ( R.id.activity_application_manager_framelayout ) != null && savedInstanceState == null ) {

        ApplicationsListFragment applicationsListFragment = new ApplicationsListFragment ( );

        applicationsListFragment.setArguments ( getIntent ( ).getExtras ( ) );
        fragmentTransaction.add ( R.id.activity_application_manager_framelayout , applicationsListFragment ).commit ( );

    }

}

@Override
public boolean onCreateOptionsMenu ( Menu menu ) {

    getMenuInflater ( ).inflate ( R.menu.main , menu );

    return true;

}

}

ApplicationListFragment.java

public class ApplicationsListFragment extends ListFragment {

private ListView listView;
private ApplicationManager applicationManager;
private ActionBar actionBar;
private CustomAdapter customAdapter;
private CustomAdapter.ActionBarDropDownCustomAdapter actionBarDropDownCustomAdapter;
private CustomAdapter.ApplicationsListCustomAdapter applicationsListCustomAdapter;
private List < ApplicationInfo > applications = new ArrayList < ApplicationInfo > ( );
private List < String > actionBarDropDownItems = new ArrayList < String > ( );

@Override
public View onCreateView ( LayoutInflater inflater , ViewGroup container , Bundle savedInstanceState ) {

    View view = inflater.inflate ( R.layout.fragment_applications_list , container , false );
    this.listView = ( ListView ) view.findViewById ( android.R.id.list );

    this.actionBarDropDownItems.add ( "All Apps" );
    this.actionBarDropDownItems.add ( "User Apps" );
    this.actionBarDropDownItems.add ( "System Apps" );

    customAdapter = new CustomAdapter ( );
    actionBarDropDownCustomAdapter = customAdapter.new ActionBarDropDownCustomAdapter ( getActivity ( ) , R.layout.spinner_activity_main_actionbar , R.layout.list_item_activity_main_actionbar , this.actionBarDropDownItems );

    actionBar.setListNavigationCallbacks ( actionBarDropDownCustomAdapter , new OnNavigationListener( ) {

        @Override
        public boolean onNavigationItemSelected ( int arg0 , long arg1 ) {

            if ( actionBarDropDownItems.get ( arg0 ).equals ( actionBarDropDownItems.get ( 0 ) ) ) {

                refreshDisplay ( 0 );

            } else if ( actionBarDropDownItems.get ( arg0 ).equals ( actionBarDropDownItems.get ( 1 ) ) ) {

                refreshDisplay ( 1 );

            } else if ( actionBarDropDownItems.get ( arg0 ).equals ( actionBarDropDownItems.get ( 2 ) ) ) {

                refreshDisplay ( 2 );

            }

            return false;

        }

    } );

    return view;

}

@Override
public void onActivityCreated ( Bundle savedInstanceState ) {

    super.onActivityCreated ( savedInstanceState );

    this.applicationManager = new ApplicationManager ( getActivity() );

    refreshDisplay ( 0 );

}

@Override
public void onAttach ( Activity activity ) {

    super.onAttach ( activity );

    actionBar = ( ( ActionBarActivity ) activity ).getSupportActionBar ( );

}

public boolean refreshDisplay ( int flag ) {

    if ( flag == 0 ) {

        this.applications = this.applicationManager.getAllAppInfos ( );
        this.applicationsListCustomAdapter = customAdapter.new ApplicationsListCustomAdapter ( getActivity() , R.layout.list_item_fragment_applications_list , this.applications );
        this.listView.setAdapter ( applicationsListCustomAdapter );

        return true;

    } else if ( flag == 1 ) {

        this.applications = this.applicationManager.getAllUserAppInfos ( );
        this.applicationsListCustomAdapter = customAdapter.new ApplicationsListCustomAdapter ( getActivity() , R.layout.list_item_fragment_applications_list , this.applications );
        this.listView.setAdapter ( applicationsListCustomAdapter );

        return true;

    } else if ( flag == 2 ) {

        this.applications = this.applicationManager.getAllSystemAppInfos ( );
        this.applicationsListCustomAdapter = customAdapter.new ApplicationsListCustomAdapter ( getActivity() , R.layout.list_item_fragment_applications_list , this.applications );
        this.listView.setAdapter ( applicationsListCustomAdapter );

        return true;

    } else {

        return false;

    }

}

}


Solution

  • I found a solution to both my questions so I thought I share it with you guys :

    1 - You implement "ActionBar.OnNavigationListener" in your class, then you override the "onNavigationItemSelected" method in your class, and finally you pass in your class as the second argument of "setListNavigationCallbacks" ( with the "this" keyword of course )

    2 - You have to override the "onSaveInstanceState" method of your activity ( not fragment ) and put an integer ( getSupportActionBar ( ).getSelectedNavigationIndex ( ) ) in the "savedInstanceState", the you override the "onRestoreInstanceState" method of your activity and set "getSupportActionBar ( ).setSelectedNavigationItem ( )" to the value you saved in the "onSaveInstanceState".