内容提供器和多媒体

标签: Anroid


1.内容提供器简介

Content Provider用于在不同的应用程序间实现数据共享。

1.1运行时权限

  1. 判断用户是否已经授权。ContextCompat.checkSelfPermission方法的返回值是否为PackageManager.pERMISSSION_GRANTED
  2. 没有得到授权,需要申请授权。requestPermissions方法,参数Activity实例,字符串数组存放权限名,以及请求码
  3. 用户处理弹出的权限申请对话框
  4. 回调onRequestPermissionsResult方法,判断授权结果

    if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_CONTACTS) != PackageManager.PERMISSION_GRANTED) {
        ActivityCompat.requestPermissions(this, new String[]{ Manifest.permission.READ_CONTACTS }, 1);
    } else {
        method();
    }
    
    
    public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
        switch (requestCode) {
            case 1:
                if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                    method();
                } else {
                    Toast.makeText(this, "You denied the permission", Toast.LENGTH_SHORT).show();
                }
                break;
            default:
        }
    }
    

    1.2访问其它程序的数据

当程序通过内容提供器给其数据提供外部访问接口,其它程序都能访问这些数据。通过Contextd的getContextResolver的几个方法完成查询、添加、删除和更新数据的操作。不同于数据库操作需要提供表名,这里需要的是内容Uri,如content://com.example.app.provider/table1

Uri uri = Uri.parse("content://com.example.app.provider/table1");

查询

query5个参数,分别是uri,列名,where约束条件,具体值,查询结果排序方式

Uri uri = Uri.parse("content://com.example.databasetest.provider/book");
Cursor cursor = getContentResolver().query(uri, null, null, null, null);
if (cursor != null) {
        while (cursor.moveToNext()) {
            String name = cursor.getString(cursor. getColumnIndex("name"));
            String author = cursor.getString(cursor. getColumnIndex("author"));
            int pages = cursor.getInt(cursor.getColumnIndex ("pages"));
            double price = cursor.getDouble(cursor. getColumnIndex("price"));
        }
        cursor.close();
}

更新

update方法中后2个参数相当于SQL中的where子句的作用

     Uri uri = Uri.parse("content://com.example.databasetest.provider/book/" + newId);
     ContentValues values = new ContentValues();
    values.put("name", "A Storm of Swords");
    values.put("pages", 1216);
    values.put("price", 24.05);
    getContentResolver().update(uri, values, null, null);

删除

Uri uri = Uri.parse("content://com.example.databasetest.provider/book/" + newId);
getContentResolver().delete(uri, null, null);

插入

Uri uri = Uri.parse("content://com.example.databasetest.provider/book");
ContentValues values = new ContentValues();
values.put("name", "A Clash of Kings");
values.put("author", "George Martin");
values.put("pages", 1040);
values.put("price", 55.55);
Uri newUri = getContentResolver().insert(uri, values);
newId = newUri.getPathSegments().get(1);

1.3创建内容提供器

步骤

  1. 继承ContentProvider新建内容提供器类,重写6个抽象方法

    • onCreate:只有ContentResolver访问此程序数据时,初始化内容提供器时调用
    • query:从内容提供器重查询数据
    • insert:向内容提供器中添加数据
    • update:更新内容提供器中的数据
    • delete:从内容提供器中删除数据
    • getType:根据内容URI返回MIME类型
  2. UriMatcher中的addURI方法,传递authority、path和自定义代码

    在query,insert,update,delete,getType方法中,当调用UriMatcher的match方法,传入Uri对象,返回值是某个自定义的代码,确定访问数据

  3. 因为需要对数据库操作,在每个方法内都要获取到SQLiteDatabase对象,通过SQLiteOpenHelper对象获取。调用数据库对象的方法进行数据操作。

    private MyDatabaseHelper dbHelper;
    SQLiteDatabase db = dbHelper.getReadableDatabase();
    

    1.4总结

    即一个程序中有数据库相关类,提供外部访问的ContentProvider类,其它程序才能通过getContentResolver访问到数据。

2.多媒体

2.1通知

