点击上方“罗晓胜”,马上关注,您的支持对我帮助很大
上期文章
/ 前言 /
多媒体技术,官方定义是:多媒体是多种媒体的bai综合,一般包括du文本,声音和图像等多种zhi媒体形式。
手机上有很多丰富的多媒体技术,常见的如:相机、相册、音视频播放器,另外还有通知,NFC等,在手机功能日益强大的今天,发一段视频肯定要比语音传递的信息更加丰富,而语音传递的信息又要比文字丰富。
/ 正文 /
多媒体技术
使用通知Notification
通知(Notification)是Android 系统中比较有特色的一个功能,当某个应用程序希望向用户发出一些提示信息,而该应用程序又不在前台运行时,就可以借助通知来实现。发出一条通知后,手机最上方的状态栏中会显示一个通知的图标,下拉状态栏后可以看到通知的详细内容。
通知的用法
首先需要一个NotificationManager 来对通知进行管理,可以调用Context 的getSystemService()方法获取到。getSystemService()方法接收一个字符串参数用于确定获取系统的哪个服务, 这里我们传入Context.NOTIFICATION_SERVICE 即可。因此, 获取NotificationManager 的实例就可以写成:
NotificationManager manager = (NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE);
接下来需要创建一个Notification 对象,这个对象用于存储通知所需的各种信息,我们可以使用它的有参构造函数来进行创建。第一个参数用于指定通知的图标,比如项目的res/drawable 目录下有一张icon.png 图片,那么这里就可以传入R.drawable.icon。第二个参数用于指定通知的ticker 内容,当通知刚被创建的时候,它会在系统的状态栏一闪而过,属于一种瞬时的提示信息。第三个参数用于指定通知被创建的时间,以毫秒为单位,当下拉系统状态栏时,这里指定的时间会显示在相应的通知上。因此,创建一个Notification 对象就可以写成:
Notification notification = new Notification(R.drawable.icon, "This is ticker text",
System.currentTimeMillis());
创建好了Notification 对象后,我们还需要对通知的布局进行设定,这里只需要调用 Notification 的setLatestEventInfo()方法就可以给通知设置一个标准的布局。第一个参数是Context,这个没什么好解释的。第二个参数用于指定通知的标题内容,下拉系统状态栏就可以看到这部分内容。第三个参数用于指定通知的正文内容,同样下拉系统状态栏就可以看到这部分内容。第四个参数用于指定通知的点击效果,即PendingIntent,可以先传入null,。
notification.setLatestEventInfo(context, "This is content title", "This is content text", null);
以上工作都完成之后,只需要调用NotificationManager 的notify()方法就可以让通知显示出来了。notify()方法接收两个参数, 第一个参数是id,要保证为每个通知所指定的id 都是不同的。第二个参数则是Notification 对象,这里直接将我们刚刚创建好的Notification 对象传入即可。因此,显示一个通知就可以写成:
manager.notify(1, notification);
通知的点击效果PendingIntent
PendingIntent 从名字上看起来就和Intent 有些类似,它们之间也确实存在着不少共同点。比如它们都可以去指明某一个“意图”,都可以用于启动活动、启动服务以及发送广播等。不同的是,Intent 更加倾向于去立即执行某个动作,而PendingIntent 更加倾向于在某个合适的时机去执行某个动作。所以,也可以把PendingIntent 简单地理解为延迟执行的Intent。PendingIntent 的用法同样很简单,它主要提供了几个静态方法用于获取PendingIntent 的实例, getActivity()方法:启动一个活动 getBroadcast()方法:发送广播 还是getService()方法:启动服务
这几个方法所接收的参数都是相同的, 第一个参数依旧是Context,不用多做解释。第二个参数一般用不到,通常都是传入0 即可。第三个参数是一个Intent 对象,我们可以通过这个对象构建出PendingIntent 的“意图”。第四个参数用于确定PendingIntent 的行为,有FLAG_ONE_SHOT、FLAG_NO_CREATE、FLAG_CANCEL_CURRENT 和FLAG_UPDATE_CURRENT 这四种值可选,
因此,Notification 的setLatestEventInfo()方法的第四个参数传入PendingIntent 构建出一个延迟执行的“意图”,当用户点击这条通知时就会执行相应的逻辑。
代码如下:
NotificationManager manager = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);
Notification notification = new Notification(R.drawable.ic_launcher, "This is ticker text", System.currentTimeMillis());
Intent intent = new Intent(this, NotificationActivity.class);
PendingIntent pi = PendingIntent.getActivity(this, 0, intent,PendingIntent.FLAG_CANCEL_CURRENT);
notification.setLatestEventInfo(this, "This is content title","This is content text", pi);
manager.notify(1, notification);
通知取消 调用NotificationManager 的cancel()方法就可以取消通知了。当时我们给这条通知设置的id 就是1。因此,如果你想要取消哪一条通知,就在cancel()方法中传入该通知的id 就行了。
NotificationManager manager = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);
manager.cancel(1);
通知的高级技巧
-
播放音频
Uri soundUri = Uri.fromFile(new File("/system/media/audio/ringtones/
Basic_tone.ogg"));
notification.sound = soundUri;
-
设置震动
例:所以,如果想要让手机在通知到来的时候立刻振动1 秒,然后静止1 秒,再振动1 秒,代码就可以写成:
long[] vibrates = {0, 1000, 1000, 1000};
notification.vibrate = vibrates;
不过,想要控制手机振动还需要声明权限的。因此,我们还得编辑AndroidManifest.xml
文件,加入如下声明:
<uses-permission android:name="android.permission.VIBRATE" />
……
-
设置前置LED灯 ledARGB 用于控制LED 灯的颜色,一般有红绿蓝三种颜色可选。ledOnMS 用于指定LED 灯亮起的时长,以毫秒为单位。ledOffMS用于指定LED 灯暗去的时长,也是以毫秒为单位。flags 可用于指定通知的一些行为,其中就包括显示LED 灯这一选项。所以,当通知到来时,如果想要实现LED 灯以绿色的灯光一闪一闪的效果,就可以写成:notification.ledARGB = Color.GREEN; notification.ledOnMS = 1000; notification.ledOffMS = 1000; notification.flags = Notification.FLAG_SHOW_LIGHTS;
-
使用通知的默认效果 当然,如果你不想进行那么多繁杂的设置,也可以直接使用通知的默认效果,它会根据 当前手机的环境来决定播放什么铃声,以及如何振动,写法如下:notification.defaults = Notification.DEFAULT_ALL; 注意,以上所涉及的这些高级技巧都要在手机上运行才能看得到效果,模拟器是无法表现出振动、以及LED 灯闪烁等功能的。
接收和发送短信
接受短信
其实接收短信主要是利用了我们在第5 章学习过的广播机制。当手机接收到一条短信的时候,系统会发出一条值为android.provider.Telephony.SMS_RECEIVED 的广播, 这条广播里携带着与短信相关的所有数据。每个应用程序都可以在广播接收器里对它进行监听,收到广播时再从中解析出短信的内容即可。
1.创建一个广播接收器来接收系统发出的短信广播
class MessageReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
Bundle bundle = intent.getExtras();
Object[] pdus = (Object[]) bundle.get("pdus"); // 提取短信消息
SmsMessage[] messages = new SmsMessage[pdus.length];
for (int i = 0; i < messages.length; i++) {
messages[i] = SmsMessage.createFromPdu((byte[]) pdus[i]);
}
String address = messages[0].getOriginatingAddress(); // 获取发送方号码
String fullMessage = "";
for (SmsMessage message : messages) {
fullMessage += message.getMessageBody(); // 获取短信内容
}
sender.setText(address);
content.setText(fullMessage);
}
2.MessageReceiver 进行注册才能让它接收到短信广播,代码如下所示:
public class MainActivity extends Activity {
private TextView sender;
private TextView content;
private IntentFilter receiveFilter;
private MessageReceiver messageReceiver;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
sender = (TextView) findViewById(R.id.sender);
content = (TextView) findViewById(R.id.content);
receiveFilter = new IntentFilter();
receiveFilter.addAction("android.provider.Telephony.SMS_RECEIVED");
messageReceiver = new MessageReceiver();
registerReceiver(messageReceiver, receiveFilter);
}
@Override
protected void onDestroy() {
super.onDestroy();
unregisterReceiver(messageReceiver);
}
……
}
拦截短信
我们就已经知道,有序广播的传递是可以截断的,而系统发出的短信广播正是一条有序广播,因此
public class MainActivity extends Activity {
……
@Override
protected void onCreate(Bundle savedInstanceState) {
……
receiveFilter = new IntentFilter();
receiveFilter.addAction("android.provider.Telephony.SMS_RECEIVED");
receiveFilter.setPriority(100);
messageReceiver = new MessageReceiver();
registerReceiver(messageReceiver, receiveFilter);
}
……
class MessageReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
……
abortBroadcast();
}
}
}
发送短信
sendTextMessage()方法接收五个参数, 其中第一个参数用于指定接收人的手机号码, 第三个参数用于指定短信的内容, 第四个参数用于监控短信发送状态回执,例:PendingIntent pi = PendingIntent.getBroadcast(MainActivity.this, 0, sentIntent, 0); 其他的几个参数我们暂时用不到,直接传入null就可以了。
SmsManager smsManager = SmsManager.getDefault();
smsManager.sendTextMessage(to.getText().toString(), null,msgInput.getText().toString(), null, null);
权限申请:
<uses-permission android:name="android.permission.RECEIVE_SMS" />
<uses-permission android:name="android.permission. SEND_SMS" />
……
调用摄像头和相册
调用摄像头拍照
主要分为两步:1.启动相机程序 2.获取保存的图片
1.启动相机程序
private Uri imageUri;
// 创建File对象,用于存储拍照后的图片
File outputImage = new File(Environment.getExternalStorageDirectory(), "tempImage.jpg");
imageUri = Uri.fromFile(outputImage);
Intent intent = new Intent("android.media.action. IMAGE_CAPTURE");
intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);
startActivityForResult(intent, TAKE_PHOTO); // 启动相机程序
2.获取保存的图片(这里使用onActivityResult实现)
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
switch (requestCode) {
case TAKE_PHOTO:
if (resultCode == RESULT_OK) {
Intent intent = new Intent("com.android.camera.action.CROP");
intent.setDataAndType(imageUri, "image/*");
intent.putExtra("scale", true);
intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);
startActivityForResult(intent, CROP_PHOTO); // 启动裁剪程序
}
break;
case CROP_PHOTO:
if (resultCode == RESULT_OK) {
try {
Bitmap bitmap = BitmapFactory.decodeStream(getContentResolver().openInputStream(imageUri));
picture.setImageBitmap(bitmap); // 将裁剪后的照片显示出来
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
break;
default:
break;
}
}
权限:<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
从相册中选择照片
// 创建File对象,用于存储选择的照片
File outputImage = new File(Environment.
getExternalStorageDirectory(), "output_image.jpg");
try {
if (outputImage.exists()) {
outputImage.delete();
}
outputImage.createNewFile();
} catch (IOException e) {
e.printStackTrace();
}
imageUri = Uri.fromFile(outputImage);
Intent intent = new Intent("android.intent.action.GET_CONTENT");
intent.setType("image/*");
intent.putExtra("crop", true);
intent.putExtra("scale", true);
intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);
startActivityForResult(intent, CROP_PHOTO);
播放多媒体文件
播放音频
在Android 中播放音频文件一般都是使用MediaPlayer 类来实现的,下表列出了MediaPlayer 类中一些较为常用的控制方法。
setDataSource() 设置要播放的音频文件的位置。prepare() 在开始播放之前调用这个方法完成准备工作。start() 开始或继续播放音频。pause() 暂停播放音频。reset() 将MediaPlayer 对象重置到刚刚创建的状态。seekTo() 从指定的位置开始播放音频。stop() 停止播放音频。调用这个方法后的MediaPlayer 对象无法再播放音频。release() 释放掉与MediaPlayer 对象相关的资源。isPlaying() 判断当前MediaPlayer 是否正在播放音频。getDuration() 获取载入的音频文件的时长
1.初始化MediaPlayer()
private void initMediaPlayer() {
try {
File file = new File(Environment.getExternalStorageDirectory(),"music.mp3");
mediaPlayer.setDataSource(file.getPath()); // 指定音频文件的路径
mediaPlayer.prepare(); // 让MediaPlayer进入到准备状态
} catch (Exception e) {
e.printStackTrace();
}
}
2.开始播放
mediaPlayer.start(); // 开始播放
3.暂停
mediaPlayer.pause(); // 暂停播放
4.停止播放
mediaPlayer.reset(); // 停止播放
initMediaPlayer(); //停止后如需重新播放需要重新初始化
5.释放MediaPlayer
protected void onDestroy() {
super.onDestroy();
if (mediaPlayer != null) {
mediaPlayer.stop();
mediaPlayer.release();
}
}
播放视频
播放视频文件其实并不比播放音频文件复杂,主要是使用VideoView 类来实现的。主要有以下常用方法:
setVideoPath() 设置要播放的视频文件的位置。start() 开始或继续播放视频。pause() 暂停播放视频。resume() 将视频重头开始播放。seekTo() 从指定的位置开始播放视频。isPlaying() 判断当前是否正在播放视频。getDuration() 获取载入的视频文件的时长。
1.初始化VideoView
private void initVideoPath() {
File file = new File(Environment.getExternalStorageDirectory(),
"movie.3gp");
videoView.setVideoPath(file.getPath()); // 指定视频文件的路径
}
videoView.start(); // 开始播放
videoView.pause(); // 暂时播放
videoView.resume(); // 重新播放
2.释放VideoView
@Override
protected void onDestroy() {
super.onDestroy();
if (videoView != null) {
videoView.suspend();
}
}
/ 总结 /
本文主要讲了多媒体技术的相关介绍,多媒体是手机中很重要的技术之一,学好它你能做出很多酷炫的App效果。
往期推荐:
关注我的公众号,学习技术或投稿
长按上图,识别图中二维码即可关注