androidsearchandroid-custom-viewsimpleadapter

Android - Adding search-bar to custom-list-view & simple adaptor


I have tried creating a custom ListView & filling values using Array of HashMaps. UI is showing okay:

enter image description here

But whenever anything typed in the search-box, app gets closed saying Unfortunately app is stopped.

I have searched a lot, but not able to get this done.

Maybe the method how I have tried to apply filter is wrong?

Here is code:

public class MyCustomListView extends ListActivity {
    SimpleAdapter adapter;
    EditText inputSearch;

    static final ArrayList<HashMap<String,String>> list = new ArrayList<HashMap<String,String>>();
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.custom_list_view);
        inputSearch = (EditText) findViewById(R.id.search);

        ImageView si = (ImageView) findViewById(R.id.search_icon);
        si.setImageResource(R.drawable.blue_search);

        adapter = new SimpleAdapter(
                this,
                list,
                R.layout.custom_row_view,
                new String[] {"img","name","dob","anniversary"},
                new int[] {R.id.image,R.id.text1,R.id.text2, R.id.text3}
        );

        try{
            getItemFromXMLandPopulateList(this); // gets the complete list
        } catch (Exception e){
            Toast.makeText(this, "Error:\n" + e, Toast.LENGTH_LONG).show();
        }

        setListAdapter(adapter);

        // Capture Text in EditText
        inputSearch.addTextChangedListener(new TextWatcher() {
            @Override
            public void onTextChanged(CharSequence s, int start, int before, int count) {
                adapter.getFilter().filter(s);
            }

            @Override
            public void beforeTextChanged(CharSequence s, int start, int count, int after) {
            }

            @Override
            public void afterTextChanged(Editable s) {
            }
        });
    }

    private void getItemFromXMLandPopulateList(Activity activity) throws XmlPullParserException, IOException {
        Resources res = activity.getResources();
        XmlResourceParser xpp = res.getXml(R.xml.db);
        String id=null, name=null, dob=null, anniversary=null;
        xpp.next();
        int eventType = xpp.getEventType();

        while (eventType != XmlPullParser.END_DOCUMENT){
            switch(eventType){
                case XmlPullParser.START_TAG:
                    String tagname = xpp.getName();
                    if(tagname.equals("ID")){
                        eventType = xpp.next();
                        if (eventType == XmlPullParser.TEXT) {
                            id = xpp.getText();
                        }
                    } else if(tagname.equals("Name")){
                        eventType = xpp.next();
                        if (eventType == XmlPullParser.TEXT) {
                            name = xpp.getText();
                        }
                    } else if(tagname.equals("DOB")){
                        eventType = xpp.next();
                        if (eventType == XmlPullParser.TEXT) {
                            dob = xpp.getText();
                        }
                    } else if(tagname.equals("Anniversary")){
                        eventType = xpp.next();
                        if (eventType == XmlPullParser.TEXT) {
                            anniversary = xpp.getText();
                        }
                    }
                    break;
                case XmlPullParser.END_TAG:
                    if(xpp.getName().equals("F")){
                        // Adding 3 value hash to array-list
                        HashMap<String,String> temp = new HashMap<String,String>();
                        temp.put("img", Integer.toString(R.mipmap.profile));
                        temp.put("id", id);
                        temp.put("name", name);
                        temp.put("dob", dob);
                        temp.put("anniversary", anniversary);
                        list.add(temp);
                        // Clearing values for next set
                        id=""; name = ""; dob = ""; anniversary = "";
                    }
                    break;
                default:
                    break;
            }
            eventType = xpp.next();
        }
    }

    protected void onListItemClick(ListView l, View v, int position, long id) {
        super.onListItemClick(l, v, position, id);
        HashMap<String, String> item = (HashMap<String, String>) getListAdapter().getItem(position);
        String xmlFile = "r" + item.get("id");
        String name = item.get("name");
        //Toast.makeText(this, "Showing details of: " + name, Toast.LENGTH_LONG).show();

        Intent intent = new Intent(this, ShowDetails.class);
        intent.putExtra("xml", xmlFile);
        startActivity(intent);
    }
}

Crash log pasted below, seems to say NullPointerException, but not sure how to resolve.

