SQLiteOpenHelper为null

时间:2017-08-04 16:21:56

标签: android sql sqlite android-fragments

在我的应用中,我有两个片段:FragmentAFragmentB,这些片段是在SlidingMenu的帮助下从我的MainActivity加载的。

感谢Crashlytics,我会在应用崩溃的时间和地点收到通知。在这种情况下,DatabaseHandler中的FragmentA有时会为空(对于某些用户而言),即使它已被初始化。

这是我的代码:

MainActivity

public class MainActivity extends AppCompatActivity implements MyFragment.OnListFragmentInteractionListener, AsyncResponse {


    private FragmentA fragmentA = new FragmentA();

    private DatabaseHandler databaseHandler = new DatabaseHandler(this);

    private NavigationView navigationView;
    private DrawerLayout drawer;
    private Toolbar toolbar;

    // index to identify current nav menu item
    private static int navItemIndex = 0;

    public static String CURRENT_TAG = MyConstants.TAG_FRAGMENT_A;

    // toolbar titles respected to selected nav menu item
    private String[] activityTitles;

    // flag to load home fragment when user presses back key
    private Handler mHandler;

    @Override
    protected void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_main);

        fragmentA.setDatabaseHandler(this.databaseHandler);

        // Init UI
        toolbar = (Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);

        mHandler = new Handler();

        drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
        navigationView = (NavigationView) findViewById(R.id.nav_view);

        fabSendButton = (FloatingActionButton) findViewById(R.id.fab);

        // Navigation view header
        navHeader = navigationView.getHeaderView(0);


        // load toolbar titles from string resources
        activityTitles = getResources().getStringArray(R.array.sliding_menu_item_activity_titles);


        // initializing navigation menu
        setUpNavigationView();

        if (savedInstanceState == null) {
            navItemIndex = 0;
            CURRENT_TAG = MyConstants.TAG_FRAGMENT_A;
            loadHomeFragment();
        }
    }

    /***
     * Returns respected fragment that user
     * selected from navigation menu
     */
    private void loadHomeFragment() {

        // set toolbar title
        setToolbarTitle();

        // if user select the current navigation menu again, don't do anything
        // just close the navigation drawer
        if (getSupportFragmentManager().findFragmentByTag(CURRENT_TAG) != null) {
            drawer.closeDrawers();
            return;
        }

        // Sometimes, when fragment has huge data, screen seems hanging
        // when switching between navigation menus
        // So using runnable, the fragment is loaded with cross fade effect
        // This effect can be seen in GMail app
        Runnable mPendingRunnable = new Runnable() {
            @Override
            public void run() {
                // update the activity_main_header_with_item content by replacing fragments
                Fragment fragment = getFragment();
                FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
                fragmentTransaction.setCustomAnimations(android.R.anim.fade_in, android.R.anim.fade_out);
                fragmentTransaction.replace(R.id.frame, fragment, CURRENT_TAG);
                fragmentTransaction.commit();
            }
        };

        // If mPendingRunnable is not null, then add to the message queue
        if (mPendingRunnable != null) {
            mHandler.post(mPendingRunnable);
        }

        //Closing drawer on item click
        drawer.closeDrawers();

        // refresh toolbar menu
        invalidateOptionsMenu();
    }

    private Fragment getFragment() {
        switch (navItemIndex) {
            case 0:
                return this.fragmentA;
            case 1:
                Fragment B fragmentB = new FragmentB();
                fragmentB.setDatabaseHandler(this.databaseHandler);
                return fragmentB;
            default:
                return this.fragmentA;
        }
    }

    private void setToolbarTitle() {
        getSupportActionBar().setTitle(activityTitles[navItemIndex]);
    }

    private void setUpNavigationView() {
        //Setting Navigation View Item Selected Listener to handle the item click of the navigation menu
        navigationView.setNavigationItemSelectedListener(new NavigationView.OnNavigationItemSelectedListener() {

            // This method will trigger on item Click of navigation menu
            @Override
            public boolean onNavigationItemSelected(MenuItem menuItem) {

                //Check to see which item was being clicked and perform appropriate action
                switch (menuItem.getItemId()) {
                    //Replacing the activity_main_header_with_item content with ContentFragment Which is our Inbox View;
                    case R.id.nav_A:
                        navItemIndex = 0;
                        CURRENT_TAG = MyConstants.TAG_FRAGMENT_A;
                        break;
                    case R.id.nav_B:
                        navItemIndex = 1;
                        CURRENT_TAG = MyConstants.TAG_FRAGMENT_B;
                        break;
                    default:
                        navItemIndex = 0;
                }

                loadHomeFragment();

                return true;
            }
        });

        ActionBarDrawerToggle actionBarDrawerToggle = new ActionBarDrawerToggle(this, drawer, toolbar, R.string.openDrawer, R.string.closeDrawer) {

            @Override
            public void onDrawerClosed(View drawerView) {
                // Code here will be triggered once the drawer closes as we dont want anything to happen so we leave this blank
                super.onDrawerClosed(drawerView);
            }

            @Override
            public void onDrawerOpened(View drawerView) {
                // Code here will be triggered once the drawer open as we dont want anything to happen so we leave this blank
                super.onDrawerOpened(drawerView);
            }
        };

        //Setting the actionbarToggle to drawer layout
        drawer.setDrawerListener(actionBarDrawerToggle);

        //calling sync state is necessary or else your hamburger icon wont show up
        actionBarDrawerToggle.syncState();
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.activity_main_header_with_item, menu);
        return true;
    }
}

