空指针异常 - BaseAdapter notifyDataSetChanged

Null Pointer Exception - BaseAdapter notifyDataSetChanged

我正在尝试实施 Filterable ListView 但得到 NPE:

08-13 11:34:20.980: E/AndroidRuntime(31796): FATAL EXCEPTION: main
08-13 11:34:20.980: E/AndroidRuntime(31796): java.lang.NullPointerException
08-13 11:34:20.980: E/AndroidRuntime(31796):    at com.wingnity.jsonparsingtutorial.ActorsActivity$ActorAdapter.getCount(ActorsActivity.java:252)
08-13 11:34:20.980: E/AndroidRuntime(31796):    at android.widget.AdapterView$AdapterDataSetObserver.onChanged(AdapterView.java:804)
08-13 11:34:20.980: E/AndroidRuntime(31796):    at android.widget.AbsListView$AdapterDataSetObserver.onChanged(AbsListView.java:6545)
08-13 11:34:20.980: E/AndroidRuntime(31796):    at android.database.DataSetObservable.notifyChanged(DataSetObservable.java:37)
08-13 11:34:20.980: E/AndroidRuntime(31796):    at android.widget.BaseAdapter.notifyDataSetChanged(BaseAdapter.java:50)
08-13 11:34:20.980: E/AndroidRuntime(31796):    at com.wingnity.jsonparsingtutorial.ActorsActivity$ActorAdapter$ItemFilter.publishResults(ActorsActivity.java:237)
08-13 11:34:20.980: E/AndroidRuntime(31796):    at android.widget.Filter$ResultsHandler.handleMessage(Filter.java:282)
08-13 11:34:20.980: E/AndroidRuntime(31796):    at android.os.Handler.dispatchMessage(Handler.java:99)
08-13 11:34:20.980: E/AndroidRuntime(31796):    at android.os.Looper.loop(Looper.java:137)
08-13 11:34:20.980: E/AndroidRuntime(31796):    at android.app.ActivityThread.main(ActivityThread.java:4921)
08-13 11:34:20.980: E/AndroidRuntime(31796):    at java.lang.reflect.Method.invokeNative(Native Method)
08-13 11:34:20.980: E/AndroidRuntime(31796):    at java.lang.reflect.Method.invoke(Method.java:511)
08-13 11:34:20.980: E/AndroidRuntime(31796):    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1036)
08-13 11:34:20.980: E/AndroidRuntime(31796):    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:803)
08-13 11:34:20.980: E/AndroidRuntime(31796):    at dalvik.system.NativeStart.main(Native Method)

这是我面临的问题:

 @Override
 protected void publishResults(CharSequence constraint,
       FilterResults results) {
       actorsList  = (ArrayList<Actors>) results.values; // Type safety: Unchecked cast from Object to ArrayList<Actors>
       notifyDataSetChanged();
 }

我正在向 ListView 中获取数据,但在向 EditText 中输入文本时遇到此错误...

Activity代码:

public class ActorsActivity extends Activity {

ArrayList<Actors> actorsList;   
ActorAdapter adapter;
ListView listView;
EditText editSearch;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    editSearch = (EditText) findViewById(R.id.editSearch);
    listView = (ListView)findViewById(R.id.list);

    actorsList = new ArrayList<Actors>();

    new JSONAsyncTask().execute("http://microblogging.wingnity.com/JSONParsingTutorial/jsonActors");

    listView.setOnItemClickListener(new OnItemClickListener() {

        @Override
        public void onItemClick(AdapterView<?> arg0, View arg1, int position,
                long id) {
            // TODO Auto-generated method stub
            Toast.makeText(getApplicationContext(), actorsList.get(position).getName(), Toast.LENGTH_LONG).show();              
        }
    });

    editSearch.addTextChangedListener(new TextWatcher() {

        @Override
        public void onTextChanged(CharSequence s, int start, int before, int count) {
            // TODO Auto-generated method stub
            adapter.getFilter().filter(s);
        }

        @Override
        public void beforeTextChanged(CharSequence s, int start, int count,
                int after) {
            // TODO Auto-generated method stub

        }

        @Override
        public void afterTextChanged(Editable s) {
            // TODO Auto-generated method stub

        }
    });
}


class JSONAsyncTask extends AsyncTask<String, Void, Boolean> {

    ProgressDialog dialog;

    @Override
    protected void onPreExecute() {
        super.onPreExecute();
        dialog = new ProgressDialog(ActorsActivity.this);
        dialog.setMessage("Loading, please wait");
        dialog.setTitle("Connecting server");
        dialog.show();
        dialog.setCancelable(false);
    }

