Android——使用通知,运用手机多媒体

1.Notification通知

通知Notification,当某个应用希望向用户发送一些提示信息,而该应用不在前台运行,就借助通知来实现。发出一条通知,手机上方的状态栏中会显示一个通知图标,下拉状态栏后可以看到通知的详细内容。通知可以在活动广播接收器服务里创建,一般程序进入后台的时候我们才使用通知。
步骤:需要一个NotificationManager来对通知进行管理,可以调用Context的getSystemService()方法得到,接收一个字符串参数用于确定获取系统的哪个服务。传入Context.NOTIFICATION_SERVICE即可。接下来需要使用一个Builder构造器来创建Notification对象,使用NotificationCompat类

activity_main.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <Button
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Send Notice"
        android:id="@+id/send_notice"/>

</LinearLayout>

新建一个NotificationActivity活动,修改xml文件里的代码

<TextView
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:id="@+id/text_view"
    android:text="this is Notification"/>

MainActivity

public class MainActivity extends AppCompatActivity implements View.OnClickListener{

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Button sendNotice = (Button) findViewById(R.id.send_notice);
        sendNotice.setOnClickListener(this);
    }

    @Override
    public void onClick(View view) {
        switch (view.getId()){
            case R.id.send_notice:
                Intent intent = new Intent(MainActivity.this,NotificationActivity.class);
                PendingIntent pi = PendingIntent.getActivity(this,0,intent,0);
                NotificationManager manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
                NotificationChannel channel = new NotificationChannel("1","channel1",NotificationManager.IMPORTANCE_HIGH);
                Notification notification = new NotificationCompat.Builder(MainActivity.this,"1")
                        .setContentTitle("this is a notification Title")
                        .setContentText("this is a notification text")
                        .setWhen(System.currentTimeMillis())
                        .setSmallIcon(R.mipmap.ic_launcher)
                        .setLargeIcon(BitmapFactory.decodeResource(getResources(),R.mipmap.ic_launcher))
                        .setContentIntent(pi)
                        .build();
                manager.notify(1,notification);
                break;
            default:
                break;
        }
    }
}

notify()方法接收两个参数,第一个参数id,每个通知指定的id是不一样的,第二个参数是Notification对象
PendingIntent和Intent类似,可以指明某个意图,启动活动,启动服务,发送广播等,不同的是Intent更加倾向于立即去执行某个动作PendingIntent倾向于在某个合适的时机去执行,可理解为延迟执行的Intent。获取PendingIntent的实例,可选择getActivity()方法getBroadcast()方法getService()方法,这三个方法接收的参数一样,第一个Content,第二个通常用不到传入0,第三个是一个Intent对象,可以通过这个对象构建出PendingIntent的“意图”,第四个参数用于确定PendingIntent行为,通常传入0。NotificationCompat.Builder,这个构造器再连缀一个setContentIntent()方法,接收的参数正是一个PendingIntent对象,因此这里可以通过一个PendingIntent构建出一个延迟执行的“意图”,当用户点击这条通知时就会执行相应的逻辑。

运行效果
点击按钮
在这里插入图片描述
点进去
在这里插入图片描述

2.调用摄像头和相册

新建一个CameraAlbumTest项目

<Button
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:id="@+id/take_photo"
    android:text="Take Photo"/>
<ImageView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_gravity="center_horizontal"
    android:id="@+id/picture"/>
public class MainActivity extends AppCompatActivity {
    public static final int TAKE_PHOTO = 1;
    private ImageView picture;
    private Uri imageUri;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Button takePhoto = (Button) findViewById(R.id.take_photo);
        picture = (ImageView) findViewById(R.id.picture);
        takePhoto.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                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 = FileProvider.getUriForFile(MainActivity.this,
                            "com.example.cameraalbumtest.fileprovider",outputImage);
                }else{
                    imageUri = Uri.fromFile(outputImage);
                }

                Intent intent = new Intent("android.media.action.IMAGE_CAPTURE");
                intent.putExtra(MediaStore.EXTRA_OUTPUT,imageUri);
                startActivityForResult(intent,TAKE_PHOTO);
            }
        });
    }



    @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 (FileNotFoundException e) {
                        e.printStackTrace();
                    }
                }
                break;
            default:
                break;
        }
    }
}

按钮的点击事件里,首先创建了一个File对象,用于存放摄像头拍下的照片,图片命名为output_image.jpg,并将它存放在SD卡的应用关联缓存目录下(SD卡中专门用于存放当前应用缓存数据的位置),调用getExternalCacheDir()方法可以得到这个目录,
然后判断,运行设备的系统版本低于Android 7.0,就调用Uri的fromFile()方法将File对象转换成Uri对象,这个Uri对象标识着output_image.jpg的本地真实路径,否则就调用FileProvider的getUriForFile()方法将File对象转换成一个封装过的Uri对象。getUriForFile()方法接收三个参数,第一个Context,第二个参数可以是任意唯一的字符串,第三个参数是刚刚创建的File对象。Android 7.0开始,直接使用本地真实路径的Uri被认为不安全,FileProvider是一种特殊的内容提供器,使用了和内容提供器类似的机制对数据进行保护,可以选择性地将封装过地Uri共享给外部,提高了应用的安全性。

