0

So I have an app with multiple navigation view tabs/fragments, and it is suppose to initialize the main fragment (Dashboard) when the app opens. It shows everything just fine, but when I try to access values within specific elements, such as this batteryView.getChargeLevel() method, it just points to a null object and the app crashes. I was wondering if there is anything I'm doing wrong to make it not initialize these objects?

Here is my onCreate method within my MainActivity.java:

@Override
protected void onCreate(Bundle savedInstanceState) {

    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_bottom_nav);

    BottomNavigationView navView = findViewById(R.id.nav_view);
    // Passing each menu ID as a set of Ids because each
    // menu should be considered as top level destinations.
    AppBarConfiguration appBarConfiguration = new AppBarConfiguration.Builder(
            R.id.navigation_dashboard, R.id.navigation_diagnostics, R.id.navigation_statistics, R.id.navigation_connection)
            .build();
    NavController navController = Navigation.findNavController(this, R.id.nav_host_fragment);
    NavigationUI.setupActionBarWithNavController(this, navController, appBarConfiguration);
    NavigationUI.setupWithNavController(navView, navController);


    initViewElements();


}

    private void initViewElements() {



    BatteryMeterView batteryView = (BatteryMeterView) findViewById(R.id.battery);
    

    if (batteryView.getChargeLevel() <= 80)
    {
        batteryView.setCharging(false);
    }
   

}

Contents of my fragment_dashboard xml file

<androidx.constraintlayout.widget.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".ui.dashboard.DashboardFragment" >

   <eo.view.batterymeter.BatteryMeterView
        android:id="@+id/battery"
        android:layout_width="225dp"
        android:layout_height="168dp"
        android:paddingStart="1dp"
        android:paddingLeft="1dp"
        android:paddingRight="1dp"
        android:rotation="90"
        app:batteryMeterChargeLevel="100"
        app:batteryMeterChargingColor="#4caf50"
        app:batteryMeterColor="#4caf50"
        app:batteryMeterCriticalChargeLevel="0"
        app:batteryMeterCriticalColor="#d84315"
        app:batteryMeterIndicatorColor="@android:color/transparent"
        app:batteryMeterIsCharging="false"
        app:batteryMeterTheme="rounded"
        app:batteryMeterUnknownColor="#e0e0e0"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/gauge1"

        app:layout_constraintVertical_bias="0.0"
        tools:layout_editor_absoluteX="-13dp" />

</androidx.constraintlayout.widget.ConstraintLayout>

The error Logcat:

    java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.obd/com.example.obd.MainActivity}: java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.Integer eo.view.batterymeter.BatteryMeterView.getChargeLevel()' on a null object reference
        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2913)
        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3048)
        at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:78)
        at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:108)
        at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:68)
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1808)
        at android.os.Handler.dispatchMessage(Handler.java:106)
        at android.os.Looper.loop(Looper.java:193)
        at android.app.ActivityThread.main(ActivityThread.java:6669)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)
     Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.Integer eo.view.batterymeter.BatteryMeterView.getChargeLevel()' on a null object reference
        at com.example.obd.MainActivity.initViewElements(MainActivity.java:194)
        at com.example.obd.MainActivity.onCreate(MainActivity.java:169)
        at android.app.Activity.performCreate(Activity.java:7136)
        at android.app.Activity.performCreate(Activity.java:7127)
        at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1271)
Zain
  • 37,492
  • 7
  • 60
  • 84
N4P
  • 11
  • 4
  • You should move your code to DashboardFragment class not MainActivity class. BatteryMeterView is in a different layout according to your code. – Mbuodile Obiosio Jan 14 '21 at 21:39

1 Answers1

0

Activity's findViewById() method can only inflate views in the activity's layout which is in your case R.layout.activity_bottom_nav.

But using the below line of code, you are trying to inflate R.id.battery view in activity; but actually it exists in a fragment layout .ui.dashboard.DashboardFragment

BatteryMeterView batteryView = (BatteryMeterView) findViewById(R.id.battery);

So, you can iflate that in DashboardFragment class using

requireView().findViewById(R.id.battery);

This should be in any fragment lifecycle method after onCreateView.. or you can use the inflated view in onCreateView like:

myInflatedView.findViewById(R.id.battery);
Zain
  • 37,492
  • 7
  • 60
  • 84
  • Okay that makes sense, but if I put requireView().findViewById(R.id.battery); in the onCreateView method within my Dashboard Fragment class, does it mean I can still access Battery from my MainActivity class like I have it? I mainly asking this because I have multiple elements which interact with eachother. Or will I absolutely have to keep everything separate? – N4P Jan 14 '21 at 21:54
  • No .. it does mean that you try to access it from the fragment before creating the fragment view.. requireView() will return null in this case ... instead use the inflated view within the `onCreateView` which already returned by `onCreateView` method – Zain Jan 14 '21 at 22:10