I/ActivityManager( 1596): Displayed com.karthikhiraskar.samplesqlitedb/.MyCustomListView: +237ms
W/Filter  (10785): An exception occured during performFiltering()!
W/Filter  (10785): java.lang.NullPointerException
W/Filter  (10785):  at android.widget.SimpleAdapter$SimpleFilter.performFiltering(SimpleAdapter.java:354)
W/Filter  (10785):  at android.widget.Filter$RequestHandler.handleMessage(Filter.java:234)
W/Filter  (10785):  at android.os.Handler.dispatchMessage(Handler.java:102)
W/Filter  (10785):  at android.os.Looper.loop(Looper.java:136)
W/Filter  (10785):  at android.os.HandlerThread.run(HandlerThread.java:61)
I/LatinIME:LogUtils( 1692): Dictionary info: dictionary = contacts.en_US.dict ; version = ? ; date = ?
D/AndroidRuntime(10785): Shutting down VM
W/dalvikvm(10785): threadid=1: thread exiting with uncaught exception (group=0xacd4eb20)
E/AndroidRuntime(10785): FATAL EXCEPTION: main
E/AndroidRuntime(10785): Process: com.karthikhiraskar.samplesqlitedb, PID: 10785
E/AndroidRuntime(10785): java.lang.NullPointerException
E/AndroidRuntime(10785):    at android.widget.SimpleAdapter.getCount(SimpleAdapter.java:93)
E/AndroidRuntime(10785):    at android.widget.AdapterView.checkFocus(AdapterView.java:713)
E/AndroidRuntime(10785):    at android.widget.AdapterView$AdapterDataSetObserver.onInvalidated(AdapterView.java:836)
E/AndroidRuntime(10785):    at android.widget.AbsListView$AdapterDataSetObserver.onInvalidated(AbsListView.java:6288)
E/AndroidRuntime(10785):    at android.database.DataSetObservable.notifyInvalidated(DataSetObservable.java:50)
E/AndroidRuntime(10785):    at android.widget.BaseAdapter.notifyDataSetInvalidated(BaseAdapter.java:59)
E/AndroidRuntime(10785):    at android.widget.SimpleAdapter$SimpleFilter.publishResults(SimpleAdapter.java:383)
E/AndroidRuntime(10785):    at android.widget.Filter$ResultsHandler.handleMessage(Filter.java:282)
E/AndroidRuntime(10785):    at android.os.Handler.dispatchMessage(Handler.java:102)
E/AndroidRuntime(10785):    at android.os.Looper.loop(Looper.java:136)
E/AndroidRuntime(10785):    at android.app.ActivityThread.main(ActivityThread.java:5017)
E/AndroidRuntime(10785):    at java.lang.reflect.Method.invokeNative(Native Method)
E/AndroidRuntime(10785):    at java.lang.reflect.Method.invoke(Method.java:515)
E/AndroidRuntime(10785):    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:779)
E/AndroidRuntime(10785):    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:595)
E/AndroidRuntime(10785):    at dalvik.system.NativeStart.main(Native Method)
W/ActivityManager( 1596):   Force finishing activity com.karthikhiraskar.samplesqlitedb/.MyCustomListView
D/dalvikvm( 1596): GC_FOR_ALLOC freed 505K, 21% free 9295K/11692K, paused 7ms, total 7ms
W/ActivityManager( 1596): Activity pause timeout for ActivityRecord{ad45ab60 u0 com.karthikhiraskar.samplesqlitedb/.MyCustomListView t59 f}
E/SoundPool( 1596): error loading /system/media/audio/ui/Effect_Tick.ogg
W/AudioService( 1596): Soundpool could not load file: /system/media/audio/ui/Effect_Tick.ogg
E/SoundPool( 1596): error loading /system/media/audio/ui/Effect_Tick.ogg
W/AudioService( 1596): Soundpool could not load file: /system/media/audio/ui/Effect_Tick.ogg
E/SoundPool( 1596): error loading /system/media/audio/ui/Effect_Tick.ogg
W/AudioService( 1596): Soundpool could not load file: /system/media/audio/ui/Effect_Tick.ogg
E/SoundPool( 1596): error loading /system/media/audio/ui/Effect_Tick.ogg
W/AudioService( 1596): Soundpool could not load file: /system/media/audio/ui/Effect_Tick.ogg
E/SoundPool( 1596): error loading /system/media/audio/ui/Effect_Tick.ogg
W/AudioService( 1596): Soundpool could not load file: /system/media/audio/ui/Effect_Tick.ogg
E/SoundPool( 1596): error loading /system/media/audio/ui/KeypressStandard.ogg
W/AudioService( 1596): Soundpool could not load file: /system/media/audio/ui/KeypressStandard.ogg
E/SoundPool( 1596): error loading /system/media/audio/ui/KeypressSpacebar.ogg
W/AudioService( 1596): Soundpool could not load file: /system/media/audio/ui/KeypressSpacebar.ogg
E/SoundPool( 1596): error loading /system/media/audio/ui/KeypressDelete.ogg
W/AudioService( 1596): Soundpool could not load file: /system/media/audio/ui/KeypressDelete.ogg
E/SoundPool( 1596): error loading /system/media/audio/ui/KeypressReturn.ogg
W/AudioService( 1596): Soundpool could not load file: /system/media/audio/ui/KeypressReturn.ogg
I/Process (10785): Sending signal. PID: 10785 SIG: 9
E/SoundPool( 1596): error loading /system/media/audio/ui/KeypressInvalid.ogg
W/AudioService( 1596): Soundpool could not load file: /system/media/audio/ui/KeypressInvalid.ogg
W/AudioService( 1596): onLoadSoundEffects(), Error -1 while loading samples
W/InputDispatcher( 1596): channel 'ad54e4b0 com.karthikhiraskar.samplesqlitedb/com.karthikhiraskar.samplesqlitedb.MyCustomListView (server)' ~ Consumer closed input channel or an error occurred.  events=0x9
E/InputDispatcher( 1596): channel 'ad54e4b0 com.karthikhiraskar.samplesqlitedb/com.karthikhiraskar.samplesqlitedb.MyCustomListView (server)' ~ Channel is unrecoverably broken and will be disposed!
I/ActivityManager( 1596): Process com.karthikhiraskar.samplesqlitedb (pid 10785) has died.
W/InputDispatcher( 1596): Attempted to unregister already unregistered input channel 'ad54e4b0 com.karthikhiraskar.samplesqlitedb/com.karthikhiraskar.samplesqlitedb.MyCustomListView (server)'
W/Binder  ( 1692): Caught a RuntimeException from the binder stub implementation.
W/Binder  ( 1692): java.lang.NullPointerException
W/Binder  ( 1692):  at android.inputmethodservice.IInputMethodWrapper.setSessionEnabled(IInputMethodWrapper.java:280)
W/Binder  ( 1692):  at com.android.internal.view.IInputMethod$Stub.onTransact(IInputMethod.java:129)
W/Binder  ( 1692):  at android.os.Binder.execTransact(Binder.java:404)
W/Binder  ( 1692):  at dalvik.system.NativeStart.run(Native Method)
W/SurfaceFlinger( 1162): couldn't log to binary event log: overflow.
I/WindowState( 1596): WIN DEATH: Window{ad54e4b0 u0 com.karthikhiraskar.samplesqlitedb/com.karthikhiraskar.samplesqlitedb.MyCustomListView}
W/InputMethodManagerService( 1596): Got RemoteException sending setActive(false) notification to pid 10785 uid 10060
W/PlatformStatsUtil( 2013): Could not retrieve Usage & Diagnostics setting. Giving up.

