自定义导航抽屉不显示片段

Custom Navigation Drawer doesn't show Fragment

我正在尝试在我的应用程序中创建收藏夹列表,为此我使用了本教程:

http://androidopentutorials.com/android-sharedpreferences-tutorial-and-example/

但为了获得收藏夹,我使用了 NavigationDrawer 而不是 ActionBar。

问题是当我选择“收藏夹”或“抽屉中的主页”时没有任何反应。

Logcat 只显示一个与我的问题无关的错误。

我哪里搞错了?

错误:

06-30 17:41:48.530    6971-6971/? E/AndroidRuntime﹕ FATAL EXCEPTION: main
    Process: com.boom.kayakapp, PID: 6971
    java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.Object android.widget.ImageView.getTag()' on a null object reference
            at com.boom.kayakapp.activities.MainActivity.onItemLongClick(MainActivity.java:148)
            at android.widget.AbsListView.showContextMenuForChild(AbsListView.java:3162)
            at android.view.ViewGroup.showContextMenuForChild(ViewGroup.java:693)
            at android.view.ViewGroup.showContextMenuForChild(ViewGroup.java:693)
            at android.view.View.showContextMenu(View.java:4853)
            at android.view.View.performLongClick(View.java:4822)
            at android.widget.TextView.performLongClick(TextView.java:8684)
            at android.view.View$CheckForLongPress.run(View.java:19840)
            at android.os.Handler.handleCallback(Handler.java:739)
            at android.os.Handler.dispatchMessage(Handler.java:95)
            at android.os.Looper.loop(Looper.java:135)
            at android.app.ActivityThread.main(ActivityThread.java:5257)
            at java.lang.reflect.Method.invoke(Native Method)
            at java.lang.reflect.Method.invoke(Method.java:372)
            at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:903)
            at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:698)
    --------- beginning of system
06-30 17:41:48.572      933-933/? E/EGL_emulation﹕ tid 933: eglCreateSyncKHR(1237): error 0x3004 (EGL_BAD_ATTRIBUTE)
06-30 17:41:50.823    1232-1274/system_process E/InputDispatcher﹕ channel '10153f49 com.boom.kayakapp/com.boom.kayakapp.activities.MainActivity (server)' ~ Channel is unrecoverably broken and will be disposed!
06-30 17:42:02.006    7546-7546/? E/memtrack﹕ Couldn't load memtrack module (No such file or directory)
06-30 17:42:02.006    7546-7546/? E/android.os.Debug﹕ failed to load memtrack module: -2
06-30 17:42:02.041    7546-7555/? E/art﹕ Thread attaching while runtime is shutting down: Binder_1
06-30 17:42:02.402    7560-7560/? E/memtrack﹕ Couldn't load memtrack module (No such file or directory)
06-30 17:42:02.402    7560-7560/? E/android.os.Debug﹕ failed to load memtrack module: -2
06-30 17:42:02.460    7560-7570/? E/art﹕ Thread attaching while runtime is shutting down: Binder_1

主要Activity:

import android.app.ProgressDialog;
import android.content.Intent;
import android.content.res.Configuration;
import android.content.res.TypedArray;
import android.graphics.Color;
import android.graphics.drawable.ColorDrawable;
import android.os.Bundle;
import android.os.StrictMode;
import android.support.v4.app.ActionBarDrawerToggle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentTransaction;
import android.support.v4.widget.DrawerLayout;
import android.support.v7.app.ActionBarActivity;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;

import com.android.volley.Response;
import com.android.volley.VolleyError;
import com.android.volley.VolleyLog;
import com.android.volley.toolbox.JsonArrayRequest;
import com.boom.kayakapp.R;
import com.boom.kayakapp.adapters.AirlinesAdapter;
import com.boom.kayakapp.adapters.NavDrawerListAdapter;
import com.boom.kayakapp.controllers.AppController;
import com.boom.kayakapp.fragment.AirlinesFragment;
import com.boom.kayakapp.fragment.FavoriteFragment;
import com.boom.kayakapp.fragment.HomeFragment;
import com.boom.kayakapp.model.Airlines;
import com.boom.kayakapp.model.NavDrawerItem;
import com.boom.kayakapp.util.SharedPreference;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import java.util.ArrayList;
import java.util.List;

