Question

I'm rewriting from scratch my app since I want it to be more modern and intuitive. To do so, I'm using a NavigationDrawer layout with fragments.

Now I want that the user's click on one of NavigationDrawer's options starts another activity (not a fragment) which is a wallpaper picker.

My code works, but when the user does so the MainActivity crashes. Why?

Here is the MainActivity:

public class MainActivity extends Activity {

  private DrawerLayout mDrawerLayout;
  private ListView mDrawerList;
  private ActionBarDrawerToggle mDrawerToggle;

  private CharSequence mDrawerTitle;
  private CharSequence mTitle;
  CustomDrawerAdapter adapter;

  List<DrawerItem> dataList;

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

        // Initializing
        dataList = new ArrayList<DrawerItem>();
        mTitle = mDrawerTitle = getTitle();
        mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
        mDrawerList = (ListView) findViewById(R.id.left_drawer);

        mDrawerLayout.setDrawerShadow(R.drawable.drawer_shadow,
                    GravityCompat.START);

        // Add Drawer Item to dataList
        dataList.add(new DrawerItem("Launchers", R.drawable.ic_action_email));
        dataList.add(new DrawerItem("Extras", R.drawable.ic_action_good));
        dataList.add(new DrawerItem("Support", R.drawable.ic_action_gamepad));
        dataList.add(new DrawerItem("Contact", R.drawable.ic_action_labels));
        dataList.add(new DrawerItem("Wallpapers", R.drawable.ic_action_search));
        dataList.add(new DrawerItem("Import & Export",
                    R.drawable.ic_action_import_export));
        dataList.add(new DrawerItem("About", R.drawable.ic_action_about));
        dataList.add(new DrawerItem("Settings", R.drawable.ic_action_settings));
        dataList.add(new DrawerItem("Help", R.drawable.ic_action_help));

        adapter = new CustomDrawerAdapter(this, R.layout.custom_drawer_item,
                    dataList);

        mDrawerList.setAdapter(adapter);

        mDrawerList.setOnItemClickListener(new DrawerItemClickListener());

        getActionBar().setDisplayHomeAsUpEnabled(true);
        getActionBar().setHomeButtonEnabled(true);

        mDrawerToggle = new ActionBarDrawerToggle(this, mDrawerLayout,
                    R.drawable.ic_drawer, R.string.drawer_open,
                    R.string.drawer_close) {
              public void onDrawerClosed(View view) {
                    getActionBar().setTitle(mTitle);
                    invalidateOptionsMenu(); // creates call to
                                                              // onPrepareOptionsMenu()
              }

              public void onDrawerOpened(View drawerView) {
                    getActionBar().setTitle(mDrawerTitle);
                    invalidateOptionsMenu(); // creates call to
                                                              // onPrepareOptionsMenu()
              }
        };

        mDrawerLayout.setDrawerListener(mDrawerToggle);

        if (savedInstanceState == null) {
              SelectItem(0);
        }

  }

  @Override
  public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
  }

  public void goToWallpaper (View view) {
        Intent intent = new Intent(this, Wallpaper.class);
        startActivity(intent);
  }

  public void SelectItem(int position) {

        Fragment fragment = null;
        Bundle args = new Bundle();
        switch (position) {
        case 0:
              fragment = new FragmentOne();
              break;
        case 1:
              fragment = new FragmentTwo();
              break;
        case 2:
              fragment = new FragmentThree();
              break;
        case 3:
              fragment = new FragmentFour();
              break;
        case 4:
              startActivity(new Intent(this, Wallpaper.class));
              break;
        default:
              break;
        }

        fragment.setArguments(args);
        FragmentManager frgManager = getFragmentManager();
        frgManager.beginTransaction().replace(R.id.content_frame, fragment)
                    .commit();

        mDrawerList.setItemChecked(position, true);
        setTitle(dataList.get(position).getItemName());
        mDrawerLayout.closeDrawer(mDrawerList);

  }

  @Override
  public void setTitle(CharSequence title) {
        mTitle = title;
        getActionBar().setTitle(mTitle);
  }

  @Override
  protected void onPostCreate(Bundle savedInstanceState) {
        super.onPostCreate(savedInstanceState);
        // Sync the toggle state after onRestoreInstanceState has occurred.
        mDrawerToggle.syncState();
  }

  @Override
  public void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);
        // Pass any configuration change to the drawer toggles
        mDrawerToggle.onConfigurationChanged(newConfig);
  }

  @Override
  public boolean onOptionsItemSelected(MenuItem item) {
        // The action bar home/up action should open or close the drawer.
        // ActionBarDrawerToggle will take care of this.
        if (mDrawerToggle.onOptionsItemSelected(item)) {
              return true;
        }

        return false;
  }

    private class DrawerItemClickListener implements
              ListView.OnItemClickListener {
        @Override
        public void onItemClick(AdapterView<?> parent, View view, int position,
                    long id) {
              SelectItem(position);

        }
  }

}

