I'm sort of having a weird problem here.
I've created a function to update a notification ("updateNotification" in MainActivity). However, the weird thing is my update notification function has no problem being called from MainActivity but when I call it from another class (line 76 in notificationSingleton), my app immediately crashes.
MainActivity.java
public static TextView dateText;private CountDownTimer countDownTimer;private NotificationSingleton notificationSingleton;@Overrideprotected void onCreate(Bundle savedInstanceState){ super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // if first start SharedPreferences prefs = getSharedPreferences("prefs", MODE_PRIVATE); boolean firstStart = prefs.getBoolean("firstStart", true); if(firstStart) { showStartDialog(); } // set dateText to date_text dateText = findViewById(R.id.date_text); // show date picker when click on show_dialog button findViewById(R.id.show_dialog).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { showDatePickerDialog(); } }); notificationSingleton = NotificationSingleton.getInstance(); startTimer();}private void showStartDialog(){ new AlertDialog.Builder(this) .setTitle("One Time Dialog") .setMessage("This should only be shown once") .setPositiveButton("ok", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { showDatePickerDialog(); } }) .create().show(); SharedPreferences prefs = getSharedPreferences("prefs", MODE_PRIVATE); SharedPreferences.Editor editor = prefs.edit(); editor.putBoolean("firstStart", false); editor.apply();}private void showDatePickerDialog(){ DatePickerDialog datePickerDialog = new DatePickerDialog( this, this, Calendar.getInstance().get(Calendar.YEAR), Calendar.getInstance().get(Calendar.MONTH), Calendar.getInstance().get(Calendar.DAY_OF_MONTH) ); datePickerDialog.show();}@Overridepublic void onDateSet(DatePicker view, int year, int month, int dayOfMonth){ Date endDate = new Date((year-1900),month,dayOfMonth); SharedPreferences prefs = getSharedPreferences("prefs", MODE_PRIVATE); SharedPreferences.Editor editor = prefs.edit(); editor.putLong("endDate", endDate.getTime()); editor.apply(); startTimer();}private void startTimer(){ long difference = getRemainDays(); if(countDownTimer !=null) { countDownTimer.cancel(); countDownTimer = null; } countDownTimer = new CountDownTimer(difference,1000) // 1 second { @Override public void onTick(long millisUntilFinished) { int days = (int)(millisUntilFinished/(1000*60*60*24)); int hours = (int)((millisUntilFinished/(1000*60*60))%24); int mins = (int)((millisUntilFinished/(1000*60))%60); int sec = (int)((millisUntilFinished/(1000))%60); dateText.setText(String.format("%02d Days %d Hours %d Mins %d Sec",days,hours,mins,sec)); } @Override public void onFinish() { // Done dateText.setText("Done"); } }.start();}private long getRemainDays(){ Date currentDate = new Date(); SharedPreferences prefs = getSharedPreferences("prefs", MODE_PRIVATE); long endDate = prefs.getLong("endDate", currentDate.getTime()); return endDate - currentDate.getTime();}public void startService(View v){ String input = dateText.getText().toString(); Intent serviceIntent = new Intent(this, ExampleService.class); serviceIntent.putExtra("inputExtra", input); ContextCompat.startForegroundService(this,serviceIntent); notificationSingleton.mNotificationRunnable.run();}public void stopService(View v){ Intent serviceIntent = new Intent(this,ExampleService.class); stopService(serviceIntent); notificationSingleton.stopService();}public TextView getDateText(){ return dateText;}public void updateNotification() { MainActivity mainActivity = new MainActivity(); String input = mainActivity.getDateText().getText().toString(); Intent notificationIntent = new Intent(this, NotificationSingleton.class); PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0); Notification notification = new NotificationCompat.Builder(this, CHANNEL_ID) .setContentTitle("Example Service") .setContentText(input) .setSmallIcon(R.drawable.ic_android) .setContentIntent(pendingIntent) .build(); NotificationManager mNotificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE); mNotificationManager.notify(1, notification);}
NotificationSingleton.java
public Handler mHandler = new Handler();MainActivity mainActivity = new MainActivity();private static NotificationSingleton instance;private NotificationSingleton(){ //private to prevent any else from instantiating}public static synchronized NotificationSingleton getInstance(){ if (instance == null){ instance = new NotificationSingleton(); } return instance;}public void stopService(){ mHandler.removeCallbacks(mNotificationRunnable);}public Runnable mNotificationRunnable = new Runnable(){ @Override public void run() { mainActivity.updateNotification(); mHandler.postDelayed(this,1000); }};
Logcat
2020-04-13 13:36:28.705 8346-8346/com.example.countdownlockdown E/AndroidRuntime: FATAL EXCEPTION: mainProcess: com.example.countdownlockdown, PID: 8346java.lang.IllegalStateException: Could not execute method for android:onClick at androidx.appcompat.app.AppCompatViewInflater$DeclaredOnClickListener.onClick(AppCompatViewInflater.java:390) at android.view.View.performClick(View.java:7350) at android.view.View.performClickInternal(View.java:7327) at android.view.View.access$3600(View.java:807) at android.view.View$PerformClick.run(View.java:28166) at android.os.Handler.handleCallback(Handler.java:907) at android.os.Handler.dispatchMessage(Handler.java:99) at android.os.Looper.loop(Looper.java:216) at android.app.ActivityThread.main(ActivityThread.java:7464) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:549) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:955) Caused by: java.lang.reflect.InvocationTargetException at java.lang.reflect.Method.invoke(Native Method) at androidx.appcompat.app.AppCompatViewInflater$DeclaredOnClickListener.onClick(AppCompatViewInflater.java:385) at android.view.View.performClick(View.java:7350) at android.view.View.performClickInternal(View.java:7327) at android.view.View.access$3600(View.java:807) at android.view.View$PerformClick.run(View.java:28166) at android.os.Handler.handleCallback(Handler.java:907) at android.os.Handler.dispatchMessage(Handler.java:99) at android.os.Looper.loop(Looper.java:216) at android.app.ActivityThread.main(ActivityThread.java:7464) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:549) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:955) Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.String android.content.Context.getPackageName()' on a null object reference at android.content.ContextWrapper.getPackageName(ContextWrapper.java:148) at android.content.ComponentName.<init>(ComponentName.java:131) at android.content.Intent.<init>(Intent.java:6860) at com.example.countdownlockdown.MainActivity.updateNotification(MainActivity.java:176) at com.example.countdownlockdown.NotificationSingleton$1.run(NotificationSingleton.java:76) at com.example.countdownlockdown.MainActivity.startService(MainActivity.java:158) at java.lang.reflect.Method.invoke(Native Method) at androidx.appcompat.app.AppCompatViewInflater$DeclaredOnClickListener.onClick(AppCompatViewInflater.java:385) at android.view.View.performClick(View.java:7350) at android.view.View.performClickInternal(View.java:7327) at android.view.View.access$3600(View.java:807) at android.view.View$PerformClick.run(View.java:28166) at android.os.Handler.handleCallback(Handler.java:907) at android.os.Handler.dispatchMessage(Handler.java:99) at android.os.Looper.loop(Looper.java:216) at android.app.ActivityThread.main(ActivityThread.java:7464) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:549) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:955)