timothyjc
timothyjc

Reputation: 2228

NullPointerException on dynamic AutoCompleteTextView

Some users are reporting this error:

java.lang.NullPointerException
at android.widget.ArrayAdapter.getCount(ArrayAdapter.java:291)
at android.widget.AutoCompleteTextView$PopupDataSetObserver$1.run(AutoCompleteTextView.java:1670)
at android.os.Handler.handleCallback(Handler.java:587)
at android.os.Handler.dispatchMessage(Handler.java:92)
at android.os.Looper.loop(Looper.java:123)
at android.app.ActivityThread.main(ActivityThread.java:3687)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:507)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:842)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:600)
at dalvik.system.NativeStart.main(Native Method)

Here is my code snippet:

    private List<City> autoCompleteCities = new ArrayList<City>();
    private List<City> autoCompleteCitiesOld = new ArrayList<City>();
    private ArrayAdapter<String> autoCompleteAdapter;
    private AutoCompleteTextView cityView;

    ...

    autoCompleteAdapter = new ArrayAdapter<String>(this, android.R.layout.simple_dropdown_item_1line);
    autoCompleteAdapter.setNotifyOnChange(true);

    cityView = (AutoCompleteTextView) findViewById(R.id.city);      

    cityView.setAdapter(autoCompleteAdapter);
    cityView.addTextChangedListener(new TextWatcher() {

        @Override
        public void onTextChanged(CharSequence s, int start, int before, int count) {
            LogUtil.i("!!!!!!!!!!!!! ontextchanged", s.toString());
            autoCompleteAdapter.clear();
            autoCompleteCitiesOld = autoCompleteCities;
            if (s.toString().length() > 2) {
                autoCompleteCities = search(s.toString());
                for (City city : autoCompleteCities) {
                    autoCompleteAdapter.add(city.getDisplayName());
                }
            }
        }

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

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

It doesnt happen for me, but I have enough error reports to know it happens for several users. Any idea what is wrong? Why does this happen to only a handful of users?

I found this post but putting the fetching of new autocomplete values in an AsyncTask meant that the results always were one character behind what the user had entered.

Upvotes: 3

Views: 2191

Answers (5)

Bevor
Bevor

Reputation: 8605

I had exactly the same problem with the same issue. In my case I have thousands of streets I dynamically add and remove from the list. In my case it was always reproducable when I enter some value into the AutoComplete field, let's say 3 characters (while threshold is set to 0), so the dropdown list appears, and then I delete those characters by delete button very quickly. That means I hit the delete button a lot of times. It always crashes then. I figured out that clear causes the crashes. I put the clear in beforeTextChanged and the crashes were gone:

public class StreetTextWatcher implements TextWatcher {

    private final StreetArrayAdapter adapter;
    private boolean alreadyAdded = false;

    public StreetTextWatcher(StreetArrayAdapter adapter) {
        this.adapter = adapter;
    }

    @Override
    public void afterTextChanged(Editable s) {
        //not used
    }

    @Override
    public void beforeTextChanged(CharSequence s, int start, int count, int after) {
        if (s.length() < 1)  {
            adapter.clear();

            alreadyAdded = false;
        }
    }

    @Override
    public void onTextChanged(CharSequence s, int start, int before, int count) {           
        if (s.length() == 1) {
            if (s.toString().toLowerCase(Locale.GERMAN).startsWith("a") && !alreadyAdded)  {
                adapter.addAll(StreetNames.STREETS_A);
                alreadyAdded = true;
            }

            if (s.toString().toLowerCase(Locale.GERMAN).startsWith("b") && !alreadyAdded)  {
                adapter.addAll(StreetNames.STREETS_B);
                alreadyAdded = true;
            }

            //more streets...
        }
    }
}

StreetArrayAdapter:

public class StreetArrayAdapter extends ArrayAdapter<String> {

    public StreetArrayAdapter(Context context, int textViewResourceId) {
        super(context, textViewResourceId);
    }

    public void addAll(String[] streets) {
        for (String street : streets) {
            add(street);
        }
    }
}

Upvotes: 0

Jitendra
Jitendra

Reputation: 1117

Better do null check before using object like below and do it in search function also..

 if (s.toString().length() > 2) {
     autoCompleteCities = search(s.toString());
     if(autoCompeleteCities!=null){     
         for (City city : autoCompleteCities) {
              autoCompleteAdapter.add(city.getDisplayName());
         }
       }

Upvotes: 0

GOLDEE
GOLDEE

Reputation: 2318

Where did u have added the array of String ,the reason of error may be the empty array list as: autoCompleteAdapter = new ArrayAdapter(this, android.R.layout.simple_dropdown_item_1line);

here u hav'nt assign any string array

And enter your full code it will help lot to the people to understand the problem

Upvotes: 0

agamov
agamov

Reputation: 4427

My hypothesis is that you are somewhere using static variables which are nulled after activity recreation. See my answer here: Public static variables and Android activity life cycle management

create android v.4 emulator, go to developer's settings, disable background tasks, disable multiple activities and then try to use your application - chances are it will fail.

Upvotes: 0

knvarma
knvarma

Reputation: 974

Where are you passing the ArrayList to the ArrayAdapter. The NullPointerException throws while counting the list lenght in ArrayAdapter. But the list is not passed to Adapter, so the list object in default Adapter contains null.

Upvotes: 1

Related Questions