首页 文章

在android中接收通知时关闭时应用程序崩溃

提问于
浏览
-1

我是android的新手 . 我想 Build 一个警报应用程序 . 问题是,警报通知无法正常工作 . 应用程序打开时它唯一的工作 . 假设是上午10点 . 我在上午10点15分设置了警报,然后关闭了应用程序 . 上午10点15分,我将收到一条错误消息“app is stopped working”请帮助 . 提前致谢 .

AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.troy.timepickerdialog">

<application
    android:allowBackup="true"
    android:icon="@mipmap/ic_launcher"
    android:label="@string/app_name"
    android:roundIcon="@mipmap/ic_launcher_round"
    android:supportsRtl="true"
    android:theme="@style/AppTheme">
    <activity android:name=".MainActivity">
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />

            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity>
    <receiver android:name=".MyBroadcastReceiver"></receiver>
    <service
        android:name=".RingtonePlayingService"
        android:enabled="true">
    </service>
</application>

MainActivity.java

package com.troy.timepickerdialog;

    import android.app.AlarmManager;
    import android.app.DatePickerDialog;
    import android.app.Dialog;
    import android.app.PendingIntent;
    import android.content.Intent;
    import android.support.v7.app.AppCompatActivity;
    import android.os.Bundle;
    import android.util.Log;
    import android.view.View;
    import android.widget.Button;
    import android.widget.DatePicker;
    import android.widget.TextView;
    import android.widget.TimePicker;
    import android.widget.Toast;
    import java.util.Calendar;
    import static android.app.PendingIntent.FLAG_UPDATE_CURRENT;


    public class MainActivity extends AppCompatActivity {

    public static final int REQUEST_CODE = 0;
    private TimePicker theTimePicker;
    private AlarmManager alarmManager;
    private PendingIntent pendingIntent;
    private Button buttonOn, btnDate, buttonOff;
    private int yearX, monthX, dayX, hourX, minX;
    private static final int DIALOG_ID = 0;
    @Override
    protected void onCreate(Bundle savedInstanceState) {

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

        Calendar cal = Calendar.getInstance();
        yearX = cal.get(Calendar.YEAR);
        monthX = cal.get(Calendar.MONTH);
        dayX = cal.get(Calendar.DAY_OF_MONTH);

        theTimePicker = findViewById(R.id.timePicker);
        theTimePicker.setIs24HourView(false);

        buttonOn = findViewById(R.id.on);
        buttonOff = findViewById(R.id.off);

        showDatePickerDialog();

        alarmManager = (AlarmManager) getSystemService(this.ALARM_SERVICE);
        final Intent intent = new Intent(this, MyBroadcastReceiver.class);

        buttonOn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                hourX = theTimePicker.getCurrentHour();
                minX = theTimePicker.getCurrentMinute();


                Calendar dateAndTime = Calendar.getInstance();
                dateAndTime.setTimeInMillis(System.currentTimeMillis());
                dateAndTime.clear();
                dateAndTime.set(yearX, monthX, dayX, hourX, minX, 0);

                if(dateAndTime.before(Calendar.getInstance())) {
                    dateAndTime.add(Calendar.DATE, 1);
                }

                int hour = hourX;
                String ampm = "";
                if(hour < 12) ampm = "AM";
                else ampm = "PM";

                if(hour >= 13 && hour <= 23) {
                    hour -= 12;
                }
                else if(hour == 0) {
                    hour = 12;
                }
                String toastDate = dayX + "/" + (monthX + 1) + "/" + yearX;
                Toast.makeText(getApplicationContext(), "Alarm Set To Date: " + toastDate + " & Time: " + hour + " : " + minX + ampm, Toast.LENGTH_SHORT).show();

                intent.putExtra("extra", "alarmOn");
                pendingIntent = PendingIntent.getBroadcast(getApplicationContext(), REQUEST_CODE, intent, FLAG_UPDATE_CURRENT);

                alarmManager.set(AlarmManager.RTC_WAKEUP, dateAndTime.getTimeInMillis(), pendingIntent);
            }
        });

        buttonOff.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if(RingtonePlayingService.isRunning == true) {
                    RingtonePlayingService.mediaPlayer.stop();
                    Toast.makeText(getApplicationContext(), "Alarm is off", Toast.LENGTH_SHORT).show();
                }
                else {
                    Toast.makeText(getApplicationContext(), "Alarm if already off", Toast.LENGTH_SHORT).show();
                    //intent.putExtra("extra",  "alarmOff");
                    //alarmManager.cancel(pendingIntent);
                    //sendBroadcast(intent);
                }

            }
        });

    }




    public void showDatePickerDialog() {
        btnDate = findViewById(R.id.date);
        btnDate.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                showDialog(DIALOG_ID);
            }
        });
    }

    private DatePickerDialog.OnDateSetListener dPickerListener = new DatePickerDialog.OnDateSetListener() {
        @Override
        public void onDateSet(DatePicker view, int year, int month, int dayOfMonth) {

            yearX = year;
            monthX = month;
            dayX = dayOfMonth;

        }
    };

    @Override
    protected Dialog onCreateDialog(int id) {
        if(id == DIALOG_ID) {
            DatePickerDialog datePickerDialog = new DatePickerDialog(this, dPickerListener, yearX, monthX, dayX);
            datePickerDialog.getDatePicker().setMinDate(System.currentTimeMillis() - 1000);
            return datePickerDialog;
            //return new DatePickerDialog(this, dPickerListener, yearX, monthX, dayX);
        }
        return null;
    }
}

MyBroadcastReceiver.java

package com.troy.timepickerdialog;

import android.app.Notification;
import android.app.NotificationManager;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.media.MediaPlayer;
import android.support.v4.app.NotificationCompat;
import android.widget.Toast;

/**
 * Created by royta on 04-Dec-18.
 */

public class MyBroadcastReceiver extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {

        Intent service_intent = new Intent(context, RingtonePlayingService.class);
        String fetchExtra = intent.getExtras().getString("extra");


        if(fetchExtra.equals("alarmOn")) {
            Toast.makeText(context, "Alarming...", Toast.LENGTH_SHORT).show();
        }
        else {
            Toast.makeText(context, "Alarm is off", Toast.LENGTH_SHORT).show();
        }

        service_intent.putExtra("extra", fetchExtra);
        context.startService(service_intent);

        /*
        mediaPlayer = MediaPlayer.create(context, R.raw.alarm);
        mediaPlayer.setLooping(true);
        mediaPlayer.start();
        */

    }
}

RingtonePlayingService.java

package com.troy.timepickerdialog;

import android.annotation.TargetApi;
import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.media.MediaPlayer;
import android.os.Build;
import android.os.IBinder;
import android.support.annotation.Nullable;
import android.support.v4.app.NotificationCompat;
import android.util.Log;
import android.widget.Toast;

/**
 * Created by royta on 09-Dec-18.
 */

public class RingtonePlayingService extends Service {

    static MediaPlayer mediaPlayer;
    static boolean isRunning;
    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {

        String state = intent.getExtras().getString("extra");

        if(state.equals("alarmOn")) {
            Log.d("ROYs", "alarmOn state");
            mediaPlayer = MediaPlayer.create(this, R.raw.alarm);
            mediaPlayer.setLooping(true);
            mediaPlayer.start();
            this.isRunning = true;

            //Notification

            NotificationManager mNotificationManager;

            NotificationCompat.Builder mBuilder =
                    new NotificationCompat.Builder(this.getApplicationContext(), "notify_001");
            Intent goMainActivity = new Intent(this.getApplicationContext(), MainActivity.class);
            PendingIntent pendingIntent_for_Main = PendingIntent.getActivity(this, 0, goMainActivity, 0);

            mBuilder.setContentIntent(pendingIntent_for_Main);
            mBuilder.setSmallIcon(R.mipmap.ic_launcher_round);
            mBuilder.setContentTitle("Voice Reminder");
            mBuilder.setContentText("Organize your BackPack.");
            mBuilder.setPriority(Notification.PRIORITY_MAX);

            mNotificationManager = (NotificationManager) this.getSystemService(Context.NOTIFICATION_SERVICE);

            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                String channelId = "VOICE_REMINDER_ID";
                NotificationChannel channel = new NotificationChannel(channelId,
                        "Voice Reminder",
                        NotificationManager.IMPORTANCE_DEFAULT);
                mNotificationManager.createNotificationChannel(channel);
                mBuilder.setChannelId(channelId);
            }
            mNotificationManager.notify(0, mBuilder.build());

            //End Notification
        }
        else if(this.isRunning && state.equals("alarmOff")) {
            Log.d("ROYs", "alarmOff state");
            mediaPlayer.stop();
            this.isRunning = false;
        }
        return START_NOT_STICKY;
    }

}

Logcat Errors

12-10 19:31:03.934 16959-16959 / com.troy.timepickerdialog E / AndroidRuntime:FATAL EXCEPTION:main进程:com.troy.timepickerdialog,PID:16959 java.lang.RuntimeException:无法启动接收器com.troy . timepickerdialog.MyBroadcastReceiver:java.lang.IllegalStateException:不允许启动服务Intent {cmp = com.troy.timepickerdialog / .RingtonePlayingService(has extras)}:app在后台uid UidRecord {6b8d36d u0a142 TRNB idle procs:1 seq(0 ,0,0)}在android.app.ActivityThread.handleReceiver(ActivityThread.java:3210)的android.app.ActivityThread.-wrap17(未知来源:0)在android.app.ActivityThread $ H.handleMessage(ActivityThread.java) :1678)在Android.os.Handler.dispatchMessage(Handler.java:106)的android.app.Looper.loop(Looper.java:164)在android.app.ActivityThread.main(ActivityThread.java:6543)在java位于com.android.internal.os.ZygoteInit.mai的com.android.internal.os.RuntimeInit $ MethodAndArgsCaller.run(RuntimeInit.java:440)的.lang.reflect.Method.invoke(Native Method) n(ZygoteInit.java:810)引起:java.lang.IllegalStateException:不允许启动服务Intent {cmp = com.troy.timepickerdialog / .RingtonePlayingService(有附加内容)}:app在后台uid UidRecord {6b8d36d u0a142 TRNB idle procs:1 seq(0,0,0)}在android.app.ContextImpl.startService(侧面是1,用于Android.content.ContextWrap)的android.app.ContextImpl.start服务(ContextImpl.java:1478) . 位于android.app.A活动时,我在android.app.Apat.Deleiver(动作线程)的com.troy.timepickerdialog.MyBroadcastReceiver.onReceive(MyBroadcastReceiver.java:33)上的startService(ContextWrapper.java:650) .java:3203)在android.app.Handler.dispatchMessage(Handler.java:)的android.app.ActivityThread $ H.handleMessage(ActivityThread.java:1678)的android.app.ActivityThread.-wrap17(未知来源:0) 106)在android.app.Looper.loop(Looper.java:164)的android.app.ActivityThread.main(ActivityThread.java:6543)java.lang.reflect.M eth.inroid.invoke(Native Method)位于com.android.internal.os.ZygoteInit.main(ZygoteInit.java:810)的com.android.internal.os.RuntimeInit $ MethodAndArgsCaller.run(RuntimeInit.java:440)

1 回答

  • 0

    如果应用的目标SDK是26(Android O)或更高,则无法在后台启动服务 . 如果应用程序未打开,则必须启动前台服务,该服务将通过通知显示给用户 .

    在你的 BroadcastReceiver 中你应该替换:

    context.startService(service_intent);
    

    附:

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
        context.startForegroundService(service_intent);
    else {
        context.startService(service_intent);
    }
    

    此外,在 RingtonePlayingServiceonStartCommand 上,您需要将通知设置为启动前景:

    @Override
        public int onStartCommand(Intent intent, int flags, int startId) {
    
            startForeground(mNotificationId, mNotification)
            ...
    

    您可以查看here以获取更多信息 .

    另请注意,针对SDK 26的应用必须为其通知创建通知渠道 . 查看更多Notification Channels training

相关问题