Android 闹钟没有通知显示,无法播放歌曲和启动按钮错误

No notifications Display, Cannot play the song and error for start button for Android Alarm Clock

我是 Android Studio 的初学者 我尝试制作 Android 闹钟,现在它无法显示通知,没有播放音乐,并且停止按钮也有错误。这是我的代码,希望有人能帮我解决。谢谢

AlarmReceiver.java

package com.google.alarmclock;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.util.Log;

public class Alarm_Receiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent)
{
    Log.e("We are in the Receiver","yaa");

    //fetch extra strings from the intent
    String get_your_string = intent.getExtras().getString("extra");

    Log.e("What is the key?", get_your_string);

    //create an intent to the ringtone service
    Intent service_intent=new Intent(context,RingtonePlayingService.class);

    //pass the extra string from Main Activity to the Ringtone Playing Service,pass to the start service
    service_intent.putExtra("extra",get_your_string);

    //start the ringtone service
    context.startService(service_intent);
}
}

MainActivity.java

package com.google.alarmclock;

import android.annotation.TargetApi;
import android.app.AlarmManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.os.Build;
import android.os.Bundle;
import android.support.design.widget.FloatingActionButton;
import android.support.design.widget.Snackbar;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.view.View;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.Button;
import android.widget.TextView;
import android.widget.TimePicker;
import java.util.Calendar;

public class MainActivity extends AppCompatActivity {
//to make alarm manager
AlarmManager alarm_manager;
TimePicker alarm_timepicker;
TextView update_text;
Context context;
PendingIntent pending_intent;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
    setSupportActionBar(toolbar);
    this.context = this;

    //initialize alarm manager
    alarm_manager=(AlarmManager)getSystemService(ALARM_SERVICE);

    //initialize timepicker
    alarm_timepicker=(TimePicker)findViewById(R.id.timePicker);

    //initialize our text update box
    update_text=(TextView)findViewById(R.id.update_text);

    //create an instance of a calender
    final Calendar calendar= Calendar.getInstance();

    //create an intent to the Alarm Receiver class
    final Intent my_intent=new Intent(MainActivity.this,Alarm_Receiver.class);

    //initialize start buttons
    Button alarm_on=(Button)findViewById(R.id.start_alarm);
    //create an onClick listener to start the alarm
    alarm_on.setOnClickListener(new View.OnClickListener() {
        @TargetApi(Build.VERSION_CODES.M)
        @Override
        public void onClick(View view) {

            //setting calendar instance with the hour and minute that ve picked
            //on the time picker
            calendar.set(Calendar.HOUR_OF_DAY,alarm_timepicker.getCurrentHour());
            calendar.set(Calendar.MINUTE,alarm_timepicker.getCurrentMinute());

            //get the string values of the hour and minute
            int hour=alarm_timepicker.getCurrentHour();
            int minute=alarm_timepicker.getCurrentMinute();

            //converts the int value to strings
            String hour_string=String.valueOf(hour);
            String minute_string=String.valueOf(minute);

            //conver 24hour time to 12 hour time
            if(hour>12)
            {
                hour_string=String.valueOf(hour-12);
            }

            if(minute<10){
                minute_string="0" +String.valueOf(minute);
            }

            //method that changes the update text Textbox
            set_alarm_text("Alarm set to: "+hour_string+ ":" + minute_string);

            //put in extra string into my_intent
            //tells the clock that you pressed the "alarm on" button
            my_intent.putExtra("extra","alarm on");

            //create a pending intent that delays the intent
            //until the specified calendar time
            pending_intent=PendingIntent.getBroadcast(MainActivity.this,0,my_intent,PendingIntent.FLAG_UPDATE_CURRENT);

            //set the alarm manager
            alarm_manager.set(AlarmManager.RTC_WAKEUP,calendar.getTimeInMillis(),pending_intent);
        }
    });

    //initialize the stop button
    Button alarm_off=(Button)findViewById(R.id.end_alarm);
    //create an onClick listener to undo an alarm set
    alarm_off.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            //method that changes the update text Textbox
            set_alarm_text("Alarm off!");

            //cancel the alarm
            alarm_manager.cancel(pending_intent);

            //put extra string into my_intent
            //tells the clock that you pressed the "alarm off" button
            my_intent.putExtra("extra","alarm off");


            //stop the ringtone
            sendBroadcast(my_intent);
        }
    });
}