and this is the Wallpaper activity:

public class Wallpaper extends SherlockActivity implements AdapterView.OnItemSelectedListener,
    OnClickListener {

private Gallery mGallery;
private ImageView mImageView;
private boolean mIsWallpaperSet;

private Bitmap mBitmap;

private ArrayList<Integer> mThumbs;
private ArrayList<Integer> mImages;
private WallpaperLoader mLoader;

@Override
public void onCreate(Bundle icicle) {
    super.onCreate(icicle);
    requestWindowFeature(Window.FEATURE_NO_TITLE);

    findWallpapers();

    setContentView(R.layout.wallpaper_chooser);

    mGallery = (Gallery) findViewById(R.id.gallery);
    mGallery.setAdapter(new ImageAdapter(this));
    mGallery.setOnItemSelectedListener(this);
    mGallery.setCallbackDuringFling(false);

    findViewById(R.id.set).setOnClickListener(this);

    mImageView = (ImageView) findViewById(R.id.wallpaper);
}

private void findWallpapers() {
    mThumbs = new ArrayList<Integer>(24);
    mImages = new ArrayList<Integer>(24);

    final Resources resources = getResources();
    final String packageName = getApplication().getPackageName();

    addWallpapers(resources, packageName, R.array.wallpapers);
    addWallpapers(resources, packageName, R.array.extra_wallpapers);
}

private void addWallpapers(Resources resources, String packageName, int list) {
    final String[] extras = resources.getStringArray(list);
    for (String extra : extras) {
        int res = resources.getIdentifier(extra, "drawable", packageName);
        if (res != 0) {
            final int thumbRes = resources.getIdentifier(extra + "_small",
                    "drawable", packageName);

            if (thumbRes != 0) {
                mThumbs.add(thumbRes);
                mImages.add(res);
            }
        }
    }
}

@Override
protected void onResume() {
    super.onResume();
    mIsWallpaperSet = false;
}

@Override
protected void onDestroy() {
    super.onDestroy();

    if (mLoader != null && mLoader.getStatus() != WallpaperLoader.Status.FINISHED) {
        mLoader.cancel(true);
        mLoader = null;
    }
}

@Override
public void onItemSelected(AdapterView<?> parent, View v, int position, long id) {
    if (mLoader != null && mLoader.getStatus() != WallpaperLoader.Status.FINISHED) {
        mLoader.cancel();
    }
    mLoader = (WallpaperLoader) new WallpaperLoader().execute(position);
}

private void selectWallpaper(int position) {
    if (mIsWallpaperSet) {
        return;
    }

    mIsWallpaperSet = true;
    try {
        InputStream stream = getResources().openRawResource(mImages.get(position));
        setWallpaper(stream);
        setResult(RESULT_OK);
        finish();
    } catch (IOException e) {
        Log.e("Template", "Failed to set wallpaper: " + e);
    }
}

@Override
public void onNothingSelected(AdapterView<?> parent) {
}

private class ImageAdapter extends BaseAdapter {
    private LayoutInflater mLayoutInflater;

    ImageAdapter(Wallpaper context) {
        mLayoutInflater = context.getLayoutInflater();
    }

    @Override
    public int getCount() {
        return mThumbs.size();
    }

    @Override
    public Object getItem(int position) {
        return position;
    }

    @Override
    public long getItemId(int position) {
        return position;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        ImageView image;

        if (convertView == null) {
            image = (ImageView) mLayoutInflater.inflate(R.layout.wallpaper_item, parent, false);
        } else {
            image = (ImageView) convertView;
        }

        int thumbRes = mThumbs.get(position);
        image.setImageResource(thumbRes);
        Drawable thumbDrawable = image.getDrawable();
        if (thumbDrawable != null) {
            thumbDrawable.setDither(true);
        } else {
            Log.e("Template", String.format(
                "Error decoding thumbnail resId=%d for wallpaper #%d",
                thumbRes, position));
        }
        return image;
    }
}

@Override
public void onClick(View v) {
    selectWallpaper(mGallery.getSelectedItemPosition());
}

class WallpaperLoader extends AsyncTask<Integer, Void, Bitmap> {
    BitmapFactory.Options mOptions;

    WallpaperLoader() {
        mOptions = new BitmapFactory.Options();
        mOptions.inDither = false;
        mOptions.inPreferredConfig = Bitmap.Config.ARGB_8888;            
    }

    @Override
    protected Bitmap doInBackground(Integer... params) {
        if (isCancelled()) return null;
        try {
            return BitmapFactory.decodeResource(getResources(),
                    mImages.get(params[0]), mOptions);
        } catch (OutOfMemoryError e) {
            return null;
        }            
    }

    @Override
    protected void onPostExecute(Bitmap b) {
        if (b == null) return;

        if (!isCancelled() && !mOptions.mCancel) {

            if (mBitmap != null) {
                mBitmap.recycle();
            }

            final ImageView view = mImageView;
            view.setImageBitmap(b);

            mBitmap = b;

            final Drawable drawable = view.getDrawable();
            drawable.setFilterBitmap(true);
            drawable.setDither(true);

            view.postInvalidate();

            mLoader = null;
        } else {
           b.recycle(); 
        }
    }

    void cancel() {
        mOptions.requestCancelDecode();
        super.cancel(true);
    }
}

}