2.1.1通知基本用法

  1. NotificationManager对通知进行管理,调用Context的getSystemService获取

    NotificationManager manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
    
  2. 使用Builder构造器创建Notification对象,通过在最终得到build方法前连缀设置方法创建丰富的Notification对象

    Notification notification = nw NotificationCompat.Builder(context).build();
    

    通知丰富后

    setContentTitle("This is content title")
                    .setContentText("This is content text")
                    .setWhen(System.currentTimeMillis())
                    .setSmallIcon(R.mipmap.ic_launcher)
                    .setLargeIcon(BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher))
                    .setContentIntent(pi)
            //        .setSound(Uri.fromFile(new File("/system/media/audio/ringtones/Luna.ogg")))
            //        .setVibrate(new long[]{0, 1000, 1000, 1000})
            //        .setLights(Color.GREEN, 1000, 1000)
                    .setDefaults(NotificationCompat.DEFAULT_ALL)
            //        .setStyle(new NotificationCompat.BigTextStyle().bigText("Learn how to build notifications, send and sync data, and use voice actions. Get the official Android IDE and developer tools to build apps for Android."))
                    .setStyle(new NotificationCompat.BigPictureStyle().bigPicture(BitmapFactory.decodeResource(getResources(), R.drawable.big_image)))
                    .setPriority(NotificationCompat.PRIORITY_MAX)
                    .build();
            manager.notify(1, notification);
    
  3. 调用NotificationManager对象的notify方法显示通知

    manager.notify(1, notification);
    
  4. 优化通知,如点击后启动一个活动

    Intent intent = new Intent(this, XXXActivity.class);
    PendingIntent pi = PendingIntent.getActivity(this, 0, inent, 0);
    Notification notification = new NotificationCompat.Builder(this)
                        ...
                        .setContentIntent(pi)
                        build();
    ...
    
  5. 关闭通知 有2种方式,自动取消和利用NotificationManager的cancel方法

    ...
    .setAutoCancel(true);
    .build();
    
    
    NotificationManager manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
    manager.cancel(1);
    

2.1.2通知的高级用法

如加振动和LED闪烁以及设置文本和图片,优先级,都需要连缀在通知的创建方法中

2.2调用摄像头和相册

2.2.1启动相机程序
Intent intent = new Intent("android.media.action.IMAGE_CAPTURE");
            intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);//图片的书橱地址
            startActivityForResult(intent, TAKE_PHOTO);//拍完照后回调onActivityResult显示图片


public void onActivityResult(int resultCode, int resultCode, Intent data){
    switch(requestCode){
        case TAKE_PHOTO:
            if (resultCode == RESULT_OK){
                try{
                    Bitmap bitmap =                                                  BitmapFactory.decodeFile(imagePath);
                    picture.setImageBitmap(bitmap);
                }catch(FileNotFouncException e){
                    e.printStackTrace();
                }
            }
            break;
            ...
        }
    }
}

针对Android系统版本的不同,调用不同的方法获取到图片的Uri对象.低于7.0调用Uri的fromFile方法可以将File对象转换成Uri对象,否则调用FileProvider的gerUriForFile方法将File对象转换成封装后的Uri对象,因为用到了FileProvider这种特殊内容提供器,需要对内容提供器注册,指定Uri的共享路径,引用创建的@xml/file_paths资源

<paths xmlns:android="http://schemas.android.com/apk/res/android">
    <external-path name="my_images" path="" />
</paths>

2.2.2从相册中选取照片

相册的照片是在外存中存储的,需要申请权限,获得授权后,利用Intent对象,打开相册程序

Intent intent = new Intent("android.intent.action.GET_CONTENT");
intent.setType("image/*");
startActivityForResult(intent, CHOOSE_PHOTO);

当从相册选择照片后,回调onActivityForResult方法,处理照片。

注意 Android4.4以后,照片不再是真实的Uri,封装过,需要解析。考虑到兼容,需要对不同的系统版本编写不同的代码。具体可参考<<第一行代码>> P300

2.3播放多媒体文件

2.3.1播放音频

借助MediaPlayer类,以及控制方法如

  • setDataSource:设置音频文件位置
  • prepare:播放前调用
  • start:开始或继续
  • pause:暂停
  • reset:重置
  • seekTo:指定位置
  • stop:停止
  • release:释放资源
  • isPlaying:播放状态
  • getDuration:时长

工作流程:

  1. 创建MediaPlayer对象
  2. 调用setDataSource设置音频文件的路径
  3. 调用prepare是MediaPlayer对象进入到准备状态
  4. 调用start开始播放,pause暂停 reset停止播放
  5. 5.

2.3.2播放视频

使用VidioView类,类似于MediaPlayer的用法
  • setVideoPath
  • start
  • pause
  • resume
  • seekTo
  • isPlaying
  • getDuration