利用MediaPlayer来实现Notification通知铃声

来源:互联网 发布:python fix 编辑:程序博客网 时间:2024/05/06 13:53

  最近一直有收到客户反馈,通知铃声不响,这让我很郁闷啊,因为那块地方是我来公司前的大神写的,看了一下他是用noticication设置的铃声,我以前的时候发现qq好像并不是用noticication来设置的,因为我在调音量的时候发现他调用的媒体的声音!
于是呼,我就百度有没有用媒体做铃声提示的,果然有!

  首先,整理一下Notification的功能与用法

  Notification是显示在手机状态栏的通知——手机状态栏位于手机屏幕的最上方,那里一般显示了手机当前的网络状态、电池状态、时间等。Notification所代表的是一种具有全局效果的通知,程序一般通过NotificationManger服务来发送Notification。
  Android3.0增加Notification.Builder类,通过该类允许开发者更轻松地创建Notification对象。Notification.Builder提供了如下常用方法。
  setDefaults():设置通知LED灯、音乐、震动等。
  setAutoCancel():设置点击通知后,让通知自动取消。
  setContentTitle():设置通知栏标题。
  setContentText():设置通知内容。
  setSmallIcon():设置通知图标。
  setLargeIcon():设置通知大图标。
  setTick():设置通知在状态栏的提示文本。
  setContentIntent():设置点击通知后将要启动的程序组件对应的 PendingIntent。

  发送Notification很简单,按如下步骤即可。
  
1、调用getSystemService(NOTIFICATION_SERVICE)方法获取系统的NotificationManger服务。
2、通过构造器创建一个Notification对象。
3、为Notification设置各种属性。
4、通过NotificationManger发送Notification。

  此外,setDefaults()方法为Notification设置了声音提示、振动提示、闪光灯等。该属性支持如下属性值。

DEFAULT_SOUND:设置使用默认声音。
DEFAULT_VIBRATE:设置默认振动。
DEFAULT_LIGHTS:设置使用默认闪光灯。
ALL:设置使用默认声音、振动、闪光灯。
  如果不想默认设置,也可以使用如下代码:
  //设置自定义声音
  setSound(Uri.parse(“file:///sdcard/click.mp3”));
  //设置自定义振动,实现效果:延迟0ms,然后振动50ms,在延迟100ms,接着在振动150ms。
  setVibrate(new long[]{0, 50, 100, 150});
  注意:需要添加权限
  android.permission.FLASHLIGHT //闪光灯
  android.permission.VIBRATE //振动

  在写demo前,还需要了解一下PendingIntent这个东东。
  pendingIntent字面意义:等待的,未决定的Intent。
  pendingIntent对象,使用方法类的静态方法 :
     getActivity(Context, int, Intent, int)——->跳转到一个activity组件
     getBroadcast(Context, int, Intent, int)——>打开一个广播组件
     getService(Context, int, Intent, int)——–>打开一个服务组件。
  pendingIntent是一种特殊的Intent。主要的区别在于Intent的执行立刻的,而pendingIntent的执行不是立刻的。pendingIntent执行的操作实质上是参数传进来的Intent的操作,但是使用pendingIntent的目的在于它所包含的Intent的操作的执行是需要满足某些条件的。
intent英文意思是意图,pending表示即将发生或来临的事情。
PendingIntent这个类用于处理即将发生的事情。比如在通知Notification中用于跳转页面,但不是马上跳转。

  PendingIntent用于描述Intent及其最终的行为.
  你可以通过getActivity(Context context, int requestCode, Intent intent, int flags)系列方法从系统取得一个用于启动一个Activity的PendingIntent对象,

  可以通过getService(Context context, int requestCode, Intent intent, int flags)方法从系统取得一个用于启动一个Service的PendingIntent对象

  可以通过getBroadcast(Context context, int requestCode, Intent intent, int flags)方法从系统取得一个用于向BroadcastReceiver的Intent广播的PendingIntent对象

  返回的PendingIntent可以递交给别的应用程序,然后继续处理。这里的话你可以稍后才处理PendingIntent中描述的Intent及其最终行为。

  当你把PendingIntent递交给别的程序进行处理时,PendingIntent仍然拥有PendingIntent原程序所拥有的权限(with the same permissions and identity).当你从系统取得一个PendingIntent时,一定要非常小心才行。比如,通常,如果Intent目的地是你自己的component(Activity/Service/BroadcastReceiver)的话,你最好采用在Intent中显示指定目的component名字的方式,以确保Intent最终能发到目的,否则Intent最后可能不知道发到哪里了。一个PendingIntent就是Android系统中的一个token(节点,这个应该是Linux或C\C++用语)的一个对象引用,它描述了一些将用于retrieve的数据(这里,这些数据描述了Intent及其最终的行为)。

  这就意味着即使PendingIntent原进程结束了的话, PendingIntent本身仍然还存在,可在其他进程(PendingIntent被递交到的其他程序)中继续使用.如果我在从系统中提取一个PendingIntent的,而系统中有一个和你描述的PendingIntent对等的PendingInent, 那么系统会直接返回和该PendingIntent其实是同一token的PendingIntent,而不是一个新的token和PendingIntent。然而你在从提取PendingIntent时,通过FLAG_CANCEL_CURRENT参数,让这个老PendingIntent的先cancel()掉,这样得到的pendingInten和其token的就是新的了。

  通过FLAG_UPDATE_CURRENT参数的话,可以让新的Intent会更新之前PendingIntent中的Intent对象数据,例如更新Intent中的Extras。另外,我们也可以在PendingIntent的原进程中调用PendingIntent的cancel ()把其从系统中移除掉。

package com.nicole.test.notifictiontest;import android.app.Notification;import android.app.NotificationManager;import android.app.PendingIntent;import android.content.Context;import android.content.Intent;import android.net.Uri;/** * Created by Nicole on 2016/10/23. */public class NotificationUtil {    private NotificationManager notificationManager;    private Context context;    public NotificationUtil(Context context){        this.context = context;        notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);    }    public NotificationManager getNotificationManager(){        return notificationManager;    }    public Notification getNotification(){        Intent intent = new Intent(context, SecondActivity.class);        PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, 0);        Notification notification = new Notification.Builder(context)                .setAutoCancel(true)                .setTicker("有新消息")                .setSmallIcon(R.mipmap.ic_launcher)                .setContentTitle("一条新通知")                .setContentText("~~~~~~~")                .setVibrate(new long[]{0, 50, 100, 150})//                .setDefaults(Notification.DEFAULT_LIGHTS|Notification.DEFAULT_SOUND)                .setSound(Uri.parse("android.resource://" + MyApplication.getInstance().getPackageName() + "/" + R.raw.message))                .setWhen(System.currentTimeMillis())                .setContentIntent(pendingIntent)                .build();        return notification;    }}

  测试下来结果总结一下,设置了Notification.DEFAULT_LIGHTS,闪光灯好像毫无反应啊!这是为啥。。。我不造。。。然后同时设置了Notification.DEFAULT_SOUND和自定义setSound,系统只会响默认的,要自定义setSound,那就不要setDefaults(Notification.DEFAULT_SOUND)。
  


  接下来利用MediaPlayer来实现通知铃声

  首先,先来了解一下MediaPlayer是怎么用的。使用MediaPlayer播放音频十分简单,当程序控制MediaPlayer对象装载音频完成之后,程序可以调用MediaPlayer的如下三个方法进行播放控制。
  start():开始或恢复播放
  stop():停止播放
  pause():暂停播放
  
  为了让MediaPlayer来装在制定音频文件,MediaPlayer提供了如下简单的静态方法。
static MediaPlayer creat(Context context, Uri uri):从指定Uri来装载音频文件,并返回新创建的MediaPlayer对象。
static MediaPlayer creat(Context context, int resid):从resid资源ID对应的资源文件中装载音频文件,并返回新创建的MediaPlayer对象。
  上面这两个方法用起来非常方便,但这两个方法每次都会返回新创建的MediaPlayer对象,如果程序需要使用MediaPlayer循环播放多个音频文件,使用MediaPlayer的静态create方法就不太合适了,此时可通过MediaPlayer的setDataSource()方法来装载指定的音频文件。
  
  MediaPlayer提供了如下方法来指定装载相应的音频文件。
setDataSource(String path):指定装载path路径所代表的文件。
setDataSource(FileDescriptor fd, long offset, long length):指定装载fd所代表的文件中从offset开始,长度为length的文件内容。
setDataSource(FileDescriptor fd):指定装载fd所代表的文件。
setDataSource(Context context, Uri uri):指定装载uri所代表的文件。
  
  执行上面所示的setDataSource()方法之后,MediaPlayer并未真正去装载那些音频文件,还需要调用MediaPlayer的prepare()方法去准备音频,所谓“准备”,就是让MediaPlayer真正去装载音频文件。
  
  因此,使用已有的MediaPlayer对象装载“下一首”歌曲的代码模块:

player.reset();player.setDataSource(“…”);player.prepare();player.start();

  
  除此之外,MediaPlayer还提供了一些绑定事件监听器的方法,用于监听MediaPlayer播放过程中所发生的特定事件,绑定事件监听器的方法如下。
setOnCompletionListener(MediaPlayer.OnCompletionListener listener):为MediaPlayer的播放完成事件绑定事件监听器。
setOnErrorListener(MediaPlayer.OnErrorListener listener):为MediaPlayer的播放错误事件绑定事件监听器。
setOnPreparedListener(MediaPlayer.OnPreparedListener listener):当MediaPlayer调用prepare()方法时触发该监听器。
setOnSeekCompleteListener(MediaPlayer.OnSeekCompleteListener listener):当MediaPlayer调用seek()方法时触发该监听器。

接下来是我写的一个demo:

package com.nicole.test.notifictiontest;import android.app.Notification;import android.app.NotificationManager;import android.app.PendingIntent;import android.content.Context;import android.content.Intent;import android.media.AudioManager;import android.media.MediaPlayer;import android.net.Uri;/** * Created by Nicole on 2016/10/23. */public class NotificationUtil {    private NotificationManager notificationManager;    private static Context context;    private static MediaPlayer player ;    public NotificationUtil(Context context){        this.context = context;        notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);    }    public NotificationManager getNotificationManager(){        return notificationManager;    }    public Notification getNotification(){        Intent intent = new Intent(context, SecondActivity.class);        PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, 0);        Notification notification = new Notification.Builder(context)//                .setAutoCancel(true)                .setTicker("有新消息")                .setSmallIcon(R.mipmap.ic_launcher)                .setContentTitle("一条新通知")                .setContentText("~~~~~~~")                .setVibrate(new long[]{1500, 500, 1500, 500})                   .setWhen(System.currentTimeMillis())                .setContentIntent(pendingIntent)                .setPriority(Notification.PRIORITY_MAX)                .build();        // 声音一直响到用户相应,就是通知会一直响起,直到你触碰通知栏的时间就会停止        // 创建后在状态栏中通知的内容        notification.flags |= Notification.FLAG_INSISTENT;        return notification;    }    public void voice(){        if(!Config.voiceIsRunning){            Config.voiceIsRunning = true;        } else {            return;        }        try {            Uri alert = Uri.parse("android.resource://" + MyApplication.getInstance().getPackageName() + "/" + R.raw.message);            player = new MediaPlayer();            player.setDataSource(context, alert);            if (player.isPlaying()) {                player.reset();  // 到初始化状态,这里需要判断是否正在响铃,如果直接在开启一次会出现2个铃声一直循环响起,您不信可以尝试            } else if (!player.isPlaying()) {                ring();            }        } catch (Exception e) {            e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.        }    }    private MediaPlayer ring() throws Exception {        final AudioManager audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);        if (audioManager.getStreamVolume(AudioManager.STREAM_NOTIFICATION) != 0) {            player.setAudioStreamType(AudioManager.STREAM_NOTIFICATION);            player.setLooping(true);            player.prepare();            player.start();        }        return player;    }    public void cancelNotification(){        notificationManager.cancel(MyApplication.NOTIFICATION_ID);        if(player!=null && player.isPlaying()){            player.stop();            player.release();        }        Config.voiceIsRunning = false;    }}

主要代码就是这样的,现在我把这两种通知做在两个按钮上,在托人在那些收到通知没声音的手机上试试看,是两个都不行呢,还是用MediaPlayer的可以,坐等中。。。

我滴个天。。。测下来都会响,那些说收到通知没声音的人!竟然又说法了!泪流满面的我! _ ( :3 」 ) _

0 0