    @Override
    protected Boolean doInBackground(String... urls) {
        try {

            //------------------>>
            HttpGet httppost = new HttpGet(urls[0]);
            HttpClient httpclient = new DefaultHttpClient();
            HttpResponse response = httpclient.execute(httppost);

            // StatusLine stat = response.getStatusLine();
            int status = response.getStatusLine().getStatusCode();

            if (status == 200) {
                HttpEntity entity = response.getEntity();
                String data = EntityUtils.toString(entity);


                JSONObject jsono = new JSONObject(data);
                JSONArray jarray = jsono.getJSONArray("actors");

                for (int i = 0; i < jarray.length(); i++) {
                    JSONObject object = jarray.getJSONObject(i);

                    Actors actor = new Actors();

                    actor.setName(object.getString("name"));
                    actor.setCountry(object.getString("country"));

                    actorsList.add(actor);
                }
                return true;
            }

            //------------------>>

        } catch (ParseException e1) {
            e1.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (JSONException e) {
            e.printStackTrace();
        }
        return false;
    }

    protected void onPostExecute(Boolean result) {

        dialog.cancel();

        adapter = new ActorAdapter(getApplicationContext(), R.layout.row, actorsList);          
        listView.setAdapter(adapter);

        adapter.notifyDataSetChanged();

        if(result == false)
            Toast.makeText(getApplicationContext(), "Unable to fetch data from server", Toast.LENGTH_LONG).show();

    }
}


public class ActorAdapter extends BaseAdapter {
    LayoutInflater inflater;
    int Resource;
    ViewHolder holder;
    private ItemFilter itemFilter;
    ArrayList<Actors> filteredItems;

    public ActorAdapter(Context context, int resource, ArrayList<Actors> arrayList) {
        inflater = (LayoutInflater) context
                .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        Resource = resource;
        actorsList = arrayList;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        View view = convertView;            
        if (view == null) {             
            holder = new ViewHolder();                          
            view = inflater.inflate(Resource, null);

            holder.tvName = (TextView) view.findViewById(R.id.tvName);
            holder.tvCountry = (TextView) view.findViewById(R.id.tvCountry);

            view.setTag(holder);

        } else {

            holder = (ViewHolder) view.getTag();
        }

        holder.tvName.setText(actorsList.get(position).getName());
        holder.tvCountry.setText(actorsList.get(position).getCountry());

        return view;
    }

    class ViewHolder {
        public TextView tvName;
        public TextView tvCountry;      
    }

    private class ItemFilter extends Filter {
        @Override
        protected FilterResults performFiltering(CharSequence constraint) {
            FilterResults results = new FilterResults();

            if (constraint != null && constraint.length() > 0) {
                ArrayList<Actors> filterList = new ArrayList<Actors>();
                for (int i = 0; i < filteredItems.size(); i++) {

                    Actors actors = filteredItems.get(i);
                    String name = actors.getName().toUpperCase();
                    String country = actors.getCountry().toUpperCase();
                    if (name.contains(constraint.toString().toUpperCase()) || country.contains(constraint.toString().toUpperCase())) {

                        filterList.add(actors);
                    }
                }
                results.count = filterList.size();
                results.values = filterList;
            } else {
                results.count = filteredItems.size();
                results.values = filteredItems;
            }
            return results;

        }

        @Override
        protected void publishResults(CharSequence constraint,
                FilterResults results) {
            actorsList  = (ArrayList<Actors>) results.values; // Type safety: Unchecked cast from Object to ArrayList<Actors>
            notifyDataSetChanged();
        }

    }

 public Filter getFilter() {
     if (itemFilter == null) {
         itemFilter = new ItemFilter();
     }
     return itemFilter;
 }

    @Override
    public int getCount() {
        // TODO Auto-generated method stub
        return actorsList.size();
    }


    @Override
    public Object getItem(int position) {
        // TODO Auto-generated method stub
        return actorsList.get(position);
    }


    @Override
    public long getItemId(int position) {
        // TODO Auto-generated method stub
        return position;
    }
  }

}

那么我该如何解决这个问题?我不明白我为什么会遇到这个问题。

异常是因为您试图从适配器内部更改显示值的列表。构建视图时,适配器找不到要通知的某些值并导致 NullPointerException。尝试在适配器外过滤您的列表。您可以以面向对象的方式在他自己的 class 中独立于适配器实现过滤器。因此,在文本侦听器中,您可以在单独的步骤中执行过滤器,第二步应该是将值分配给您的 actorList,第三步是通知适配器。应该是这样的

editSearch.addTextChangedListener(new TextWatcher() {

    @Override
    public void onTextChanged(CharSequence s, int start, int before, int count) {

        //change the values, DO NOT create new because the reference will change
        actorsList = myFilter.filter(s); //assign the filtered values, myFilter could be static function also
        adapter.notifyDataSetChanged();
    }

    @Override
    public void beforeTextChanged(CharSequence s, int start, int count,
            int after) {
        // TODO Auto-generated method stub

    }

    @Override
    public void afterTextChanged(Editable s) {
        // TODO Auto-generated method stub

    }
});

你还没有初始化 filteredItems 这就是你在 publishResults() 函数中得到 NPE 的原因。您必须先在构造函数中初始化

public ActorAdapter(Context context, int resource, ArrayList<Actors> arrayList) {
    // your code
    actorsList = arrayList;
    filteredItems=arrayList; //initially show all items 
} 

现在您必须在所有其他功能(如 getCount(), getView()...等)中使用 filteredItems 代替 actorsList,以便您的列表视图仅显示过滤后的项目并在 performFiltering() 改变

for (int i = 0; i < filteredItems.size(); i++) 

for (int i = 0; i < actorsList .size(); i++) 

同时删除 adapter.notifyDataSetChanged();,因为在将 Arraylist 分配给适配器后您没有对其进行任何更改。