安卓学习之多媒体

1.使用通知

1.通知的基本用法

public class MainActivity extends AppCompatActivity implements View.OnClickListener {
    NotificationManager manager;
    @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);

        manager= (NotificationManager) getSystemService(NOTIFICATION_SERVICE);//获取到哪个服务
    }
    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.send_notice:
//                Intent intent = new Intent(this, NotificationActivity.class);
//                PendingIntent pi = PendingIntent.getActivity(this, 0, intent, 0);
                if(Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O){
                    //只在Android O之上需要渠道
                    NotificationChannel notificationChannel = new NotificationChannel("channelid1","channelname",NotificationManager.IMPORTANCE_HIGH);
                    //如果这里用IMPORTANCE_NOENE就需要在系统的设置里面开启渠道,通知才能正常弹出
                    manager.createNotificationChannel(notificationChannel);
                }
//                NotificationManager manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
                Notification notification = new NotificationCompat.Builder(MainActivity.this,"channelid1")
                        .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)) //大图标
                        .setAutoCancel(true)
//                        .setContentIntent(pi)

                        .build();
                manager.notify(1, notification);
                break;
            default:
                break;
        }
    }
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Heu42FFS-1621477304761)(C:\Users\tanglei\AppData\Roaming\Typora\typora-user-images\image-20210519191134337.png)]

注意,书中的代码不能直接运行,需要更改,加上判断条件

if(Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O){
                    //只在Android O之上需要渠道
                    NotificationChannel notificationChannel = new NotificationChannel("channelid1","channelname",NotificationManager.IMPORTANCE_DEFAULT);
                    //如果这里用IMPORTANCE_NOENE就需要在系统的设置里面开启渠道,通知才能正常弹出
                    manager.createNotificationChannel(notificationChannel);
                }

//其中, manager= (NotificationManager) getSystemService(NOTIFICATION_SERVICE);//获取到哪个服务
要声明为全局变量,提升作用域
    NotificationManager manager;

以上代码,只能实现通知,现在给通知加入点击跳转功能。

引入PendingIntent从名字上看起来就和Intent有些类似,可以把PendingIntent简单地理解为延迟执行的Intent。

....
case R.id.send_notice:
//①重点是加入了这两句
Intent intent = new Intent(this, NotificationActivity.class);
PendingIntent pi = PendingIntent.getActivity(this, 0, intent, 0);
                if(Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O){
                .....
                }
//②加入下面一句
    .setAutoCancel(true)
    .setContentIntent(pi)

使用getActivity() 方法,传入四个参数,第一个参数依旧是Context,不用多做解释。第二个参数一般用不到,通常都是传入0即可。第三个参数是一个Intent 对象,我们可以通过这个对象构建出PendingIntent的“意图”。第四个参数用于确定PendingIntent的行为,通常为0.

记得在布局文件中定义新的布局

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        android:textSize="24sp"
        android:text="This is notification layout"
        />
</RelativeLayout>

2.通知的进阶用法

    .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) 默认效果
        
手机声音提示:setSound()方法接收一个Uri 参数     
手机进行振动:vibrate ()下标为0的值表示手机静止的时长,下标为1的值表示手机振动的时长,下标为2的值又表示手机静止的时长,属于危险权限,需要声明
        <uses-permission android:name="android.permission.VIBRATE" />
手机LED灯闪烁:setLights() 第一个参数用于指定LED灯的颜色,第二个参数用于指定LED灯亮起的时长,以毫秒为单位,第三个参数用于指定LED灯暗去的时长

3.通知的高级功能

setStyle() 方法,这个方法允许我们构建出富文本的通知内容。也就是说通知中不光可以有文字和图标,还可以包含更多的东西。setStyle() 方法接收一个NotificationCompat.Style 参数,这个参数就是用来构建具体的富文本信息的,如长文字、图片

//文字
Notification notification = new NotificationCompat.Builder(this)
        ...
        .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."))
        .build();
//图片
 Notification notification = new NotificationCompat.Builder(this)
        ...
        .setStyle(new NotificationCompat.BigPictureStyle().bigPicture
            (BitmapFactory.decodeResource(getResources(), R.drawable.big_image)))
        .build();    
       //BitmapFactory的decodeResource() 方法将图片解析成Bitmap 对象

setPriority() 方法,它可以用于设置通知的重要程度

.setPriority(NotificationCompat.PRIORITY_MAX)
  • PRIORITY_DEFAULT 表示默认的重要程度,和不设置效果是一样的;
  • PRIORITY_MIN表示最低的重要程度,系统可能只会在特定的场景才显示这条通知,比如用户下拉状态栏的时
    候;
  • PRIORITY_LOW 表示较低的重要程度,系统可能会将这类通知缩小,或改变其显示的顺序,将其排在更重要的通知之后;
  • PRIORITY_HIGH 表示较高的重要程度,系统可能会将这类通知放大,或改变其显示的顺序,将其排在比较靠前的位置;
  • PRIORITY_MAX 表示最高的重要程度,这类通知消息必须要让用户立刻看到,甚至需要用户做出响应操作