And this is the logcat if it may help:

04-19 14:59:41.735: W/dalvikvm(11025): threadid=1: thread exiting with uncaught exception (group=0x41961da0) 04-19 14:59:41.735: E/AndroidRuntime(11025): FATAL EXCEPTION: main 04-19 14:59:41.735: E/AndroidRuntime(11025): Process: com.tutecentral.navigationdrawer, PID: 11025 04-19 14:59:41.735: E/AndroidRuntime(11025): java.lang.NullPointerException 04-19 14:59:41.735: E/AndroidRuntime(11025): at com.tutecentral.navigationdrawer.MainActivity.SelectItem(MainActivity.java:143) 04-19 14:59:41.735: E/AndroidRuntime(11025): at com.tutecentral.navigationdrawer.MainActivity$DrawerItemClickListener.onItemClick(MainActivity.java:190) 04-19 14:59:41.735: E/AndroidRuntime(11025): at android.widget.AdapterView.performItemClick(AdapterView.java:308) 04-19 14:59:41.735: E/AndroidRuntime(11025): at android.widget.AbsListView.performItemClick(AbsListView.java:1476) 04-19 14:59:41.735: E/AndroidRuntime(11025): at android.widget.AbsListView$PerformClick.run(AbsListView.java:3497) 04-19 14:59:41.735: E/AndroidRuntime(11025): at android.widget.AbsListView$3.run(AbsListView.java:4814) 04-19 14:59:41.735: E/AndroidRuntime(11025): at android.os.Handler.handleCallback(Handler.java:733) 04-19 14:59:41.735: E/AndroidRuntime(11025): at android.os.Handler.dispatchMessage(Handler.java:95) 04-19 14:59:41.735: E/AndroidRuntime(11025): at android.os.Looper.loop(Looper.java:157) 04-19 14:59:41.735: E/AndroidRuntime(11025): at android.app.ActivityThread.main(ActivityThread.java:5293) 04-19 14:59:41.735: E/AndroidRuntime(11025): at java.lang.reflect.Method.invokeNative(Native Method) 04-19 14:59:41.735: E/AndroidRuntime(11025): at java.lang.reflect.Method.invoke(Method.java:515) 04-19 14:59:41.735: E/AndroidRuntime(11025): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1265) 04-19 14:59:41.735: E/AndroidRuntime(11025): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1081) 04-19 14:59:41.735: E/AndroidRuntime(11025): at dalvik.system.NativeStart.main(Native Method)

Thanks a million!

Was it helpful?

Solution

As the logcat points out the problem is in your SelectItem method.

At the top you define the fragment as null:

Fragment fragment = null;

But after the switch you try to do this:

fragment.setArguments(args);  // If the fragment is null, an Exception will occur

I assume your reasoning behind this was that you call

case 4:
   startActivity(new Intent(this, Wallpaper.class));
   break;

here and that this would end the Activity and it would never reach anything below the switch, but that is false. Even if you start a new Activity the old one exists and even after a call to startActivity the old Activity still finishes the method and continues with it's normal lifecycle. So what you have to do is this:

if(fragment != null) {
    fragment.setArguments(args);
    FragmentManager frgManager = getFragmentManager();
    frgManager.beginTransaction().replace(R.id.content_frame, fragment)
                .commit();
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top