接下来构建出了一个Intent对象,将这个Intent的action指定为android.media.action.IMAGE_CAPTURE,再调用Intent的putExtra()方法将指定的图片输出地址,最后调用startActivityForResult()来启动活动,使用了隐式Intent,系统会找出能响应这个Intent的活动去启动,这样照相机程序会被打开,拍下的照片会输出到output_image.jpg中。

刚刚使用了startActivityForResult()来启动活动,拍完照后会有结果返回到onActivityResult()方法中,若拍照成功,就可以调用BitmapFactory的decodeStream()方法将output_stream.jpg解析成Bitmap对象,然后把他设置到ImageView中显示出来

我们要在AndroidManifest.xml中对内容提供器进行注册,

...
<provider
    android:authorities="com.example.cameraalbumtest.fileprovider"
    android:name="androidx.core.content.FileProvider"
    android:exported="false"
    android:grantUriPermissions="true">
    <meta-data
        android:name="android.support.FILE_PROVIDER_PATHS"
        android:resource="@xml/file_paths"/>
</provider>
...

android:name的属性是固定的
android:authorities的属性要和刚刚FileProvider.getUriForFile()方法中第二个参数一致,另外,使用< meta-data >来指定Uri的共享路径,并引用一个@xml/file_paths资源,在res目录下创建它,创建一个xml目录,创建一个file_paths.xml文件

<?xml version="1.0" encoding="utf-8" ?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-path name="my_images" path="" />
</paths>

external-path来指定Uri共享,name属性的值可以随便填,path属性的值表示共享的具体路径,空值表示将整个SD卡进行共享。
Android 4.4系统之前访问SD卡的应用关联目录要声明权限,4.4之后不需要说明,为了兼容老手机,在AndroidManifest.xml中声明一下访问SD卡的权限:

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

从相册中选择照片

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">
    ......

     <Button
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/choose_photo"
        android:text="Choose Photo"/>
     ......
</LinearLayout>
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);
        ......
        Button chooseFromAlbum = (Button) findViewById(R.id.choose_photo);
        chooseFromAlbum.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                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();
                }
            }
        });
    }


    @Override
    protected void onActivityResult(int requestCode,int resultCode,Intent data) {
        switch (requestCode) {
        ......
                case CHOOSE_PHOTO:
                if(resultCode ==RESULT_OK) {
                    if (Build.VERSION.SDK_INT >= 19) {
                        handleImageOnKitKat(data);
                    } else {
                        handleImageBeforeKitKat(data);
                    }
                }
                break;
            default:
                break;
        }
    }

    @TargetApi(19)
    private void handleImageOnKitKat(Intent data){
        String imagePath = null;
        Uri uri = data.getData();
        if(DocumentsContract.isDocumentUri(this,uri)){
            String docId = DocumentsContract.getDocumentId(uri);
            if("com.android.providers.media.documents".equals(uri.getAuthority())){
                String id = docId.split(":")[1];
                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())){
                imagePath = getImagePath(uri,null);
        }else if("file".equalsIgnoreCase(uri.getScheme())){
                imagePath = uri.getPath();
        }
        displayImage(imagePath);

    }
    private void handleImageBeforeKitKat(Intent data){
        Uri uri = data.getData();
        String imagePath = getImagePath(uri,null);
        displayImage(imagePath);
    }

    private String getImagePath(Uri uri,String selection){
        String path = null;
        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_LONG).show();
        }
    }

    public void openAlbum(){
        Intent intent = new Intent("android.intent.action.GET_CONTENT");
        intent.setType("image/*");
        startActivityForResult(intent,CHOOSE_PHOTO);
    }	
    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        switch (requestCode){
            case 1:
                if(grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED){
                openAlbum();
                }else{
                    Toast.makeText(this,"you deny the permission",Toast.LENGTH_LONG).show();
                }
                break;
            default:
        }
    }
    
   ......

}

首先在chooseFromAlbum按钮的点击事件里进行了权限处理,动态申请WRITE_EXTERNAL_STORAGE这个危险权限,同时授予程序对SD读和写的能力。
授权了权限申请之后会调用openAlbum()方法,构建了一个Intent对象,并将他的动作指定为android.intent.action.GET_CONTENT,接着给这个Intent设置一些必要的参数,然后调用startActivityForResult()方法就可以给打开相册程序选择照片,startActivityForResult的第二个参数是CHOOSE_PHOTO,当选择完照片回到onActivityResult()方法时会进入CHOOSE_PHOTO的case,处理图片。
如果是4.4系统版本以上,调用handleImageOnKitKat()方法,不是则调用handleImageBeforeKitKat()方法,android系统从4.4开始,选取相册中的图片不再返回图片真实的Uri,是一个封装过的Uri,需要对这个Uri进行解析。
handleImageOnKitKat()方法里,如果返回的Uri是document类型,就取出document id进行处理,如果不是就用普通方式处理,如果Uri的authority是media格式的话,document id还需要再解析一次,通过字符串分割取出后半部分,得到真正的数字id取出的id用于构建新的Uri和条件语句,然后把这些值作为参数传入到getImagePath()方法中将图片显示到界面上。
handleImageBeforeKitKat()方法直接将Uri传入到getImagePath()方法中。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值