Solution

  • If you search any thing, you will use Textchange listener, We will use two list of data one for backup & other for refilling according to search.

     edit_text.addTextChangedListener(new TextWatcher() {
    
            @Override
            public void onTextChanged(CharSequence s, int start, int before, int count) {
                List<LocationSearchModel> textToCheckList=new ArrayList<>();
                String textToCheck=s.toString();
                if(s.length()!=0){
                    //code for making First letter of string CAPITAL
                    textToCheck = textToCheck.substring(0, 1).toUpperCase() + textToCheck.substring(1); 
    
                    //code for filling second list from backup list based on text to search here in this case, it is "textToCheck"
                    for (LocationSearchModel searchModel: locationSearchList) {
                        if(searchModel.getLocationName().startsWith(textToCheck)){
                            textToCheckList.add(searchModel);
                        }
                    }
                }else{
                    textToCheckList.addAll(locationSearchList) ;
                }
    
                // Setting new list to adapter and notifying it
                locationSearchAdapter.setLocationSearchList(textToCheckList);
                locationSearchAdapter.notifyDataSetChanged();
            }
    
        });
    

    In above case, "locationSearchList" is my backup list, to which i will use for filling my second list which is

     List<LocationSearchModel> textToCheckList=new ArrayList<>();
    

    in this case.

    I have mentioned the comments in above code, follow it and u will reach to solution.and please mark my solution use full if found really so.