public class MainActivity extends ActionBarActivity {

        private Fragment contentFragment;
        AirlinesFragment airlinesFragment;
        FavoriteFragment favoriteFragment;

        // JSON Node names
        public static final String TAG_NAME = "name";
        public static final String TAG_PHONE = "phone";
        public static final String TAG_SITE = "site";
        public static final String TAG_LOGO = "logoURL";
        public static final String TAG_CODE = "code";

        // Log tag
        private static final String TAG = MainActivity.class.getSimpleName();

        // Airlines json url
        private static final String url = "https://www.kayak.com/h/mobileapis/directory/airlines";

        public ProgressDialog pDialog;
        public List<Airlines> airlinesList = new ArrayList<Airlines>();
        public ListView listView;
        public AirlinesAdapter adapterAirlines;

        SharedPreference sharedPreference;

    // DrawerLayout

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

    // nav drawer title
    private CharSequence mDrawerTitle;

    // used to store app title
    private CharSequence mTitle;

    // slide menu items
    private String[] navMenuTitles;
    private TypedArray navMenuIcons;

    private ArrayList<NavDrawerItem> navDrawerItems;
    private NavDrawerListAdapter adapterDrawer;

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

//            SharedPrefs
            sharedPreference = new SharedPreference();

            StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
            StrictMode.setThreadPolicy(policy);

//            Json Array
            listView = (ListView) findViewById(R.id.list);
            adapterAirlines = new AirlinesAdapter(this, airlinesList);
            listView.setAdapter(adapterAirlines);

            pDialog = new ProgressDialog(this);

            // Showing progress dialog before making http request
            pDialog.setMessage("Loading...");
            pDialog.show();