private void set_alarm_text(String output) {
    update_text.setText(output);

}

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    // Inflate the menu; this adds items to the action bar if it is present.
    getMenuInflater().inflate(R.menu.menu_main, menu);
    return true;
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    // Handle action bar item clicks here. The action bar will
    // automatically handle clicks on the Home/Up button, so long
    // as you specify a parent activity in AndroidManifest.xml.
    int id = item.getItemId();

    //noinspection SimplifiableIfStatement
    if (id == R.id.action_settings) {
        return true;
    }

    return super.onOptionsItemSelected(item);
}
}

RingtonePlayingService.java

  package com.google.alarmclock;

import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Intent;
import android.media.MediaPlayer;
import android.os.IBinder;
import android.support.annotation.Nullable;
import android.util.Log;
import android.widget.Toast;

import java.security.Provider;
import java.util.List;
import java.util.Map;


public class RingtonePlayingService extends Service {

MediaPlayer player=MediaPlayer.create(this, Settings.System.DEFAULT_RINGTONE_URI);
int startId;
boolean isRunning;

@Nullable
@Override
public IBinder onBind(Intent intent) {
    return null;
}

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

    Log.i("LocalService", "Received start id " + startId + ": " + intent);

    //fetch the extra string values
    String state = intent.getExtras().getString("extra");

    Log.e("Ringtone extra is",state);




    //this converts the extra strings from the intent
    //to start IDs, values 0 or 1
    assert state !=null;
    switch (state) {
        case "alarm on":
            startId = 1;
            break;
        case "alarm off":
            startId = 0;
            Log.e("Start ID is ",state);
            break;
        default:
            startId = 0;
            break;
    }


    //if else statements

    //if there is no music playing, and the user pressed "alarm on"
    //music should start playing
    if (!this.isRunning && startId==1)
    {
        Log.e("there is no music, ","and you want start");
        //create an instance of the media player
        player = MediaPlayer.create(this,R.raw.singer);
        player.start();

        this.isRunning=true;
        this.startId=0;

        //put the notification here,test it out
        //notification
        //set up the notification service
        NotificationManager notify_manager=(NotificationManager)
                getSystemService(NOTIFICATION_SERVICE);
        //set up an intent that goes to the Main Activity
        Intent intent_main_activity=new Intent(this.getApplicationContext(),MainActivity.class);

        //set up a pending intent
        PendingIntent pending_intent_main_activity=PendingIntent.getActivity(this,0,
                intent_main_activity,0);

        //make the notification parameters
       Notification notification_popup=new Notification.Builder(this)
                .setContentTitle("An alarm is going off!")
                .setContentText("Click Me")
                .setContentIntent(pending_intent_main_activity)
                .setAutoCancel(true)
                .setSmallIcon(R.mipmap.ic_launcher)
                .build();

        //set up the notification call command
        notify_manager.notify(0,notification_popup);

    }
    //if there is music playing, and the user pressed "alarm off"
    //music should stop playing
    else if (this.isRunning && startId == 0)
    {
        Log.e("there is music, ","and you want end");

        //stop the ringtone
        player.stop();
        player.reset();

        this.isRunning=false;
        this.startId=0;

    }
    //there are if user presses random buttons
    //just to bug-proof the app
    //if there is no music playing, and the user pressed "alarm off"
    //do nothing
    else if (!this.isRunning && startId == 0)
    {
        Log.e("there is no music, ","and you want end");

        //stop the ringtone
        this.isRunning=false;
        this.startId=0;

    }
    //if there is music playing and the user pressed "alarm on"
    //do nothing
    else if (this.isRunning && startId ==1)
    {
        Log.e("there is music, ","and you want start");

        this.isRunning =true;
        this.startId=1;

    }
    //can't think of anything else, just to catch the odd event
    else
    {
        Log.e("else ","somehow you reached ");

    }
    //if something is wrong, it can restart
    return START_NOT_STICKY;
}

@Override
public void onDestroy() {
    // Tell the user we stopped.
    Log.e("on Destroy called","ta da");
    super.onDestroy();
    this.isRunning=false;
    //Toast.makeText(this, "on Destroy called ", Toast.LENGTH_SHORT).show();
}

}

AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>

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

            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity>

    <receiver android:name=".Alarm_Receiver"/>
    <service android:name=".RingtonePlayingService"
        android:enabled="true"/>
</application>

build.gradle

apply plugin: 'com.android.application'

android {
    compileSdkVersion 24
    buildToolsVersion "24.0.2"
    defaultConfig {
        applicationId "com.google.alarmclock"
        minSdkVersion 16
        targetSdkVersion 24
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
}

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
        exclude group: 'com.android.support', module: 'support-annotations'
    })
    compile 'com.android.support:appcompat-v7:24.2.1'
    compile 'com.android.support:design:24.2.1'
    testCompile 'junit:junit:4.12'
}

