2

I have a navigation drawer and onClick is as follows:

private class SlideMenuClickListener implements
    ListView.OnItemClickListener {
        @Override
        public void onItemClick(AdapterView<?> parent, View view, final int position,
                long id) {
            //  System.out.println("Clicked");
            mDrawerLayout.postDelayed(new Runnable() {
                @Override
                public void run() {
                    displayView(position);
                }
            }, 200);

        }
    }

My displayView(position); method is:

private void displayView(int position) {
        // update the main content by replacing fragments
        Fragment fragment = null;
        switch (position) {
        case 0:

            fragment = new FragmentTab1();
            break;
        case 1:
            fragment = new FragmentTab2();
            break;
        case 2:
            fragment = new FragmentTab3();
            break;
        case 3:
            fragment = new FragmentTab3();
            //create dialog 



            break;
        default:
            break;
        }

        if (fragment != null) {
            FragmentManager fragmentManager = getFragmentManager();
            fragmentManager.beginTransaction()
            .replace(R.id.frame_container, fragment).commit();

            // update selected item and title, then close the drawer
            mDrawerList.setItemChecked(position, true);
            mDrawerList.setSelection(position);
            setTitle(navMenuTitles[position]);
            mDrawerLayout.closeDrawer(Gravity.LEFT);
        } else {
            // error in creating fragment
            Log.e("MainActivity", "Error in creating fragment");
        }
    }

Now in the onCreateView of my Fragment class I call:

new ListLoader().execute(getActivity());

Here is the implementation:

public class ListLoader extends AsyncTask<Context, Void, CurAdapter> {

        ProgressDialog Asycdialog = new ProgressDialog(getActivity());
        @Override
        protected void onPreExecute() {
            // TODO Auto-generated method stub

            Asycdialog.setMessage("Working");
            Asycdialog.getWindow().setGravity(Gravity.CENTER_VERTICAL);
            Asycdialog.getWindow().setGravity(Gravity.CENTER_HORIZONTAL);
            Asycdialog.setCancelable(false);
            Asycdialog.show();
            super.onPreExecute();
        }

        protected void onPostExecute(CurAdapter result) {
            Asycdialog.cancel();
            lv.setAdapter(result);
        //  dbHelper.close();
        }

        @Override
        protected CurAdapter doInBackground(Context... params) {

            System.out.println("Loading list");
            dbHelper.open();
            final String status = fetch();
            Cursor mCur; 
            mCur = dbHelper.magicQuery(status); 
            Cur = new CurAdapter(getActivity(), mCur,0);    


            Cur.setFilterQueryProvider(new FilterQueryProvider() {
                public Cursor runQuery(CharSequence constraint) {
                    return dbHelper.getDirectoryList(constraint,status);
                }
            }); 


            return Cur;
        }


    }

The message Loading List appears each time I open and close the Navigation Drawer, what is making this to execute? I have put a System.out message in my onCreateView but that does not show up, while as I am calling the AsyncTask only from onCreateView. What do I miss here?

I also face a flicker onClick of NavDrawer item to Fragment transition, even though I am using the asynchronous method. I have to, against my wish use a loading progress dialog.

Edit:

Got the culprit:

SearchView.OnQueryTextListener textChangeListener = new SearchView.OnQueryTextListener() {
        @Override
        public boolean onQueryTextChange(String newText){

            if (TextUtils.isEmpty(newText)){
                new ListLoader().execute(getActivity());
            }
            else {
                CursorAdapter filterAdapter = (CursorAdapter) Cur;
                filterAdapter.getFilter().filter(newText.toString());
            }

            return true;
        }

        @Override
        public boolean onQueryTextSubmit(String query) {
            return true;
        }
    };

Edit I fiddled around with OnQueryTextListener and this is resolved.

    int ix =1; 
    SearchView.OnQueryTextListener textChangeListener = new SearchView.OnQueryTextListener() {
        @Override
        public boolean onQueryTextChange(String newText){
            if (TextUtils.isEmpty(newText)){
                if(ix == 2)
                    new ListLoader().execute(getActivity());


            }
            else {
                ix = 2;
                CursorAdapter filterAdapter = (CursorAdapter) Cur;
                filterAdapter.getFilter().filter(newText.toString());
            }

            return true;
        }

        @Override
        public boolean onQueryTextSubmit(String query) {
            return true;

        }
    };
Skynet
  • 7,820
  • 5
  • 44
  • 80

1 Answers1

2

The Reason:

This is the observed behavior when using Fragments with NavigationDrawer. Each time the NavigationDrawer is opened, the current Fragment's onPause() and onDestroy() are called, and each time the drawer is closed, the current Fragment's onCreateView() and onResume() are called.

In a nutshell, the Fragment is destroyed and created anew with every open/close cycle of the drawer. That's why your AsyncTask is called repeatedly.

The Solution(s):

You have two options:

1. Save the state of each Fragment in onSavedInstanceState() and restore the saved data in onCreate(). Execute the AsyncTask only if savedInstanceState is null in onCreate() or onCreateView().

2. Try using Activitys instead of Fragments. Activitys are not created anew when the drawer is opened/closed.

Skynet
  • 7,820
  • 5
  • 44
  • 80
Yash Sampat
  • 30,051
  • 12
  • 94
  • 120
  • I have a System.out statement in my onCreateView - that is the only entry point for my ListLoader AsyncTask (`new ListLoader().execute(getActivity());`) to execute as I call it from there. While as the System.out in the doInbackground method of ListLoader Class is called, I do not see any log pertaining to the system.out in my onCreateView. – Skynet Mar 21 '15 at 12:06
  • @Skynet: I'd advise you to check the code again. The cycle I've described is correct, and is indeed the observed behavior of `Fragment`s with `NavigationDrawer`. – Yash Sampat Mar 25 '15 at 08:58
  • Hello ZygoteInit, check [this](http://stackoverflow.com/questions/26655992/opening-closing-navdrawer-with-invalidateoptionsmenu-cause-onrestore-call-on-s). As per my observation, I reckon that onResume and onStart are called, however onCreate is not called. I dont get any debug logs from onCreate. Yes that is not tested on memory intense operations. – Skynet Mar 25 '15 at 09:28
  • @Skynet: so did that answer work for you ? sorry for replying late btw ... :) – Yash Sampat Apr 25 '15 at 11:24
  • I did a bit of dirty trick to handle it, have updated my question. – Skynet Apr 26 '15 at 14:48