2017-08-04 47 views
0

在我的應用程序中,我有兩個片段:FragmentAFragmentB,這些片段是通過SlidingMenu從我的MainActivity加載的。SQLiteOpenHelper爲空

感謝Crashlytics,我得知我的應用何時何地崩潰。在這種情況下,FragmentA中的DatabaseHandler不時(對於某些用戶)爲空,即使它已被初始化。

這是我的代碼:

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) 
+2

'fragmentA.setDatabaseHandler(this.databaseHandler);' - 這是與片段交互的錯誤方式。請參閱https://stackoverflow.com/questions/17436298/how-to-pass-a-variable-from-activity-to-fragment-and-pass-it-back – Serg

回答

0

試試這個

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

並添加構造函數在數據庫處理器類

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

試試這FragmentA。

databaseHandler=new DataBaseHandler(getContext()); 

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

0

發現基於SERG的答案的解決方案:

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); 
+0

問題仍未解決,我現在得到一個由java.lang.RuntimeException:Parcelable在讀取Serializable對象(名稱= com.myapp.appname.database.DatabaseHandler)時遇到IOException。有任何想法嗎? – joshi737