欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

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

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

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构建出一个延迟执行的“意图”,当用户点击这条通知时就会执行相应的逻辑。

运行效果
点击按钮
Android——使用通知,运用手机多媒体
点进去
Android——使用通知,运用手机多媒体

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()方法中。

本文地址:https://blog.csdn.net/zhougongjinxuan/article/details/108534143

相关标签: android