如今,手机在我们的生活中扮演着越来越重要的角色,各种娱乐方式都可以在手机上进行,众多的娱乐方式少不了强大的多媒体功能的支持,而Android在这方面也做得非常出色,它提供了一系列API,使得我们可以在程序中调用很多手机的多媒体资源,从而编写出更加丰富的应用程序。
1.使用通知
当我们发出一条通知后,在手机最上方的状态栏会显示一个通知的图标,下拉状态栏可以看到通知的详细内容。通知既可以在 Activity (这种场景比较少,因为一般只有程序进入后台的时候我们才需要使用通知)中创建,也可以在 BroadcastReceiver 和 Service 中创建。
1.通知的基本功能
创建通知:
Intent intent = new Intent(Settings.ACTION_WIFI_SETTINGS); PendingIntent pi = PendingIntent.getActivity(this, 0 ,intent, 0);// 首先需要获得 NotificationManager 来对通知进行管理NotificationManager manager = (NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE);// 使用一个 Builder 构造器来创建 Notification 对象Notification notification = new NotificationCompat.Builder(this) .setContentTitle("This is content title") .setContentText("This is content text") .setWhen(System.currentTimeMillis()) // 指定通知被创建的时间,会显示在下拉状态栏相应的通知上 .setSmallIcon(R.drawable.small_icon) .setLargeIcon(BitmapFactory.decodeResource(getResources(), R.drawable.large_icon)) .setContentIntent(pi) // 构建一个延迟执行的"意图" .setAutoCancel(true) // 点击通知的时候自动取消通知栏图标,或者调用 manager.cancel(1); 取消 /* 自定义个性设置部分 start */ // 在通知发出的时候播放一段音频 .setSound(RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION)) //.setSound(Uri.fromFile(new File("路径"))) // 自定义音频 // 设置手机振动,单位毫秒,需要权限 <uses-permission android:name="android.permission.VIBRATE"/> .setVibrate(new long[]{0, 1000, 1000, 1000}) .setLights(Color.GREEN, 1000, 1000) // 设置LED灯绿色闪烁 // .setDefaults(NotificationCompat.DEFAULT_ALL) // 不进行自定义个性设置,全部默认系统设置 /* 自定义个性设置部分 end */ .build();// 参数1:保证为每个通知所指定的id都是不同的; 参数2:Notification对象manager.notify(1, notification);
PendingIntent 对比 Intent,更倾向于在某个合适的时机去执行某个动作,所以也可以称为 延迟执行的 Intent。PendingIntent提供了几个静态方法用于获取PendingIntent的实例,可根据需求选择使用,getActivity()、getBroadcast()、getService()。
运行程序,状态栏会显示一个通知的图标,并且下拉状态栏可以看到通知的详细内容:
2.通知的高级功能
继续观察 NotificationCompat.Builder 这个类,发现很多API是没有使用过的。例如 setStyle() 方法允许我们构建出富文本的通知内容,setStyle() 方法接受一个 NotificationCompat.Style 参数,这个参数就是用来构建具体的富文本信息的。还包含 setPriority() 方法用于设置通知的重要程度。
1)通知中显示长文字效果
Notification notification = new NotificationCompat.Builder(this) ... .setStyle(new NotificationCompat.BigTextStyle().bigText("Android Studio is Android's " + "official IDE. It is purpose built for Android to accelerate your development " + "and help you build the highest-quality apps for every Android device.")) .build();
2)通知中显示大图片效果
Notification notification = new NotificationCompat.Builder(this) ... .setStyle(new NotificationCompat.BigPictureStyle().bigPicture( BitmapFactory.decodeResource(getResources(), R.drawable.large_icon))) .build();
3)通知的重要程度
Notification notification = new NotificationCompat.Builder(this) ... .setPriority(NotificationCompat.PRIORITY_MAX) .build();
setPriority() 方法参数一共有5个常量值可选:
PRIORITY_MIN:最低,特定场景中使用,比如用户下拉状态栏的时候 PRIORITY_LOW:较低,系统可能会将这类通知缩小或改变其显示的顺序,靠后显示 PRIORITY_DEFAULT:默认 PRIORITY_HIGH:较高,系统可能会将这类通知方法或改变其显示的顺序,靠前显示 PRIORITY_MAX:最高,弹出横幅,让用户立刻看到
运行程序可以看到弹出横幅:
2.调用摄像头和相册
调用摄像头和相册的功能实在是太常见了,相信很多人已经很熟了,这里直接以代码给出:
public class MainActivity extends AppCompatActivity { public static final int TAKE_PHOTO = 1; public static final int CHOOSE_PHOTO = 2; private ImageView picture; private Uri imageUri; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); picture = (ImageView) findViewById(R.id.picture); // 调用摄像头拍照的点击事件 findViewById(R.id.take_photo).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { // 创建File对象,用于存储拍照后的图片,到手机SD卡的应用关联缓存目录 // 应用关联缓存目录: 指SD卡专门用于存放当前应用缓存数据的位置 // 应用关联缓存目录的具体路径: /sdcard/Android/data/< package name>/cache File outputImage = new File(getExternalCacheDir(), "output_image.jpg"); try { if (outputImage.exists()) { outputImage.delete(); } outputImage.createNewFile(); } catch (IOException e) { e.printStackTrace(); } if (Build.VERSION.SDK_INT < 24) { imageUri = Uri.fromFile(outputImage); } else { // 从Android7.0开始,直接使用本地真实路径的Uri被认为是不安全的,会抛出一个 // FileUriExposedException异常,而FileProvider使用了和内容提供器类似的机制来对数据 // 进行保护,可以选择性地将封装过的Uri共享给外部,从而提高了应用的安全性。 imageUri = FileProvider.getUriForFile(MainActivity.this, "com.demo.camera.fileprovider", outputImage); } Intent intent = new Intent("android.media.action.IMAGE_CAPTURE"); // 启动相机程序 intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri); // 指定图片的输出地址 startActivityForResult(intent, TAKE_PHOTO); } }); // 调用相册的点击事件 findViewById(R.id.choose_from_album).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { // 运行时权限处理,动态申请 WRITE_EXTERNAL_STORAGE 这个危险权限(SD卡的读写权限) if (ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) { ActivityCompat.requestPermissions(MainActivity.this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 1); } else { openAlbum(); } } }); } /** * 打开相册 */ private void openAlbum() { Intent intent = new Intent("android.intent.action.GET_CONTENT"); intent.setType("image/*"); startActivityForResult(intent, CHOOSE_PHOTO); // 打开相册 } /** * 申请权限的回调 */ @Override public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) { switch (requestCode) { case 1: if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { openAlbum(); } else { Toast.makeText(this, "You denied the permission", Toast.LENGTH_SHORT).show(); } break; default: } } /** * @param requestCode 请求码 * @param resultCode 结果码 * @param data 返回的数据 */ @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { switch (requestCode) { // 调用摄像头 case TAKE_PHOTO: if (resultCode == RESULT_OK) { try { // 将拍摄的照片显示出来 Bitmap bitmap = BitmapFactory.decodeStream(getContentResolver() .openInputStream(imageUri)); picture.setImageBitmap(bitmap); } catch (Exception e) { e.printStackTrace(); } } break; // 调用相册 case CHOOSE_PHOTO: if (resultCode == RESULT_OK) { // 判断手机系统版本号 if (Build.VERSION.SDK_INT >= 19) { // 4.4及以上系统使用这个方法处理图片 handleImageOnKitKat(data); } else { // 4.4以下系统使用这个方法处理图片 handleImageBeforeKitKat(data); } } break; default: break; } } /** * 调用相册 Android4.4及以上系统使用这个方法处理图片 * 从4.4开始,选取相册中的图片不再返回图片的真实Uri了,而是一个封装过的Uri,所以需要解析。 */ @TargetApi(19) private void handleImageOnKitKat(Intent data) { String imagePath = null; Uri uri = data.getData(); Log.d("TAG", "handleImageOnKitKat: uri is " + uri); if (DocumentsContract.isDocumentUri(this, uri)) { // 如果是document类型的Uri,则通过document id处理 String docId = DocumentsContract.getDocumentId(uri); if ("com.android.providers.media.documents".equals(uri.getAuthority())) { String id = docId.split(":")[1]; // 解析出数字格式的id String selection = MediaStore.Images.Media._ID + "=" + id; imagePath = getImagePath(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, selection); } else if ("com.android.providers.downloads.documents".equals(uri.getAuthority())) { Uri contentUri = ContentUris.withAppendedId( Uri.parse("content://downloads/public_downloads"), Long.valueOf(docId)); imagePath = getImagePath(contentUri, null); } } else if ("content".equalsIgnoreCase(uri.getScheme())) { // 如果是content类型的Uri,则使用普通方式处理 imagePath = getImagePath(uri, null); } else if ("file".equalsIgnoreCase(uri.getScheme())) { // 如果是file类型的Uri,直接获取图片路径即可 imagePath = uri.getPath(); } displayImage(imagePath); // 根据图片路径显示图片 } /** * 调用相册 Android4.4以下系统使用这个方法处理图片 */ private void handleImageBeforeKitKat(Intent data) { Uri uri = data.getData(); String imagePath = getImagePath(uri, null); displayImage(imagePath); } /** * 调用相册 通过Uri获取图片路径 */ private String getImagePath(Uri uri, String selection) { String path = null; // 通过Uri和selection来获取真实的图片路径 Cursor cursor = getContentResolver().query(uri, null, selection, null, null); if (cursor != null) { if (cursor.moveToFirst()) { path = cursor.getString(cursor.getColumnIndex(MediaStore.Images.Media.DATA)); } cursor.close(); } return path; } /** * 调用相册 根据图片路径显示图片 */ private void displayImage(String imagePath) { if (imagePath != null) { Bitmap bitmap = BitmapFactory.decodeFile(imagePath); picture.setImageBitmap(bitmap); } else { Toast.makeText(this, "failed to get image", Toast.LENGTH_SHORT).show(); } } }
还要记得在 AndroidManifest.xml 中申请权限和注册 FileProvider:
<!-- 兼容性权限声明,Android4.4之前需要的权限声明,从4.4开始后不再需要此权限声明 --><uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />...<provider android:name="android.support.v4.content.FileProvider" android:authorities="com.demo.camera.fileprovider" android:exported="false" android:grantUriPermissions="true"> <meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/file_paths" /></provider>
其中 xml/file_paths 为:
<?xml version="1.0" encoding="utf-8"?><paths xmlns:android="http://schemas.android.com/apk/res/android"> <!-- external-path用来指定Uri共享的,name属性随便填,path属性的值表示共享的具体路径,null表示整个SD卡 --> <external-path name="my_images" path="" /></paths>
实际工作中存在图片大的问题,直接加载进内存中有可能导致程序崩溃,更好的做法是根据项目的需求先对照片进行适当的压缩,然后再加载进内存中。
3.播放多媒体文件
手机上最常见的休闲方式毫无疑问就是听音乐和看电影了,Android则提供了完整的API,使得开发者可以很容易的编写出一个简易的音频或视频播放器。
1.播放音频
Android中播放音频文件一般都是使用的 MediaPlayer 类来实现的,MediaPlayer 主要有以下方法:
方法名 | 功能描述 |
---|---|
setDataSource() | 设置要播放音频文件的位置 |
prepare() | 在开始播放之前调用这个方法完成准备工作 |
start() | 开始或继续播放 |
pause() | 暂停播放 |
reset() | 重置到刚刚创建的状态 |
seekTo() | 从指定位置开始播放 |
stop() | 停止播放,调用后MediaPlayer对象无法再播放音频 |
release() | 释放与MediaPlayer对象相关的资源 |
isPlaying() | 判断当前MediaPlayer是否正在播放音频 |
getDuration() | 获取载入的音频文件的时长 |
首先我们需要动态申请 WRITE_EXTERNAL_STORAGE 这个危险权限,并初始化 MediaPlayer对象:
// 需声明权限 <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />private MediaPlayer mMediaPlayer = new MediaPlayer();@Overrideprotected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // 运行时权限处理,动态申请 WRITE_EXTERNAL_STORAGE 这个危险权限(SD卡的读写权限) if (ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) { ActivityCompat.requestPermissions(MainActivity.this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 1); } else { initMediaPlayer(); } }/** * 初始化MediaPlayer */private void initMediaPlayer() { try { File file = new File(Environment.getExternalStorageDirectory(), "music.mp3"); mMediaPlayer.setDataSource(file.getPath()); mMediaPlayer.prepare(); } catch (IOException e) { e.printStackTrace(); } }
下来我们就可以对音频文件进行操作了:
// 开始播放if (!mMediaPlayer.isPlaying()) { mMediaPlayer.start(); }/* // 暂停播放 if (mMediaPlayer.isPlaying()) { mMediaPlayer.pause(); } // 停止播放 if (mMediaPlayer.isPlaying()) { mMediaPlayer.reset(); initMediaPlayer(); }*/
最后要在 onDestroy() 方法中停止音频并释放资源:
@Overrideprotected void onDestroy() { super.onDestroy(); if (mMediaPlayer != null) { mMediaPlayer.stop(); mMediaPlayer.release(); } }
2.播放视频
播放视频主要是使用 VideoView 类来实现的,VideoView 主要有以下方法:
方法名 | 功能描述 |
---|---|
setVideoPath() | 设置要播放视频文件的位置 |
start() | 开始或继续播放 |
pause() | 暂停播放 |
resume() | 将视频从头开始播放 |
seekTo() | 从指定位置开始播放 |
suspend() | 释放占用的资源 |
isPlaying() | 判断当前是否正在播放音频 |
getDuration() | 获取载入的视频文件的时长 |
首先我们需要动态申请 WRITE_EXTERNAL_STORAGE 这个危险权限,并初始化 VideoView对象:
// 需声明权限 <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />private VideoView mVideoView;@Overrideprotected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mVideoView = (VideoView) findViewById(R.id.video_view); // 运行时权限处理,动态申请 WRITE_EXTERNAL_STORAGE 这个危险权限(SD卡的读写权限) if (ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) { ActivityCompat.requestPermissions(MainActivity.this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 1); } else { initVideoView(); } }/** * 初始化Video */private void initVideoView() { File file = new File(Environment.getExternalStorageDirectory(), "video.mp4"); mVideoView.setVideoPath(file.getPath()); }
下来我们就可以对视频文件进行操作了:
// 开始播放if (!mVideoView.isPlaying()) { mVideoView.start(); }/* // 暂停播放 if (mVideoView.isPlaying()) { mVideoView.pause(); } // 重新播放 if (mVideoView.isPlaying()) { mVideoView.resume(); }*/
最后要在 onDestroy() 方法中释放占用的资源:
@Overrideprotected void onDestroy() { super.onDestroy(); if (mVideoView != null) { mVideoView.suspend(); } }
另外需要注意的是,VideoView并不是一个万能的视频播放工具类,它在视频格式的支持以及播放效率方面都存在着一些不足。不过对于一些游戏片头动画、视频宣传还是绰绰有余的。
共同学习,写下你的评论
评论加载中...
作者其他优质文章