Search code examples
androidfragmentsearchviewsimplecursoradapter

how to Filter by Using SearcheView Widjet on ListFragment


Hello I am googling on that issue for long time but no solution i have ListFragment that show data from SQlite i want to build the option to filter by TextChange i Added the widjet and its working perfect - but how to make the filter ?? getFilter().filter() is not enough .

this is fragmentList

public class CarGallery extends ListFragment {
    public static final String ROW_ID = "row_id"; // Intent extra key
    private int contentFrameId;
    private SimpleCursorAdapter myCarSimpleCursorAdapter;
private  SearchView searchView;
private   SearchManager searchManager;
private Cursor cursor;
   private String[] from;
   private int[] to;
    @Override
    public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
        setHasOptionsMenu(true);
        contentFrameId= ((ViewGroup) getView().getParent()).getId();
        // map each contact's name to a TextView in the ListView layout
         from = new String[] {"number","manufacturer","model","img"};
        // in file  car_row.xml
         to = new int[] {R.id.textViewNumber,R.id.textViewManufacturer,R.id.textViewModel,R.id.imageViewCar};
        myCarSimpleCursorAdapter = new SimpleCursorAdapter(getActivity().getApplicationContext(),
                R.layout.car_row, // layout to inflate it
                null , // cursor adapter : if null then it will be created within the constructor
                from , to , 0 );
        myCarSimpleCursorAdapter.setViewBinder(new MyViewBinder());
        setListAdapter(myCarSimpleCursorAdapter);  //databinding --> set contactView's adapter
    }
    @Override
    public void onResume() {
        super.onResume();
        // create new GetCarsTask and execute it
        //  our inner class
        new GetCarTask().execute();//  (Object[]) null

        getActivity().setTitle(R.string.actionbarTitleGallery);
    }
    @Override
    public void onStop() {
        super.onStop();
         cursor = myCarSimpleCursorAdapter.getCursor(); // get current Cursor
        if (cursor != null)
            cursor.deactivate(); // deactivate it
        myCarSimpleCursorAdapter.changeCursor(null); // adapted now has no Cursor
    }
    ////// performs database query outside GUI thread/////////////
    private class GetCarTask extends AsyncTask<Void , Void , Cursor>{
        DatabaseConnector databaseConnector = new DatabaseConnector(getActivity().getApplicationContext());
        @Override
        protected Cursor doInBackground(Void... voids) {
            databaseConnector.open();
            return databaseConnector.getAllCars();
        }
        @Override
        protected void onPostExecute(Cursor result) {
            myCarSimpleCursorAdapter.changeCursor(result);
            databaseConnector.close();
        }
    }
    /////// MyViewBinder Class////////////////////////////////
    public class MyViewBinder implements SimpleCursorAdapter.ViewBinder {
        @Override
        public boolean setViewValue(View view, Cursor cursor, int columnIndex) {
            int viewID = view.getId();
            switch (viewID) {
                case R.id.textViewNumber:
                    TextView carNumber = (TextView) view;
                    String car_number;
                    car_number = cursor.getString(cursor.getColumnIndex("number"));
                    carNumber.setText(car_number);
                    break:
                case R.id.textViewManufacturer:
                    TextView carManufacturer = (TextView) view;
                    String car_manufacturer;
                    car_manufacturer = cursor.getString(cursor.getColumnIndex("manufacturer"));
                    carManufacturer.setText(car_manufacturer);
                    break;
                case R.id.textViewModel:
                    TextView carModel = (TextView) view;
                    String car_model;
                    car_model = cursor.getString(cursor.getColumnIndex("model"));
                    carModel.setText(car_model);
                    break;
                case R.id.imageViewCar:
                    ImageView carImageView = (ImageView) view;
                    byte[] imageBytes = cursor.getBlob(cursor.getColumnIndex("img"));
                    if (imageBytes != null) {                  carImageView.setImageBitmap(BitmapFactory.decodeByteArray(imageBytes, 0, imageBytes.length));
                    } else {
                        // carImageView.setBackgroundResource(R.mipmap.ic_launcher);
                    }
                    break;
            }
            return true;
        }
 @Override
    public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
        super.onCreateOptionsMenu(menu, inflater);
        inflater.inflate(R.menu.search , menu);
        final MenuItem searchItem = menu.findItem(R.id.action_search);
        searchView = (SearchView) MenuItemCompat.getActionView(menu.findItem(R.id.action_search));
        searchManager = (SearchManager)getActivity().getSystemService(Context.SEARCH_SERVICE);       searchView.setSearchableInfo(searchManager.getSearchableInfo(getActivity().getComponentName()));
        if(searchItem != null){
                searchView = (SearchView) MenuItemCompat.getActionView(searchItem);
                searchView.setOnCloseListener(new SearchView.OnCloseListener() {
                    @Override
                    public boolean onClose() {
                        // some opertion
                        return true;
                    }
                });
            searchView.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    //some operario
                }
            });
            EditText searchPlate = (EditText) searchView.findViewById(android.support.v7.appcompat.R.id.search_src_text);
            searchPlate.setHint("Search");
            View searchPlateView = searchView.findViewById(android.support.v7.appcompat.R.id.search_plate);            searchPlateView.setBackgroundColor(ContextCompat.getColor(getActivity(), android.R.color.transparent));
            //  this method for search process
            searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
                @Override
                public boolean onQueryTextSubmit(String s) {
                    //  this method when query submitted
                    Toast.makeText(getActivity(), s, Toast.LENGTH_SHORT).show();
                    return true;
                }
                @Override
                public boolean onQueryTextChange(String s) {
                    // this method for auto complete search process
                    Toast.makeText(getActivity(), s, Toast.LENGTH_SHORT).show();
             myCarSimpleCursorAdapter.getFilter().filter(s);                    return true;
                }
            });
        }
      }
    }