            // Listview OnItemClickListener
            listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {

                @Override
                public void onItemClick(AdapterView<?> parent, View view,
                                        int position, long id) {
                    // getting values from selected ListItem
                    String name = ((TextView) view.findViewById(R.id.name))
                            .getText().toString();
                    String phone = ((TextView) view.findViewById(R.id.phone))
                            .getText().toString();
                    String site = ((TextView) view.findViewById(R.id.site))
                            .getText().toString();
                    String logoURL = String.valueOf(((ImageView) view.findViewById(R.id.logoURL)));

                    // Starting single contact activity
                    Intent in = new Intent(getApplicationContext(),
                            SingleContactActivity.class);
                    in.putExtra(TAG_NAME, name);
                    in.putExtra(TAG_PHONE, phone);
                    in.putExtra(TAG_SITE, site);
                    in.putExtra(TAG_LOGO, logoURL);
                    startActivity(in);
                }
            });

            listView.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() {
                @Override
                public boolean onItemLongClick(AdapterView<?> parent, View view,
                                               int position, long id) {
                    ImageView button = (ImageView) view.findViewById(R.id.favorite_button);

                    String tag = button.getTag().toString();
                    if (tag.equalsIgnoreCase("grey")) {
                        sharedPreference.addFavorite(MainActivity.this, airlinesList.get(position));
                        Toast.makeText(MainActivity.this,
                                MainActivity.this.getResources().getString(R.string.add_favr),
                                Toast.LENGTH_SHORT).show();

                        button.setTag("red");
                        button.setImageResource(R.drawable.heart_red);
                    } else {
                        sharedPreference.removeFavorite(MainActivity.this, airlinesList.get(position));
                        button.setTag("grey");
                        button.setImageResource(R.drawable.heart_grey);
                        Toast.makeText(MainActivity.this,
                                MainActivity.this.getResources().getString(R.string.remove_favr),
                                Toast.LENGTH_SHORT).show();
                    }
                    return true;
                }
            });

            // changing action bar color
            getSupportActionBar().setBackgroundDrawable(
                    new ColorDrawable(Color.parseColor("#1b1b1b")));

            // Creating volley request obj
            JsonArrayRequest airlinesReq = new JsonArrayRequest(url,
                    new Response.Listener<JSONArray>() {
                        @Override
                        public void onResponse(JSONArray response) {
                            Log.d(TAG, response.toString());
                            hidePDialog();

                            // Parsing json
                            for (int i = 0; i < response.length(); i++) {
                                try {
                                    JSONObject obj = response.getJSONObject(i);
                                    Airlines airlines = new Airlines();
                                    airlines.setName(obj.getString("name"));
                                    airlines.setLogoURL(obj.getString("logoURL"));
                                    airlines.setPhone(obj.getString("phone"));
                                    airlines.setCode(obj.getInt("code"));
                                    airlines.setSite(obj.getString("site"));

                                    // adding airlines to array
                                    airlinesList.add(airlines);

                                } catch (JSONException e) {
                                    e.printStackTrace();
                                }
                            }
                            // notifying list adapterAirlines about data changes
                            // so that it renders the list view with updated data
                            adapterAirlines.notifyDataSetChanged();
                        }
                    }, new Response.ErrorListener() {
                @Override
                public void onErrorResponse(VolleyError error) {
                    VolleyLog.d(TAG, "Error: " + error.getMessage());
                    hidePDialog();
                }
            });

            // Adding request to request queue
            AppController.getInstance().addToRequestQueue(airlinesReq);

            FragmentManager fragmentManager = getSupportFragmentManager();

        /*
         * This is called when orientation is changed.
         */
            if (savedInstanceState != null) {
                if (savedInstanceState.containsKey("content")) {
                    String content = savedInstanceState.getString("content");
                    if (content.equals(FavoriteFragment.ARG_ITEM_ID)) {
                        if (fragmentManager.findFragmentByTag(FavoriteFragment.ARG_ITEM_ID) != null) {
                            setFragmentTitle(R.string.favorites);
                            contentFragment = fragmentManager
                                    .findFragmentByTag(FavoriteFragment.ARG_ITEM_ID);
                        }
                    }
                }
                if (fragmentManager.findFragmentByTag(AirlinesFragment.ARG_ITEM_ID) != null) {
                    airlinesFragment = (AirlinesFragment) fragmentManager
                            .findFragmentByTag(AirlinesFragment.ARG_ITEM_ID);
                    contentFragment = airlinesFragment;
                }
            } else {
                airlinesFragment = new AirlinesFragment();
                switchContent(airlinesFragment, AirlinesFragment.ARG_ITEM_ID);
            }

            /*
            From this place DrawerLayout starts
             */
            mTitle = mDrawerTitle = getTitle();

            // load slide menu items
            navMenuTitles = getResources().getStringArray(R.array.nav_drawer_items);

            // nav drawer icons from resources
            navMenuIcons = getResources()
                    .obtainTypedArray(R.array.nav_drawer_icons);

            mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
            mDrawerList = (ListView) findViewById(R.id.list_slidermenu);

            navDrawerItems = new ArrayList<NavDrawerItem>();

            // adding nav drawer items to array
            // Home
            navDrawerItems.add(new NavDrawerItem(navMenuTitles[0], navMenuIcons.getResourceId(0, -1)));
            // Favorites
            navDrawerItems.add(new NavDrawerItem(navMenuTitles[1], navMenuIcons.getResourceId(1, -1)));

            // Recycle the typed array
            navMenuIcons.recycle();

            // setting the nav drawer list adapterDrawer
            adapterDrawer = new NavDrawerListAdapter(getApplicationContext(),
                    navDrawerItems);
            mDrawerList.setAdapter(adapterDrawer);

            // enabling action bar app icon and behaving it as toggle button
            getSupportActionBar().setDisplayHomeAsUpEnabled(true);
            getSupportActionBar().setHomeButtonEnabled(true);

            mDrawerToggle = new ActionBarDrawerToggle(this, mDrawerLayout,
                    R.drawable.ic_drawer, //nav menu toggle icon
                    R.string.app_name, // nav drawer open - description for accessibility
                    R.string.app_name // nav drawer close - description for accessibility
            ){
                public void onDrawerClosed(View view) {
                    getSupportActionBar().setTitle(mTitle);
                    // calling onPrepareOptionsMenu() to show action bar icons
                    invalidateOptionsMenu();
                }

                public void onDrawerOpened(View drawerView) {
                    getSupportActionBar().setTitle(mDrawerTitle);
                    // calling onPrepareOptionsMenu() to hide action bar icons
                    invalidateOptionsMenu();
                }
            };
            mDrawerLayout.setDrawerListener(mDrawerToggle);

            if (savedInstanceState == null) {
                // on first time display view for first nav item
                displayView(0);
            }
        }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // toggle nav drawer on selecting action bar app icon/title
