简体   繁体   中英

ListView throwing NullPointerException while scrolling

Despite the title of this question, its content is quite different.

In my Activity I want to represent data both with a GridView and a ListView . I created two Button s that when clicked hide one of the View s and shows the other:

//onClick
//switch(view.getId())
case R.id.itemselect_button_grid:
    if (lv.getVisibility() == View.VISIBLE) {
        lv.invalidate();
        lv.setVisibility(View.GONE);
        gv.setVisibility(View.VISIBLE);
        mAdapter.setIsListView(false);
        mAdapter.notifyDataSetChanged();
        gv.setAdapter(mAdapter);
    }
    break;
case R.id.itemselect_button_list:
    if (gv.getVisibility() == View.VISIBLE) {
        gv.invalidate();
        gv.setVisibility(View.GONE);
        lv.setVisibility(View.VISIBLE);
        mAdapter.setIsListView(true);
        mAdapter.notifyDataSetChanged();
        lv.setAdapter(mAdapter);
    }
    break;

I am using the same Adapter to handle the items. I set a boolean flag (setIsListview) that basically represents data in two different ways according to the parent View .

public View getView(final int position, View v, ViewGroup parent) {
    if (v == null) {
        LayoutInflater inflater = ((Activity) mContext).getLayoutInflater();
        if (!isListView)
            v = inflater.inflate(layId, parent, false);
        else
            v = inflater.inflate(R.layout.item_list_layout, parent,
                    false);
    }
    Item entry = Entries.getItems().get(position);
    if (!isListView) {
        NetworkImageView image = (NetworkImageView) v
                .findViewById(R.id.item_cover);
        //Line 70 is the following, image is null.
        image.setImageDrawable(mContext.getResources().getDrawable(
                Items.notFoundDrawables.get(categoryItem)));
        image.measure(
                MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED),
                MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
        image.setScaleType(ScaleType.FIT_XY);
        image.getLayoutParams().width = image.getMeasuredWidth();
        image.getLayoutParams().height = image.getMeasuredHeight();
        image.setDefaultImageResId(GamesomePlatforms.notFoundDrawables.get(platform));
        image.setErrorImageResId(GamesomePlatforms.notFoundDrawables.get(platform));
        if (null != entry.getCoverURL()) {
            image.setImageUrl(entry.getCoverURL(), mImageLoader);
        }
    }
    TextView itemTitle = (TextView) v.findViewById(R.id.item_title);
    itemTitle.setText(entry.getTitle());
    return v;
}

logcat error:

02-21 11:01:12.216: E/AndroidRuntime(7587): FATAL EXCEPTION: main
02-21 11:01:12.216: E/AndroidRuntime(7587): Process: com.vektor.gamesome, PID: 7587
02-21 11:01:12.216: E/AndroidRuntime(7587): java.lang.NullPointerException
02-21 11:01:12.216: E/AndroidRuntime(7587):     at com.vektor.myapp.domain.adapters.MyListAdapter.getView(MyListAdapter.java:70)
02-21 11:01:12.216: E/AndroidRuntime(7587):     at android.widget.AbsListView.obtainView(AbsListView.java:2240)
02-21 11:01:12.216: E/AndroidRuntime(7587):     at android.widget.ListView.makeAndAddView(ListView.java:1790)
02-21 11:01:12.216: E/AndroidRuntime(7587):     at android.widget.ListView.fillSpecific(ListView.java:1337)
02-21 11:01:12.216: E/AndroidRuntime(7587):     at android.widget.ListView.layoutChildren(ListView.java:1608)
02-21 11:01:12.216: E/AndroidRuntime(7587):     at android.widget.AbsListView$FlingRunnable.run(AbsListView.java:4202)
02-21 11:01:12.216: E/AndroidRuntime(7587):     at android.view.Choreographer$CallbackRecord.run(Choreographer.java:761)
02-21 11:01:12.216: E/AndroidRuntime(7587):     at android.view.Choreographer.doCallbacks(Choreographer.java:574)
02-21 11:01:12.216: E/AndroidRuntime(7587):     at android.view.Choreographer.doFrame(Choreographer.java:543)
02-21 11:01:12.216: E/AndroidRuntime(7587):     at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:747)
02-21 11:01:12.216: E/AndroidRuntime(7587):     at android.os.Handler.handleCallback(Handler.java:733)
02-21 11:01:12.216: E/AndroidRuntime(7587):     at android.os.Handler.dispatchMessage(Handler.java:95)
02-21 11:01:12.216: E/AndroidRuntime(7587):     at android.os.Looper.loop(Looper.java:136)
02-21 11:01:12.216: E/AndroidRuntime(7587):     at android.app.ActivityThread.main(ActivityThread.java:5081)
02-21 11:01:12.216: E/AndroidRuntime(7587):     at java.lang.reflect.Method.invokeNative(Native Method)
02-21 11:01:12.216: E/AndroidRuntime(7587):     at java.lang.reflect.Method.invoke(Method.java:515)
02-21 11:01:12.216: E/AndroidRuntime(7587):     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:781)
02-21 11:01:12.216: E/AndroidRuntime(7587):     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:597)
02-21 11:01:12.216: E/AndroidRuntime(7587):     at dalvik.system.NativeStart.main(Native Method)

When I am scrolling the GridView and click to convert it to ListView , nothing happens, but if I am scrolling the ListView and click to convert it to GridView , the app throws a NullPointerException saying that the image is null. Why does this happen if I've already invalidated the ListView and made it invisible?

I found a solution.

In each of the onClick cases, I added a line to set the Adapter of the old View to null. This interrupts pending operations on the old View .

case R.id.items_button_grid:
    if (lv.getVisibility() == View.VISIBLE) {
        lv.invalidate();
        lv.setAdapter(null);
        lv.setVisibility(View.GONE);
        mAdapter.setIsListView(false);
        mAdapter.notifyDataSetChanged();
        gv.setVisibility(View.VISIBLE);
        gv.setAdapter(mAdapter);
    }
    break;
case R.id.items_button_list:
    if (gv.getVisibility() == View.VISIBLE) {
        gv.invalidate();
        gv.setAdapter(null);
        gv.setVisibility(View.GONE);
        mAdapter.setIsListView(true);
        mAdapter.notifyDataSetChanged();
        lv.setVisibility(View.VISIBLE);
        lv.setAdapter(mAdapter);
    }
    break;

A good decoupled and simple solution is to reuse your data inside adapter and not the adapter itself. Make 2 adapters for GridView and ListView but re-use the same DataSource for both the adapters. This way you can in future change the UI of any view without changing anything with other view.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM