当从另一个 class 调用但从 MainActivity.java 调用时函数崩溃应用程序

Function crashing app when called from another class but not when called from MainActivity.java

我遇到了一个奇怪的问题。

我创建了一个更新通知的函数("updateNotification" 在 MainActivity 中)。然而,奇怪的是我的更新通知功能从 MainActivity 调用没有问题但是当我从另一个 class (notificationSingleton 中的第 76 行)调用它时,我的应用程序立即崩溃。

MainActivity.java

 public static TextView dateText;
private CountDownTimer countDownTimer;
private NotificationSingleton notificationSingleton;

@Override
protected 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();
}

@Override
public 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: main
Process: com.example.countdownlockdown, PID: 8346
java.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.access00(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.access00(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.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.access00(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) 

我不确定 MainActivity 是否真的扩展了 Activity component.If 所以 updateNotification 方法中的 MainActivity mainActivity = new MainActivity(); 行是完全错误的。您不应该以这种方式创建 Activity 的实例。请删除它并尽可能使用 getContext() 来使用上下文。