为了账号安全,请及时绑定邮箱和手机立即绑定

Android Primer——使用通知和手机多媒体功能

标签:
Android

如今,手机在我们的生活中扮演着越来越重要的角色,各种娱乐方式都可以在手机上进行,众多的娱乐方式少不了强大的多媒体功能的支持,而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()。

运行程序,状态栏会显示一个通知的图标,并且下拉状态栏可以看到通知的详细内容:

5b8281c70001a80203500276.jpg

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:最高,弹出横幅,让用户立刻看到

运行程序可以看到弹出横幅:

5b8281c800011c9003500139.jpg

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并不是一个万能的视频播放工具类,它在视频格式的支持以及播放效率方面都存在着一些不足。不过对于一些游戏片头动画、视频宣传还是绰绰有余的。

原文链接:http://www.apkbus.com/blog-856294-76954.html

点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
微信客服

购课补贴
联系客服咨询优惠详情

帮助反馈 APP下载

慕课网APP
您的移动学习伙伴

公众号

扫描二维码
关注慕课网微信公众号

举报

0/150
提交
取消