2.调用摄像头和相册

1.调用摄像头拍照

1.新建一个CameraAlbumTest项目,然后修改activity_main.xml中的代码。Button是用于打开摄像头进行拍照的,而ImageView则是用于将拍到的图片显示出来。

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >
    <Button
        android:id="@+id/take_photo"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Take Photo" />
    <ImageView
        android:id="@+id/picture"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal" />
</LinearLayout>

2.开始编写调用摄像头的具体逻辑,修改MainActivity中的代码

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 v) {
                // 创建File对象,用于存储拍照后的图片
                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卡的应用关联缓存目录下
  • 调用getExternalCacheDir()方法可以得到这个目录,具体的路径是/sdcard/Android/data//cache
  • 接着会进行一个判断,如果运行设备的系统版本低于Android 7.0,就调用Uri的fromFile() 方法将File 对象转换成Uri 对象,这个Uri对象标识着output_image.jpg这张图片的本地真实路径。否则,就调用FileProvider的getUriForFile() 方法将File 对象转换成一个封装过的Uri对象。
  • getUriForFile() 方法接收3个参数,第一个参数要求传入Context 对象,第二个参数可以是任意唯一的字符串,第三个参数则是我们刚刚创建的File 对象
  • 之所以要进行这样一层转换,是因为从Android 7.0系统开始,直接使用本地真实路径的Uri被认为是不安全的,会抛出一个FileUriExposedException异常。而FileProvider则是一种特殊的内容提供器,它使用了和内
    容提供器类似的机制来对数据进行保护,可以选择性地将封装过的Uri共享给外部,从而提高了应用的安全性
  • 接下来构建出了一个Intent 对象,并将这个Intent 的action 指定为android.media.action.IMAGE_CAPTURE ,再调用Intent 的putExtra() 方法指定图片的输出地址,这里填入刚刚得到的Uri对象,最后调用startActivityForResult() 来启动活动。由于我们使用的是一个隐式Intent,系统会找出能够响应这个Intent的活动去启动,这样照相机程序就会被打开,拍下的照片将会输出到output_image.jpg中
  • 刚才我们是使用startActivityForResult() 来启动活动的,因此拍完照后会有结果返回到onActivityResult() 方法中。如果发现拍照成功,就可以调用BitmapFactory的decodeStream() 方法将output_image.jpg这张照片解析成Bitmap 对象,然后把它设置ImageView中显示出来

3.刚才提到了内容提供器,那么我们自然要在AndroidManifest.xml中对内容提供器进行注册了

?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.cameraalbumtest">

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


    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">

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

        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>



</manifest>

android:name 属性的值是固定的,android:authorities 属性的值必须要和刚才FileProvider.getUriForFile() 方法中的第二个参数一致。另外,这里还在 标签的内部使用 来指定Uri 的共享路径,并引用了一个@xml/file_paths 资源。当然,这个资源现在还是不存在的,下面我们就来创建它

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

2.从相册中选择照片

编辑activity_main.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >
    <Button
        android:id="@+id/take_photo"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Take Photo" />
    <Button
        android:id="@+id/choose_from_album"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Choose From Album" />
    <ImageView
        android:id="@+id/picture"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal" />
</LinearLayout>

修改MainActivity中的代码,加入从相册选择照片的逻辑

public class MainActivity extends AppCompatActivity {
    ...
    public static final int CHOOSE_PHOTO = 2;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Button takePhoto = (Button) findViewById(R.id.take_photo);
        Button chooseFromAlbum = (Button) findViewById(R.id.choose_from_album);
        ...
        chooseFromAlbum.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                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:
        }
    }
    @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) {
                        // 4.4及以上系统使用这个方法处理图片
                        handleImageOnKitKat(data);
                    } else {
                        // 4.4以下系统使用这个方法处理图片
                        handleImageBeforeKitKat(data);
                    }
                }
                break;
            default:
                break;
        }
    }
    @TargetApi(19)
    private void handleImageOnKitKat(Intent data) {
        String imagePath = null;
        Uri uri = data.getData();
        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); // 根据图片路径显示图片
    }
    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;
        // 通过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();
        }
    }
}

在Choose From Album按钮的点击事件里我们先是进行了一个运行时权限处理,动态申请WRITE_EXTERNAL_STORAGE 这个危险权限;用户授权了权限申请之后会调用openAlbum() 方法,这里我们先是构建出了一个Intent 对象,并将它的action 指定为android.intent.action.GET_CONTENT 。接着给这个Intent 对象设置一些必要的参数,然后调用startActivityForResult() 方法就可以打开相册程序选择照片了;用户授权了权限申请之后会调用openAlbum() 方法,这里我们先是构建出了一个Intent 对象,并将它的action 指定为android.intent.action.GET_CONTENT 。接着给这个Intent 对象设置一些必要的参数,然后调startActivityForResult() 方法就可以打开相册程序选择照片了

疑问:我没有实现相册选取展示这一功能!!!怎么解决呀

3.播放多媒体文件

1.播放音频

2.播放视频

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值