FragmentA

public class FragmentA extends MyFragment implements AsyncResponse {

    private View view;
    private RecyclerView recyclerView;

    public FragmentA() {
    }


    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {

        List<Song> songsList = databaseHandler.getAllSongs();

        view = inflater.inflate(R.layout.home_list, container, false);

        // Set the adapter
        Context context = view.getContext();
        recyclerView = (RecyclerView) view.findViewById(R.id.listinclude);
        recyclerView.setLayoutManager(new LinearLayoutManager(context));

        recyclerView.addItemDecoration(new DividerItemDecoration(getActivity(), R.drawable.divider));

        setVisibilities(songsList);

        this.recyclerViewAdapter = new RecyclerViewAdapter(songsList, mListener, false, true);

        recyclerView.setAdapter(this.recyclerViewAdapter);
        return view;
    }

    @Override
    public void onActivityCreated(@Nullable Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
    }


    private void setVisibilities(List<Song> songsList) {
        ViewFlipper viewFlipper = (ViewFlipper) view.findViewById(R.id.viewFlipper);
        if (songsList.isEmpty() && viewFlipper.getDisplayedChild() == 0) {
            viewFlipper.setDisplayedChild(1);
        } else if (!songsList.isEmpty() && viewFlipper.getDisplayedChild() == 1) {
            viewFlipper.setDisplayedChild(0);
        }
    }


    @Override
    public void processFinish(String output) {
        // does something
    }
}

MyFragment

public class MyFragment extends Fragment {
    protected DatabaseHandler databaseHandler;
    protected static final String ARG_COLUMN_COUNT = "column-count";
    protected int mColumnCount = 1;
    protected MyFragment.OnListFragmentInteractionListener mListener;
    protected RecyclerViewAdapter recyclerViewAdapter;
    public void setDatabaseHandler(DatabaseHandler databaseHandler) {
        this.databaseHandler = databaseHandler;
    }
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Timber.i( "onCreate");
        if (getArguments() != null) {
            mColumnCount = getArguments().getInt(ARG_COLUMN_COUNT);
        }
    }
    @Override
    public void onPause() {
        Timber.i( "onPause");
        super.onPause();
    }
    @Override
    public void onAttach(Context context) {
        Timber.i( "onAttach");
        super.onAttach(context);
        if (context instanceof OnListFragmentInteractionListener) {
            mListener = (FragmentA.OnListFragmentInteractionListener) context;
        } else {
            throw new RuntimeException(context.toString() + " must implement OnListFragmentInteractionListener");
        }
    }
    @Override
    public void onDetach() {
        Timber.i( "onDetach");
        super.onDetach();
        mListener = null;
    }

    public interface OnListFragmentInteractionListener {
        // TODO: Update argument type and name
        void onListFragmentInteraction(Song item);
    }
}

数据库处理器

public class DatabaseHandler extends SQLiteOpenHelper {

    // All Static variables
    // Database Version
    private static final int DATABASE_VERSION = 1;

    // Database Name
    private static final String DATABASE_NAME = "appName";

    // Songs table name
    private static final String TABLE_SONGS = "songs";


    @Override
    public void onCreate(SQLiteDatabase db) {
        // create Tables
    }


    // Upgrading database
    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        switch(oldVersion) {
            case 1:
                //upgrade logic from version 1 to 2
            case 2:
                //upgrade logic from version 2 to 3
            case 3:
                //upgrade logic from version 3 to 4
                break;
            default:
                throw new IllegalStateException(
                        "onUpgrade() with unknown oldVersion " + oldVersion);
        }
    }


    // Getting All Songs
    public List<Song> getAllSongs() {

        // Select All Query
        String selectQuery = "SELECT  * FROM " + TABLE_SONGS + " ORDER BY ID DESC";

        SQLiteDatabase db = this.getWritableDatabase();
        Cursor cursor = db.rawQuery(selectQuery, null);

        List<Song> songList = new ArrayList<>();

        songList.addAll(getSongsFromCursor(cursor));

        cursor.close();
        // return title list
        return songList;
    }
}

问题

Fatal Exception: java.lang.RuntimeException
Unable to start activity ComponentInfo{com.myapp.myappname/com.myapp.myappname.ui.activity.MainActivity}: java.lang.NullPointerException: Attempt to invoke virtual method 'java.util.List com.myapp.myappname.database.DatabaseHandler.getAllSongs()' on a null object reference

详情