Solution

  • For peaple that will have problems with that issue i am posting the best sloution.

    Step 1 : Define empty simpleCursor Adapter

        public class CarGallery extends ListFragment {
    
            public static final String ROW_ID = "row_id"; // Intent extra key
            private SimpleCursorAdapter myCarSimpleCursorAdapter;
            private Cursor mCursor;
            private String[] from;
            private int[] to;
    
            @Override
            public void onViewCreated(final View view, @Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
                setHasOptionsMenu(true);
                // map each car details to a TextViews in the ListView layout
                from = new String[]{"number", "manufacturer", "model", "img"};
                // in file  car_row.xml
                to = new int[]{R.id.textViewNumber, R.id.textViewManufacturer, R.id.textViewModel, R.id.imageViewCar};
                //Create Empty Adapter
                myCarSimpleCursorAdapter = new SimpleCursorAdapter(getActivity().getApplicationContext(),
                        R.layout.car_row, // layout to inflate it
                        mCursor, // cursor adapter : if null then it will be created within the constructor
                        from, to, 0);
    
        // set the Adapter on ViewBinder Class 
                myCarSimpleCursorAdapter.setViewBinder(new MyViewBinder());
                setListAdapter(myCarSimpleCursorAdapter);  //databinding --> set contactView's adapter
    }
    

    Step 2 : Define the Filter method in DatabaseConnector after we created the table :

    public class DatabaseConnector //DAL
    {
        private static final String DATABASE_NAME = "UserCars";
    
        private DatabaseOpenHelper databaseOpenHelper;
        private SQLiteDatabase database;
    
        public Cursor getFilteredCars(CharSequence charSequence) {
    
            if (charSequence == null || charSequence.length() == 0) {
                return database.rawQuery("SELECT _id ,number, manufacturer , model ,  img FROM cars order by manufacturer", null);
            } else {
                String value = "%" + charSequence.toString() + "%";
    
                return database.rawQuery("SELECT _id , number , manufacturer , model ,img FROM cars WHERE  manufacturer || number || model like ?", new String[]{value});
    
            }
    
        }
    }
    

    Step 3 : Create the Search Widjet on Fragment Class

    // creating the SearchView Widjet
        @Override
        public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
            super.onCreateOptionsMenu(menu, inflater);
            inflater.inflate(R.menu.search, menu);
            MenuItem searchItem = menu.findItem(R.id.action_search);
    
            SearchView searchView = (SearchView) MenuItemCompat.getActionView(menu.findItem(R.id.action_search));
            SearchManager searchManager = (SearchManager) getActivity().getSystemService(Context.SEARCH_SERVICE);
            searchView.setSearchableInfo(searchManager.getSearchableInfo(getActivity().getComponentName()));
    
    
            if (searchItem != null) {
                searchView = (SearchView) MenuItemCompat.getActionView(searchItem);
    
                searchView.setOnCloseListener(new SearchView.OnCloseListener() {
                    @Override
                    public boolean onClose() {
                        // some opertion
    
                        return true;
                    }
                });
                searchView.setOnClickListener(new View.OnClickListener() {
                    @Override
                    public void onClick(View view) {
                        //some operarion
    
                    }
                });
    
                EditText searchPlate = (EditText) searchView.findViewById(android.support.v7.appcompat.R.id.search_src_text);
                searchPlate.setHint("Search");
                View searchPlateView = searchView.findViewById(android.support.v7.appcompat.R.id.search_plate);
                searchPlateView.setBackgroundColor(ContextCompat.getColor(getActivity(), android.R.color.transparent));
    
                //  this method for search process
                searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
                    @Override
                    public boolean onQueryTextSubmit(String s) {
                        //  this method when query submitted
                        myCarSimpleCursorAdapter.getFilter().filter(s);
    
                        return true;
                    }
    
                    @Override
                    public boolean onQueryTextChange(String s) {
                        // this method for auto complete search process
                        myCarSimpleCursorAdapter.getFilter().filter(s);
                        return true;
                    }
                });
            }
        }
    

    With it"s XML

    <menu 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"
        tools:context=".ui.home.activities.TransactionSearchActivity">
        <item
            android:id="@+id/action_search"
            android:icon="@android:drawable/ic_menu_search"
            android:title="Search"
            app:actionViewClass="android.support.v7.widget.SearchView"
            app:showAsAction="ifRoom" />
    </menu>
    

    Step 4 : back to onViewCreate to setFilterQueryProvider , and create the method getCursor

    // add this code to onViewCreate 
            myCarSimpleCursorAdapter.setFilterQueryProvider(new FilterQueryProvider() {
                @Override
                public Cursor runQuery(CharSequence charSequence) {
                    return getCursor(charSequence.toString());
    
    
    // create the getCursor that Include AsyncTask to get data on BackGround 
    
        private Cursor getCursor(String str) {
            class GetCarTask extends AsyncTask<CharSequence, Object, Cursor> {
                DatabaseConnector databaseConnector = new DatabaseConnector(getActivity().getApplicationContext());
    
                @Override
                protected Cursor doInBackground(CharSequence... charSequences) {
                    databaseConnector.open();
                    return databaseConnector.getFilteredCars(charSequences[0]);
    
                }
    
                @Override
                protected void onPostExecute(Cursor cursor) {
                    super.onPostExecute(cursor);
                    myCarSimpleCursorAdapter.changeCursor(cursor);
                    databaseConnector.close();
                }
    
            }
            new GetCarTask().execute(new CharSequence[]{str});
            return null;
    
        } // end of getCursor
    

    Step 5 : Finaly execute the Cursor with null in onResum sending null String wil show all the data befor the filtering and that's it .

    @Override
    public void onResume() {
        super.onResume();
    
        getActivity().setTitle(R.string.actionbarTitleGallery);
        mCursor = getCursor("");
    }