简体   繁体   中英

Android ArrayAdapter causes NullPointerException when used in ViewPager

I've serched everywhere but I haven't solved my problem yet.

I'm using a ViewPager inside an Activity. The ViewPager contains 3 fragments: one is a plain fragment, the second Fragment contains a custom ListView and the third is a MapFragment (SupportMapFragment).

I'm using only support fragments.

The problem is that the getItem() method of the ViewPager adapter (FragmentPagerAdapter) is called after the activity tries to populate the fragments setting the adapter and the markers on the map.

So, I'm triyng to initialize the fragment before initializing the ViewPager, using a singleton pattern for the fragments:

In the Activity onCreate():

setContentView(R.layout.act_discover_small);
profiloFragment = new ProfiloFragment();
mapFragment = new MappaMonumentiFragment();
elencoFragment = new ElencoMonumentiFragment();
initViewPager();

The initViewPager() method is:

private void initViewPager() {
    mPagerAdapter = new PagerAdapter(getSupportFragmentManager());
    mViewPager = (SmartViewPager) findViewById(R.id.pager);
    mViewPager.setAdapter(mPagerAdapter);
    mViewPager.setOffscreenPageLimit(3);
    mViewPager.setOnPageChangeListener(new OnPageChangeListener() {
        @Override
        public void onPageScrolled(int arg0, float arg1, int arg2) {
            if (!beginSwipe)
                elencoFragment.List.finishRefresh();
            beginSwipe = true;
        }

        @Override
        public void onPageScrollStateChanged(int arg0) {

        }

        @Override
        public void onPageSelected(int arg0) {
            beginSwipe = false;
            lockDrawer(arg0);
            if (arg0 == 0) {
                swipe_left_button.setText("show map");
            } else {
                swipe_left_button.setText("show list");
            }
        }
    });
}

This is the ViewPager adapter

class PagerAdapter extends FragmentPagerAdapter {
    public PagerAdapter(FragmentManager fm) {
        super(fm);
    }

    @Override
    public int getCount() {
        return 3;
    }

    @Override
    public Fragment getItem(int i) {
        Log.i(TAG, "getItem viewpager n." + i);
        switch (i) {
        case 0:
            if (profiloFragment == null)
                profiloFragment = new ProfiloFragment();
            return profiloFragment;
        case 1:
            if (elencoFragment == null)
                elencoFragment = new ElencoMonumentiFragment();
            return elencoFragment;
        case 2:
            if (mapFragment == null)
                mapFragment = new MappaMonumentiFragment();
            return mapFragment;
        }
        return null;
    }
}

I get a NullPointerException when triyng to fill the ArrayAdapter of the second fragment with the elements in this method (executed in the onPostExecute() of an AsyncTask):

    public void populateElencoMonumenti(List<SmartPlace> placesList) {
    if (placesList != null) {
        places = (ArrayList<SmartPlace>) placesList;
        //before: adapter.clear(); //NullPointerException at this line
                    //after:
                    if (adapter == null) {
            adapter = new ElencoMonumentiAdapter(ctx, act, app);
        }


        adapter.addAll(places);
        List.setAdapter(adapter);

    } else {
        adapter.clear();
        List.setAdapter(adapter);
    }
}

If I log (adapter == null) before calling adapter.clear() it return true, so it's null.

if I try to check if it's null and reinitialize it I get a NPE in the constructor of the adapter:

   public ElencoMonumentiAdapter(Context ctx, Discover homAct, SmartApplication app) {
    // super(ctx, R.layout.list_row_monument);
    super(ctx, R.layout.list_row_monument, new ArrayList<SmartPlace>()); //NPE here
    Log.e(TAG, "null ctx? " + (ctx == null));
    this.app = app;
    this.ctx = ctx;
}

the stacktrace is:

12-18 11:13:07.285: E/AndroidRuntime(20865): FATAL EXCEPTION: main
12-18 11:13:07.285: E/AndroidRuntime(20865): Process: com.Thinple.MiWalks.ui, PID: 20865
12-18 11:13:07.285: E/AndroidRuntime(20865): java.lang.NullPointerException
12-18 11:13:07.285: E/AndroidRuntime(20865):    at android.widget.ArrayAdapter.init(ArrayAdapter.java:310)
12-18 11:13:07.285: E/AndroidRuntime(20865):    at android.widget.ArrayAdapter.<init>(ArrayAdapter.java:153)
12-18 11:13:07.285: E/AndroidRuntime(20865):    at com.Thinple.MiWalks.ui.adapters.ElencoMonumentiAdapter.<init>(ElencoMonumentiAdapter.java:41)
12-18 11:13:07.285: E/AndroidRuntime(20865):    at com.Thinple.MiWalks.ui.fragments.ElencoMonumentiFragment.populateElencoMonumenti(ElencoMonumentiFragment.java:129)
12-18 11:13:07.285: E/AndroidRuntime(20865):    at com.Thinple.MiWalks.ui.Discover.notifyFragments(Discover.java:328)
12-18 11:13:07.285: E/AndroidRuntime(20865):    at com.Thinple.MiWalks.ui.Discover.populatePlaces(Discover.java:509)
12-18 11:13:07.285: E/AndroidRuntime(20865):    at com.Thinple.MiWalks.threading.tasks.GetPlacesFromDBtask.onPostExecute(GetPlacesFromDBtask.java:53)
12-18 11:13:07.285: E/AndroidRuntime(20865):    at com.Thinple.MiWalks.threading.tasks.GetPlacesFromDBtask.onPostExecute(GetPlacesFromDBtask.java:1)
12-18 11:13:07.285: E/AndroidRuntime(20865):    at android.os.AsyncTask.finish(AsyncTask.java:632)
12-18 11:13:07.285: E/AndroidRuntime(20865):    at android.os.AsyncTask.access$600(AsyncTask.java:177)
12-18 11:13:07.285: E/AndroidRuntime(20865):    at android.os.AsyncTask$InternalHandler.handleMessage(AsyncTask.java:645)
12-18 11:13:07.285: E/AndroidRuntime(20865):    at android.os.Handler.dispatchMessage(Handler.java:102)
12-18 11:13:07.285: E/AndroidRuntime(20865):    at android.os.Looper.loop(Looper.java:136)
12-18 11:13:07.285: E/AndroidRuntime(20865):    at android.app.ActivityThread.main(ActivityThread.java:5017)
12-18 11:13:07.285: E/AndroidRuntime(20865):    at java.lang.reflect.Method.invokeNative(Native Method)
12-18 11:13:07.285: E/AndroidRuntime(20865):    at java.lang.reflect.Method.invoke(Method.java:515)
12-18 11:13:07.285: E/AndroidRuntime(20865):    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:779)
12-18 11:13:07.285: E/AndroidRuntime(20865):    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:595)
12-18 11:13:07.285: E/AndroidRuntime(20865):    at dalvik.system.NativeStart.main(Native Method)

I really don't find a solution.

Thanks in advance for the replies.

Change

super(ctx, R.layout.list_row_monument, new ArrayList<SmartPlace>());

new ArrayList<SmartPlace>() is new arraylsit but its empty not populated with any data

to

super(ctx, R.layout.list_row_monument, list);

list is probably ArrayList<SmartPlace>() which is passed to the constructor of adapter class

Look at the public constructors

http://developer.android.com/reference/android/widget/ArrayAdapter.html

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