//        if (mDrawerToggle.onOptionsItemSelected(item)) {
//            return true;
//        }
//         Handle action bar actions click
//        switch (item.getItemId()) {
//            case R.id.action_settings:
//                return true;
//            default:
//                return super.onOptionsItemSelected(item);
//        }
//
        switch (item.getItemId()) {
            case R.id.action_settings:
                setFragmentTitle(R.string.favorites);
                favoriteFragment = new FavoriteFragment();
                switchContent(favoriteFragment, FavoriteFragment.ARG_ITEM_ID);

                return true;
        }
        return super.onOptionsItemSelected(item);
    }

    /***
     * Called when invalidateOptionsMenu() is triggered
     */
    @Override
    public boolean onPrepareOptionsMenu(Menu menu) {
        // if nav drawer is opened, hide the action items
        boolean drawerOpen = mDrawerLayout.isDrawerOpen(mDrawerList);
        menu.findItem(R.id.action_settings).setVisible(!drawerOpen);
        return super.onPrepareOptionsMenu(menu);
    }

    /**
     * Diplaying fragment view for selected nav drawer list item
     * */
    private void displayView(int position) {
        // update the main content by replacing fragments
        Fragment fragment = null;
        switch (position) {
            case 0:
                fragment = new HomeFragment();
                break;
            case 1:
                fragment = new FavoriteFragment();
                break;

            default:
                break;
        }

        if (fragment != null) {
            FragmentManager fragmentManager = getSupportFragmentManager();
            fragmentManager.beginTransaction()
                    .replace(R.id.frame_container, fragment).commit();

            // update selected item and title, then close the drawer
            mDrawerList.setItemChecked(position, true);
            mDrawerList.setSelection(position);
            setTitle(navMenuTitles[position]);
            mDrawerLayout.closeDrawer(mDrawerList);
        } else {
            // error in creating fragment
            Log.e("MainActivity", "Error in creating fragment");
        }
    }

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

    /**
     * When using the ActionBarDrawerToggle, you must call it during
     * onPostCreate() and onConfigurationChanged()...
     */

    @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 toggls
        mDrawerToggle.onConfigurationChanged(newConfig);
    }

    @Override
        public void onDestroy () {
        super.onDestroy();
        hidePDialog();
    }

    private void hidePDialog() {
        if (pDialog != null) {
            pDialog.dismiss();
            pDialog = null;
        }
    }

    @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;
    }

    @Override
    protected void onSaveInstanceState(Bundle outState) {
        if (contentFragment instanceof FavoriteFragment) {
            outState.putString("content", FavoriteFragment.ARG_ITEM_ID);
        } else {
            outState.putString("content", AirlinesFragment.ARG_ITEM_ID);
        }
        super.onSaveInstanceState(outState);
    }

    public void switchContent(Fragment fragment, String tag) {
        FragmentManager fragmentManager = getSupportFragmentManager();
        while (fragmentManager.popBackStackImmediate()) ;

        if (fragment != null) {
            FragmentTransaction transaction = fragmentManager
                    .beginTransaction();
            transaction.replace(R.id.content_frame, fragment, tag);
            //Only FavoriteFragment is added to the back stack.
            if (!(fragment instanceof AirlinesFragment)) {
                transaction.addToBackStack(tag);
            }
            transaction.commit();
            contentFragment = fragment;
        }
    }

    protected void setFragmentTitle(int resourseId) {
        setTitle(resourseId);
        getSupportActionBar().setTitle(resourseId);
    }
    /*
     * We call super.onBackPressed(); when the stack entry count is > 0. if it
     * is instanceof ProductListFragment or if the stack entry count is == 0, then
     * we finish the activity.
     * In other words, from AirlinesFragment on back press it quits the app.
     */

    @Override
    public void onBackPressed() {
        FragmentManager fm = getSupportFragmentManager();
        if (fm.getBackStackEntryCount() > 0) {
            super.onBackPressed();
        } else if (contentFragment instanceof AirlinesFragment
                || fm.getBackStackEntryCount() == 0) {
            finish();
        }
    }

    @Override
    public void onResume() {
        super.onResume();
    }
}

