Android 如果应用关闭,每 15 分钟通知一次崩溃

Android notification every 15 minutes crashes if app is closed

所以我是 Android Studio 的新手,我正在尝试制作一个简单的应用程序来执行以下操作:

该应用程序在 /res/values 文件夹中设置了一个名为 "frases" 的字符串数组。 Main activity 包含一个按钮,当它被按下时,它会递增一个表示要使用的数组索引的变量(我称之为 "iterador")并将 textView 设置为 frases 的值[迭代器].

然后在 MainActivity 的 onCreate 方法上,我有一个带有 setRepeating 的警报,它调用 class 每 15 分钟接收一次通知。这样做的目的是在 MainActivity 中有一个 textview 和一个可以显示 frases[iterador].

值的通知

这里的问题是每当我的应用程序关闭时(不是从 android 设置菜单停止,只是关闭)我收到一条错误消息,指出字符串数组为空。更糟糕的是,在第一次通知之后,如果我没有在我的 phone 中打开应用程序(即使它没有关闭),有时即使在 15 分钟后第二个通知也不会出现。

我试图通过将两个变量设为静态来解决此问题,以便我可以从通知中访问它们 class,但仍然不起作用。

有没有办法解决这个问题,让通知即使在应用程序关闭时也能显示?

我的 MainActivity 变量和 onCreate 方法:

public class MainActivity extends Activity implements View.OnClickListener {

//MY CODE
public static boolean primera; //APP OPENED FOR THE FIRST TIME

private Button b_corazon, b_carta;
private TextView t_frase;
public static final String PREFS_NAME = "MyPrefsFile";


//-------------------------STRING SHOW VARIABLES----------------------
public static String[] frases; //STRING ARRAY
public static int iterador; // INDEX FOR THE ARRAY
AlarmManager alarmManager; //ALARM MANAGER





@Override
protected void onCreate(Bundle savedInstanceState) {
    Resources res=getResources(); //GET THE RESOURCES
    frases=res.getStringArray(R.array.cartas); //ASIGN THE STRING ARRAY TO THE VARIABLE
    super.onCreate(savedInstanceState);
    requestWindowFeature(Window.FEATURE_NO_TITLE);
    setContentView(R.layout.activity_main);
    //MI CODIGO

    Intent intent = new Intent(getApplicationContext(), RecibeNotif.class);
    PendingIntent pendingIntent = PendingIntent.getBroadcast(getApplicationContext(),0,intent,0);
    alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);

    Calendar firing = Calendar.getInstance();  //SCHEDULED TIME
    Calendar current = Calendar.getInstance(); //CURRENT TIME

    firing.set(Calendar.HOUR_OF_DAY,14);
    firing.set(Calendar.MINUTE,20);
    firing.set(Calendar.SECOND,0);

    long intendedTime=firing.getTimeInMillis(); //SCHEDULED TIME
    long currentTime=current.getTimeInMillis(); //CURRENT TIME

    if(intendedTime>=currentTime){ //IF IT ISN'T THE TIME YET
        alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, intendedTime,AlarmManager.INTERVAL_FIFTEEN_MINUTES,pendingIntent);
    }
    else{ //IF THE TIME HAS ALREADY PASSED
        firing.add(Calendar.MINUTE,15); //ADD 15 MINUTES FOR THE NEXT ALARM
        intendedTime=firing.getTimeInMillis();
        alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, intendedTime,AlarmManager.INTERVAL_FIFTEEN_MINUTES,pendingIntent);
    }






    //SAVE THE VALUE OF ITERADOR IN THE APPLICATION DATA
    SharedPreferences settings = getSharedPreferences(PREFS_NAME,0); //GUARDAR DATO DE ITERADOR
    primera=getSharedPreferences("PREFERENCE",MODE_PRIVATE).getBoolean("primera", true);
    iterador=settings.getInt("iterador",iterador);
    init();
}

我的 BroadcastReceiver 通知 class:

public class RecibeNotif extends BroadcastReceiver{

    @Override
    public void onReceive(Context context, Intent intent) {
        String[] frasesaux;
        int iteraux;

        iteraux=MainActivity.iterador;
        frasesaux=MainActivity.frases;
        if(iteraux==frasesaux.length){
            iteraux=0;
        }

        NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);

        Intent redir = new Intent(context,direct.class);
        redir.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);

        PendingIntent pendingIntent = PendingIntent.getActivity(context, 100, redir, PendingIntent.FLAG_UPDATE_CURRENT);

        NotificationCompat.Builder builder = new NotificationCompat.Builder(context)
                .setContentIntent(pendingIntent)
                .setSmallIcon(R.drawable.message)  //ICONO DE LA NOTIFICACION
                .setContentTitle(".////.")
                .setContentText(frasesaux[iteraux])
                .setAutoCancel(true);

        notificationManager.notify(100,builder.build());

    }
}

<------------编辑------------>

好的,现在已经修复了,通知效果很好。唯一仍然让我发疯的是如何在通知 class 结束时更新 iterador 的值,使其与 iteraux.

匹配

到目前为止,我已经尝试使用 SharedPreferences.editor 编辑 iterador 的值,但它似乎不起作用。

有什么想法吗?

public void onReceive(Context context, Intent intent) {
    String[] finale;
    int iteraux;
    SharedPreferences settings = context.getSharedPreferences(PREFS_NAME,0); //GUARDAR DATO DE ITERADOR
    iteraux = settings.getInt("iterador",iterador);
    Resources res= context.getResources(); //GET THE RESOURCES
    finale=res.getStringArray(R.array.cartas); //ASIGN THE STRING ARRAY TO THE VARIABLE
    //iteraux=MainActivity.iterador;

    if(iteraux==finale.length){
        iteraux=0;
    }
    else{
        iteraux++;
    }



    //<-----------UPDATE ITERADOR VAR IN MAINACTIVITY
    SharedPreferences.Editor editor2 = settings.edit();
    editor2.putInt("iterador",iteraux);
    editor2.commit();

   // frasesaux=MainActivity.frases;

当您收到通知时,您的 activity 不是 alive,因此如果您尝试访问 Activity 的字段而不是 alive,则会出现异常

解决方案

1.) 使用context得到getStringArray(R.array.cartas)

2.) 使用相同的 contextSharedPreferences

获取数据
public class RecibeNotif extends BroadcastReceiver{

    @Override
    public void onReceive(Context context, Intent intent) {
        String[] frasesaux;
        int iteraux;
        SharedPreferences settings = context.getSharedPreferences("MyPrefsFile",0);
        iteraux = settings.getInt("iterador",0);
        //                                   ^^ your default value

        //iteraux=MainActivity.iterador;
        frasesaux=context.getResources().getStringArray(R.array.cartas);
        // ^^ fetch the array 
        if(iteraux==frasesaux.length){
            iteraux=0;
        }
        //...
   }
}

注意:static 不会有任何区别,因为你的数组只会在 onCreate 被 android OS 调用时初始化,所以这是并非如此,因此您的 static 字段将保持 un-initialized 表示 null 和 0.