this is the error when clicking the start button

Is this an error for the music?

java.lang.RuntimeException: Unable to start service com.google.alarmclock.RingtonePlayingService@1cba53b with Intent { cmp=com.google.alarmclock/.RingtonePlayingService (has extras) }: java.lang.IllegalArgumentException: Invalid notification (no valid small icon): Notification(pri=0 contentView=null vibrate=null sound=null defaults=0x0 flags=0x10 color=0x00000000 vis=PRIVATE)
                  at android.app.ActivityThread.handleServiceArgs(ActivityThread.java:3314)
                  at android.app.ActivityThread.-wrap21(ActivityThread.java)
                  at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1565)
                  at android.os.Handler.dispatchMessage(Handler.java:102)
                  at android.os.Looper.loop(Looper.java:154)
                  at android.app.ActivityThread.main(ActivityThread.java:6077)
                  at java.lang.reflect.Method.invoke(Native Method)
                  at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:865)
                  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:755)
               Caused by: java.lang.IllegalArgumentException: Invalid notification (no valid small icon): Notification(pri=0 contentView=null vibrate=null sound=null defaults=0x0 flags=0x10 color=0x00000000 vis=PRIVATE)
                  at android.app.NotificationManager.notifyAsUser(NotificationManager.java:306)
                  at android.app.NotificationManager.notify(NotificationManager.java:284)
                  at android.app.NotificationManager.notify(NotificationManager.java:268)
                  at com.google.alarmclock.RingtonePlayingService.onStartCommand(RingtonePlayingService.java:96)
                  at android.app.ActivityThread.handleServiceArgs(ActivityThread.java:3297)
                  at android.app.ActivityThread.-wrap21(ActivityThread.java) 
                  at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1565) 
                  at android.os.Handler.dispatchMessage(Handler.java:102) 
                  at android.os.Looper.loop(Looper.java:154) 
                  at android.app.ActivityThread.main(ActivityThread.java:6077) 
                  at java.lang.reflect.Method.invoke(Native Method) 
                  at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:865) 
                  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:755) 

当点击停止按钮时

E/AndroidRuntime: FATAL EXCEPTION: main
                  Process: com.google.alarmclock, PID: 2665
                  java.lang.NullPointerException: cancel() called with a null PendingIntent
                      at android.app.AlarmManager.cancel(AlarmManager.java:890)
                      at com.google.alarmclock.MainActivity.onClick(MainActivity.java:111)
                      at android.view.View.performClick(View.java:5609)
                      at android.view.View$PerformClick.run(View.java:22259)
                      at android.os.Handler.handleCallback(Handler.java:751)
                      at android.os.Handler.dispatchMessage(Handler.java:95)
                      at android.os.Looper.loop(Looper.java:154)
                      at android.app.ActivityThread.main(ActivityThread.java:6077)
                      at java.lang.reflect.Method.invoke(Native Method)
                      at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:865)
                      at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:755)

从你的 build.gradle 我可以看出为什么抛出 noSuchMethod 异常。 为了使用函数alarm_timepicker.getHour()。您的目标必须是最小 API 23,才能毫无问题地使用此功能。

您包装函数的注释并没有多大作用。它只是防止 warnings/errors 在编码过程中显示。当应用程序处于活动状态时,将抛出运行时异常,因为找不到该方法。

如果您想继续使用 timepicker.getHour(),请确保您在 build.gradle minSdkVersion 23 中指定。请注意,这将要求您将应用安装到设备上 运行 SDK 23.

如果您不想对 build.gradle 进行这样的修改,那么我建议您使用此功能。 timepicker.getCurrentHour() 和 timepicker.getCurrentMinute()。

为了解决与 java.lang.RuntimeException: Unable to start service com.google.alarmclock.RingtonePlayingService@1cba53b with Intent { cmp=com.google.alarmclock/.RingtonePlayingService (has extras) }: java.lang.IllegalArgumentException: Invalid notification (no valid small icon)

相关的问题 #2

确保为通知设置了一个小图标。通知对象要求您设置此 属性.

试试这个:

Notification notification_popup=new Notification.Builder(this)
                    .setContentTitle("An alarm is going off!")
                    .setContentText("Click Me")
                    .setContentIntent(pending_intent_main_activity)
                    .setAutoCancel(true)
                    .setSmallIcon(R.mipmap.ic_launcher)
                    .build();

一定要注意 .setSmallIcon 代码。您的项目可能没有 mipmap 文件夹。您可能需要更改为 R.drawable.ic_launcher

与声音有关。我真的不知道这是否是一个问题,但我会尽快更新。

谢谢。