Fatal Exception: java.lang.RuntimeException: Unable to start activity ComponentInfo{com.myapp.myappname/com.myapp.myappname.ui.activity.MainActivity}: java.lang.NullPointerException: Attempt to invoke virtual method 'java.util.List com.myapp.myappname.database.DatabaseHandler.getAllSongs()' on a null object reference
       at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2984)
       at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3045)
       at android.app.ActivityThread.-wrap14(ActivityThread.java)
       at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1642)
       at android.os.Handler.dispatchMessage(Handler.java:102)
       at android.os.Looper.loop(Looper.java:154)
       at android.app.ActivityThread.main(ActivityThread.java:6776)
       at java.lang.reflect.Method.invoke(Method.java)
       at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1496)
       at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1386)
Caused by java.lang.NullPointerException: Attempt to invoke virtual method 'java.util.List com.myapp.myappname.database.DatabaseHandler.getAllSongs()' on a null object reference
       at com.myapp.myappname.ui.fragment.FragmentA.onCreateView(FragmentA.java:51)
       at android.support.v4.app.Fragment.performCreateView(Fragment.java:2192)
       at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1299)
       at android.support.v4.app.FragmentManagerImpl.moveFragmentToExpectedState(FragmentManager.java:1528)
       at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1595)
       at android.support.v4.app.FragmentManagerImpl.dispatchActivityCreated(FragmentManager.java:2900)
       at android.support.v4.app.FragmentController.dispatchActivityCreated(FragmentController.java:201)
       at android.support.v4.app.FragmentActivity.onStart(FragmentActivity.java:603)
       at android.support.v7.app.AppCompatActivity.onStart(AppCompatActivity.java:178)
       at com.myapp.myappname.ui.activity.MainActivity.onStart(MainActivity.java:590)
       at android.app.Instrumentation.callActivityOnStart(Instrumentation.java:1256)
       at android.app.Activity.performStart(Activity.java:6972)
       at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2937)
       at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3045)
       at android.app.ActivityThread.-wrap14(ActivityThread.java)
       at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1642)
       at android.os.Handler.dispatchMessage(Handler.java:102)
       at android.os.Looper.loop(Looper.java:154)
       at android.app.ActivityThread.main(ActivityThread.java:6776)
       at java.lang.reflect.Method.invoke(Method.java)
       at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1496)
       at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1386)

3 个答案:

答案 0 :(得分:0)

尝试这个

databaseHandler=new DataBaseHandler(getActivity());
List<Song> songsList = databaseHandler.getAllSongs();

在DataBaseHandler类中添加构造函数

public DataBaseHandler(Context context){
super(context, DB_NAME, null, 1);
}

答案 1 :(得分:0)

在FragmentA上试试这个。

databaseHandler=new DataBaseHandler(getContext());

您正在使用mainActivity的上下文来初始化databaseHandler但是在片段中使用。

答案 2 :(得分:0)

Found a solution based on Serg's answer:

FragmentA:

    public class FragmentA extends MyFragment implements AsyncResponse {

        private View view;
        private RecyclerView recyclerView;

        public FragmentA() {
        }

  public static FragmentA newInstance(DatabaseHandler DatabaseHandler) {
        FragmentA fragment = new FragmentA();
        Bundle bundle = new Bundle();
        bundle.putSerializable(MyConstants.FRAGMENT_ARGUMENT_KEY, databaseHandler);
        fragment.setArguments(bundle);
        return fragment;
    }

        @Override
        public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
            databaseHandler = (DatabaseHandler) getArguments().getSerializable(MyConstants.FRAGMENT_ARGUMENT_KEY);
            List<Song> songsList = databaseHandler.getAllSongs();

            view = inflater.inflate(R.layout.home_list, container, false);

            // Set the adapter
            Context context = view.getContext();
            recyclerView = (RecyclerView) view.findViewById(R.id.listinclude);
            recyclerView.setLayoutManager(new LinearLayoutManager(context));

            recyclerView.addItemDecoration(new DividerItemDecoration(getActivity(), R.drawable.divider));

            setVisibilities(songsList);

            this.recyclerViewAdapter = new RecyclerViewAdapter(songsList, mListener, false, true);

            recyclerView.setAdapter(this.recyclerViewAdapter);
            return view;
        }

        @Override
        public void onActivityCreated(@Nullable Bundle savedInstanceState) {
            super.onActivityCreated(savedInstanceState);
        }


        private void setVisibilities(List<Song> songsList) {
            ViewFlipper viewFlipper = (ViewFlipper) view.findViewById(R.id.viewFlipper);
            if (songsList.isEmpty() && viewFlipper.getDisplayedChild() == 0) {
                viewFlipper.setDisplayedChild(1);
            } else if (!songsList.isEmpty() && viewFlipper.getDisplayedChild() == 1) {
                viewFlipper.setDisplayedChild(0);
            }
        }


        @Override
        public void processFinish(String output) {
            // does something
        }
    }

MainActivity:

    fragmentA = FragmentA.newInstance(this.databaseHandler);