最喜欢的片段:

import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.AdapterView.OnItemLongClickListener;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.Toast;

import com.boom.kayakapp.R;
import com.boom.kayakapp.adapters.AirlinesAdapter;
import com.boom.kayakapp.model.Airlines;
import com.boom.kayakapp.util.SharedPreference;

import java.util.List;

public class FavoriteFragment extends Fragment {

    public static final String ARG_ITEM_ID = "favorite_list";

    ListView favoriteList;
    SharedPreference sharedPreference;
    List<Airlines> favorites;

    Activity activity;
    AirlinesAdapter airlinesAdapter;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        activity = getActivity();
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.activity_list, container,
                false);
        // Get favorite items from SharedPreferences.
        sharedPreference = new SharedPreference();
        favorites = sharedPreference.getFavorites(activity);

        if (favorites == null) {
            showAlert(getResources().getString(R.string.no_favorites_items),
                    getResources().getString(R.string.no_favorites_msg));
        } else {

            if (favorites.size() == 0) {
                showAlert(
                        getResources().getString(R.string.no_favorites_items),
                        getResources().getString(R.string.no_favorites_msg));
            }

            favoriteList = (ListView) view.findViewById(R.id.list);
            if (favorites != null) {
                airlinesAdapter = new AirlinesAdapter(activity, favorites);
                favoriteList.setAdapter(airlinesAdapter);

                favoriteList.setOnItemClickListener(new OnItemClickListener() {

                    public void onItemClick(AdapterView<?> parent, View arg1,
                            int position, long arg3) {

                    }
                });

                favoriteList
                        .setOnItemLongClickListener(new OnItemLongClickListener() {

                            @Override
                            public boolean onItemLongClick(
                                    AdapterView<?> parent, View view,
                                    int position, long id) {

                                ImageView button = (ImageView) view
                                        .findViewById(R.id.favorite_button);

                                String tag = button.getTag().toString();
                                if (tag.equalsIgnoreCase("grey")) {
                                    sharedPreference.addFavorite(activity,
                                            favorites.get(position));
                                    Toast.makeText(
                                            activity,
                                            activity.getResources().getString(
                                                    R.string.add_favr),
                                            Toast.LENGTH_SHORT).show();

                                    button.setTag("red");
                                    button.setImageResource(R.drawable.heart_red);
                                } else {
                                    sharedPreference.removeFavorite(activity,
                                            favorites.get(position));
                                    button.setTag("grey");
                                    button.setImageResource(R.drawable.heart_grey);
                                    airlinesAdapter.remove(favorites
                                            .get(position));
                                    Toast.makeText(
                                            activity,
                                            activity.getResources().getString(
                                                    R.string.remove_favr),
                                            Toast.LENGTH_SHORT).show();
                                }
                                return true;
                            }
                        });
            }
        }
        return view;
    }

    public void showAlert(String title, String message) {
        if (activity != null && !activity.isFinishing()) {
            AlertDialog alertDialog = new AlertDialog.Builder(activity)
                    .create();
            alertDialog.setTitle(title);
            alertDialog.setMessage(message);
            alertDialog.setCancelable(false);

            // setting OK Button
            alertDialog.setButton(AlertDialog.BUTTON_POSITIVE, "OK",
                    new DialogInterface.OnClickListener() {

                        public void onClick(DialogInterface dialog, int which) {
                            dialog.dismiss();
                            // activity.finish();
                            getFragmentManager().popBackStackImmediate();
                        }
                    });
            alertDialog.show();
        }
    }

    @Override
    public void onResume() {
        getActivity().setTitle(R.string.favorites);
        super.onResume();
    }
}

这个错误在我看来很漂亮 self-explaining。

java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.Object android.widget.ImageView.getTag()' on a null object reference

您尝试通过 ID 查找的按钮在长按后返回 null,因此您无法在该 object 上使用 getTag() 方法。

ImageView button = (ImageView) view.findViewById(R.id.favorite_button);

所以您应该检查收藏夹列表是否真的包含具有该 ID 的视图(按钮)。尝试使用 getActivity().findViewByID() 来测试它。