【Android】安卓多媒体之通知、摄像头、相册、播放音乐、视频用法总结

一、通知

Android 8.0(API26)后对通知更改了一些内容,以前是通过Notification,Builder(Context context).se..来设置通知的震动、灯光、音效的设置,新内容加了NotificationChannel(通知渠道),通过NotificatonChannel来进行震动、灯光、音效的设置,且通知必须添加通知渠道,同样需进行版本判断,否则通知不会被发送。

步骤:

  1. 首先创建NotificationManager对象
  2. 创建Notificationchannel对象
  3. 通过Notificationcompat.Builder(Context.Notification)对象指定channel并设置通知的各项信息,调用build()方法创建Notifcation对象
  4. 调用NotificationManagernotify(id,Notification)方法发送通知

1. 申请权限

AndroidManifest.xml 文件中声明权限

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

在运行时请求权限

if (ContextCompat.checkSelfPermission(this, Manifest.permission.POST_NOTIFICATIONS)
                != PackageManager.PERMISSION_GRANTED) {
            // 权限尚未授予,申请权限
            ActivityCompat.requestPermissions(this,
                    new String[]{Manifest.permission.POST_NOTIFICATIONS},1);
}

2. 创建通道

使用NotificationChannel类创建通知通道的实例
创建通知通道:

  • 设置唯一的id
  • 通道的用户可见的名称
  • 通道的重要性

image-20240731095312726

private static final String MESSAGES_CHANNEL = "default_channel";
private void createMessagesNotificationChannel(Context context) {
    // 检查当前设备的系统版本是否大于或等于 Android 8.0 (API 级别 26)
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
        // 从资源中获取通知渠道的名称
        CharSequence name = context.getString(R.string.message_channel_name);
        
        // 创建一个通知渠道对象
        NotificationChannel channel = new NotificationChannel(
                MESSAGES_CHANNEL, // 渠道 ID,用于标识这个通知渠道
                name, // 渠道名称,从资源文件中获取
                NotificationManager.IMPORTANCE_HIGH // 渠道的重要性级别,决定通知的行为和显示方式
        );
        
        // 获取 NotificationManager 系统服务
        NotificationManager manager = context.getSystemService(NotificationManager.class);
        
        // 创建通知渠道
        manager.createNotificationChannel(channel);
    }
}

这样后就创建了渠道,下来直接构建通知然后发送即可

3. 创建通知

image-20240731095422811

    public void onClick(View v) {
        NotificationManager manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
        Notification notification = new NotificationCompat.Builder(this, MESSAGES_CHANNEL)
                .setContentTitle("重要通知")
                .setContentText("您今天睡眠时间不足")
                .setWhen(System.currentTimeMillis())
                .setSmallIcon(R.drawable.messages_1)
                .setLargeIcon(BitmapFactory.decodeResource(getResources(), R.drawable.messages_2))
                .build();
        manager.notify(1, notification);
    }

4. 发送通知

使用NotificationManager类发送通知

  • 调用getSystemService()方法创建NotificationManager的对象
  • 调用它的notify()方法发送消息,传递通知idNotification对象
 manager.notify(1, notification); // 参数 1 是通知的 ID,用于更新或取消通知,notification 是要显示的通知对象

拓展功能

点击行为

所有通知在点击后都必须作出响应,一般是启动一个Activity

  • 调用setContentlntent()方法设置一个内容Intent;

  • 然后通过一个PendingIntent对象传递内容Intent

public void onClick(View v) {
		//----在这里设置PendingIntent----
        Intent intent = new Intent(this, NotificationActivity.class);
        PendingIntent pendingIntent = PendingIntent.getActivity(
                this,
                0,
                intent,
                PendingIntent.FLAG_IMMUTABLE
        );

        NotificationManager manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
        Notification notification = new NotificationCompat.Builder(this, MESSAGES_CHANNEL)
                .setContentTitle("重要通知")
                .setContentText("您今天睡眠时间不足")
                .setWhen(System.currentTimeMillis())
                .setSmallIcon(R.drawable.messages_1)
                .setLargeIcon(BitmapFactory.decodeResource(getResources(), R.drawable.messages_2))
                .setContentIntent(pendingIntent)// 设置点击通知时的 PendingIntent
                .setAutoCancel(true)// 点击通知后自动取消
                .build();
        manager.notify(1, notification);
    }
public static PendingIntent getActivity
(Context context, int requestCode, Intent intent, int flags)

PendingIntent 是一种封装了 Intent 的机制,可以在将来某个时刻代替应用程序的进程执行特定的操作,即使应用程序不在运行中。

flags: 标志位,指定 PendingIntent 的行为。常用标志包括:

通常使用FLAG_IMMUTABLE

  • PendingIntent.FLAG_UPDATE_CURRENT: 如果 PendingIntent 已存在,更新其内容。
  • PendingIntent.FLAG_CANCEL_CURRENT: 如果 PendingIntent 已存在,先取消它,然后创建一个新的。
  • PendingIntent.FLAG_IMMUTABLE: 使 PendingIntent 不可变,即创建后不会被修改。
  • PendingIntent.FLAG_MUTABLE: 使 PendingIntent 可变,即创建后可以被修改。

更新通知

  • 使用NotificationCompat.Builder构造其创建有更新内容的通知
  • 将相同的通知Id和更新内容后的通知传递给notify()方法即可实现更新
    • 若之前的通知仍然可见,则系统更新
    • 若之前的通知已被取消,则发送新的通知

取消通知

通知会一直保存可见,以下操作会使消息取消

  • 用户通过滑动或使用"清除所有"取消它
  • 创建通知时调用setAutoCancel(),那么当用户单击通知时会从状态栏消失
  • 通过NotificationManagercancel(通知ld)取消,或调用cancelAll()取消所有通知

锁屏通知

Android 5.0(APl21)开始,通知可以显示在锁屏上。用户可以通过设置选择是否允许敏感的通知内容显示在安全的锁屏上。

android5.0加入一种新的模式Notification的显示等级,共有三种:

  • VISIBILITY_PUBLIC 任何情况都会显示通知
  • VISIBILITY_PRIVATE 显示基本信息隐藏通知内部信息
  • VISIBILITY SECRET 在没有锁屏的情况下才能够显示
  • 调用setVisibility方法设置
builder.setVisibility(Notification.VISIBILITY_PUBLIC);

富文本通知

富文本通知指的是可以展示复杂内容的通知,例如包含多种样式的文本、图片、链接等。要创建富文本通知,可以使用 NotificationCompat 类的一些方法和样式。

setStyle(new NotificationCompat.BigTextStyle())
  1. 使用 BigTextStyleBigTextStyle 用于显示大段文本内容,这些内容会在展开时显示完整。
        Notification notification = new NotificationCompat.Builder(this, MESSAGES_CHANNEL)
                .setContentTitle("富文本通知")
                .setContentText("点击查看详细内容")
                .setWhen(System.currentTimeMillis())
                .setSmallIcon(R.drawable.messages_1)
                .setLargeIcon(BitmapFactory.decodeResource(getResources(), R.drawable.messages_2))
                .setStyle(new NotificationCompat.BigTextStyle()
                        .bigText("这是一个长文本示例。在展开通知后,可以看到更多的内容," +
                                "而不是只显示简短的预览文本。这样可以展示更详细的信息。"))
                .setContentIntent(pendingIntent)
                .setAutoCancel(true)
                .build();

VID_20240731_115043

  1. 使用 BigPictureStyleBigPictureStyle 用于显示一张大图片,可以同时显示文本。

  2. 使用 InboxStyleInboxStyle 用于显示一组消息的列表,适合显示多个简短的消息。

  3. MessageingStyle通知

使用 MessagingStyle 的通知可以展示一系列的消息,仿佛是一个对话线程,让用户能够在通知栏中查看消息交流的上下文。

// 创建 MessagingStyle 对象
        NotificationCompat.MessagingStyle messagingStyle = new NotificationCompat.MessagingStyle("聊天机器人")
                .addMessage("你好!有什么我可以帮助你的吗?", System.currentTimeMillis(), "聊天机器人") 
// 添加一条消息,内容为“你好!有什么我可以帮助你的吗?”,时间为当前时间,发送者为“聊天机器人”
                .addMessage("我想知道今天的天气怎么样。", System.currentTimeMillis(), "用户") 
// 添加另一条消息,内容为“我想知道今天的天气怎么样。”,时间为当前时间,发送者为“用户”
                .setConversationTitle("天气咨询"); 
// 设置对话标题为“天气咨询”,用来标识对话的主题



// 创建通知
        Notification notification = new NotificationCompat.Builder(this, MESSAGES_CHANNEL)
                .setContentTitle("消息通知")
                .setContentText("您有新的消息")
                .setWhen(System.currentTimeMillis())
                .setSmallIcon(R.drawable.messages_1)
                .setLargeIcon(BitmapFactory.decodeResource(getResources(), R.drawable.messages_2))
                .setStyle(messagingStyle) // 设置 MessagingStyle
                .setContentIntent(pendingIntent) 
                .setAutoCancel(true) 
                .build();
        manager.notify(1, notification);
    }

Screenshot_2024-07-31-11-43-50-051_com.android.sy

二、摄像头

1. 申请权限

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

允许应用使用设备的相机进行拍照或录像

在运行时请求权限

public class MainActivity extends AppCompatActivity {

    private ImageView image;  // 显示拍摄照片的ImageView
    private static final int REQUEST_CAMERA_PERMISSION = 100;  // 请求权限的请求码

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        image = findViewById(R.id.image);

        // 检查并请求相机权限
        if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED ) {
            ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.CAMERA}, REQUEST_CAMERA_PERMISSION);
        }
    }

    // 处理权限请求结果
    @Override
    public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        if (requestCode == REQUEST_CAMERA_PERMISSION) {
            if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                // 权限授予,执行相应操作
            } else {
                // 权限拒绝,提示用户
                Toast.makeText(this, "相机权限被拒绝", Toast.LENGTH_SHORT).show();
            }
        }
    }

2. 调用逻辑

public class MainActivity extends AppCompatActivity {

    private ImageView image;  // 显示拍摄照片的ImageView
    private Uri imageUri;  // 存储照片文件的Uri
    private static final int TAKE_PHOTO = 1;  // 拍照请求码
    private static final int REQUEST_CAMERA_PERMISSION = 100;  // 请求权限的请求码

   @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        image = findViewById(R.id.image);

        // 检查并请求相机权限
        if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED ) {
            ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.CAMERA}, REQUEST_CAMERA_PERMISSION);
        }
    }

    // 处理权限请求结果
    @Override
    public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        if (requestCode == REQUEST_CAMERA_PERMISSION) {
            if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                // 权限授予,执行相应操作
            } else {
                // 权限拒绝,提示用户
                Toast.makeText(this, "相机权限被拒绝", Toast.LENGTH_SHORT).show();
            }
        }
    }

    // 调用相机拍照
    public void invokeCamera(View view) {
        // 创建一个文件对象,用于存储拍摄的照片,存储在应用的外部缓存目录中,文件名为 "output_image.jpg"
        File outputImage = new File(getExternalCacheDir(), "output_image.jpg");

        try {
            // 如果文件存在,删除旧文件
            if (outputImage.exists()) {
                outputImage.delete();
            }
            // 创建新文件
            outputImage.createNewFile();
        } catch (IOException e) {
            // 处理文件操作异常
            throw new RuntimeException(e);
        }

        // 检查安卓版本,如果版本大于等于 24(安卓 7.0),使用 FileProvider 获取文件的 URI
        if (Build.VERSION.SDK_INT >= 24) {
            // FileProvider 是一个安全的方式来分享文件
            imageUri = FileProvider.getUriForFile(MainActivity.this, "com.example.cameraalubmtest.fileprovider", outputImage);
        } else {
            // 如果安卓版本小于 24,直接获取文件的 URI
            imageUri = Uri.fromFile(outputImage);
        }

        // 创建一个 Intent 对象,指定动作为 "android.media.action.IMAGE_CAPTURE" 以调用系统相机应用
        Intent intent = new Intent("android.media.action.IMAGE_CAPTURE");
        // 将文件 URI 作为额外参数传递给相机应用,指定拍摄的照片应保存到该 URI 对应的文件中
        intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);
        // 启动相机应用,并传入请求码 TAKE_PHOTO,等待返回结果
        startActivityForResult(intent, TAKE_PHOTO);
    }


    // 处理拍照结果
    @Override
    protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        switch (requestCode) {
            case TAKE_PHOTO:
                if (resultCode == RESULT_OK) {
                    try {
                        // 使用内容解析器打开 imageUri 对应的输入流,并将其解码为 Bitmap
                        Bitmap bitmap = BitmapFactory.decodeStream(getContentResolver().openInputStream(imageUri));
                        // 将解码后的 Bitmap 设置为 ImageView 的图像显示
                        image.setImageBitmap(bitmap);
                    } catch (FileNotFoundException e) {
                        // 如果文件未找到,抛出运行时异常
                        throw new RuntimeException(e);
                    }
                }
                break;
            default:
                break;
        }
    }

3. 声明内容提供器

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools">
    <uses-permission android:name="android.permission.CAMERA" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />

    <application
        android:allowBackup="true"
        android:dataExtractionRules="@xml/data_extraction_rules"
        android:fullBackupContent="@xml/backup_rules"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/Theme.CameraAlubmTest"
        tools:targetApi="31">
        <activity
            android:name=".MainActivity"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

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

指定路径配置文件的位置:

新建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>

三、打开相册

1. 申请权限

检查并请求权限

onCreate 方法中,应用检查相机和存储权限是否已经被授予。如果未被授予,则请求这些权限。

if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED
        || ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
    ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.CAMERA, Manifest.permission.WRITE_EXTERNAL_STORAGE}, REQUEST_CAMERA_PERMISSION);
}

这里用到的 ContextCompat.checkSelfPermission 方法返回一个整数,表示指定权限是否被授予。如果返回值为 PackageManager.PERMISSION_GRANTED,则表示权限已被授予;否则表示未被授予。

如果任何一个权限未被授予,则通过 ActivityCompat.requestPermissions 方法请求这些权限。请求码 REQUEST_CAMERA_PERMISSION 用于在权限请求结果中识别这个请求。

处理权限请求结果

当用户响应权限请求时,系统会调用 onRequestPermissionsResult 方法。在这里处理用户的响应。

@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    switch (requestCode) {
        case REQUEST_CAMERA_PERMISSION:
            if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                // 权限授予,执行相应操作
            } else {
                // 权限拒绝,提示用户
                Toast.makeText(this, "相机权限被拒绝", Toast.LENGTH_SHORT).show();
            }
    }
}

在这个方法中,我们检查请求码是否为 REQUEST_CAMERA_PERMISSION,然后检查 grantResults 数组,确认权限是否被授予。如果权限被拒绝,我们通过 Toast 提示用户权限被拒绝。

2.处理图片

从相册中选择图片

public void chooseFromAlbum(View view) {
    // 创建一个 Intent 对象,用于启动系统的图片选择器
    Intent intent = new Intent("android.intent.action.GET_CONTENT");
    // 设置选择器类型为图片
    intent.setType("image/*");
    // 启动图片选择器,并传入请求码 CHOOSE_PHOTO,等待返回结果
    startActivityForResult(intent, CHOOSE_PHOTO);
}

处理选择图片的结果

@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    switch (requestCode) {
        case TAKE_PHOTO:
            // 拍照
        case CHOOSE_PHOTO:
            if (resultCode == RESULT_OK) {
                if (Build.VERSION.SDK_INT >= 19) {
                    // 针对安卓 4.4 及以上系统处理图片
                    handleImageOnKitKat(data);
                } else {
                    // 针对低版本安卓系统处理图片
                }
            }
            break;
        default:
            break;
    }
}

处理图片

@TargetApi(19)
private void handleImageOnKitKat(Intent data) {
    String imagePath = null;
    // 获取用户选择的图片的 URI
    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())) {
            // 如果是媒体类型的 Document Uri,解析出数字 ID
            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())) {
            // 如果是下载类型的 Document Uri,解析出文件 ID
            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);
}

获取图片真实路径

@SuppressLint("Range")
private String getImagePath(Uri uri, String selection) {
    String path = null;
    // 通过内容解析器查询指定 URI 的数据
    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;
}

四、播放音乐

image-20240801121942815

1.申请权限

<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
public class MainActivity extends AppCompatActivity implements View.OnClickListener {

    private static final int REQUEST_PERMISSION_CODE = 1; // 权限请求代码
    private MediaPlayer mediaPlayer = new MediaPlayer(); // 媒体播放器实例

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main); // 设置布局文件

        // 初始化按钮并设置点击监听器
        Button btn1 = findViewById(R.id.btn_start);
        Button btn2 = findViewById(R.id.btn_pause);
        Button btn3 = findViewById(R.id.btn_stop);
        btn1.setOnClickListener(this);
        btn2.setOnClickListener(this);
        btn3.setOnClickListener(this);

        // 检查是否具有读取外部存储的权限
        if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE)
                != PackageManager.PERMISSION_GRANTED) {
            // 请求权限
            ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.READ_EXTERNAL_STORAGE}, REQUEST_PERMISSION_CODE);
        } else {
            // 已有权限,初始化媒体播放器
            initMediaPlayer();
        }
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        if (requestCode == REQUEST_PERMISSION_CODE) {
            if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                // 权限被授予,初始化媒体播放器
                initMediaPlayer();
            } else {
                // 权限被拒绝,显示提示并关闭应用
                Toast.makeText(this, "拒绝权限将无法使用程序", Toast.LENGTH_SHORT).show();
                finish();
            }
        }
    }
}

2.处理音乐

public class MainActivity extends AppCompatActivity implements View.OnClickListener {

    private static final int REQUEST_PERMISSION_CODE = 1; // 权限请求代码
    private MediaPlayer mediaPlayer = new MediaPlayer(); // 媒体播放器实例

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main); // 设置布局文件

        // 初始化按钮并设置点击监听器
        Button btn1 = findViewById(R.id.btn_start);
        Button btn2 = findViewById(R.id.btn_pause);
        Button btn3 = findViewById(R.id.btn_stop);
        btn1.setOnClickListener(this);
        btn2.setOnClickListener(this);
        btn3.setOnClickListener(this);

        // 检查是否具有读取外部存储的权限
        if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE)
                != PackageManager.PERMISSION_GRANTED) {
            // 请求权限
            ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.READ_EXTERNAL_STORAGE}, REQUEST_PERMISSION_CODE);
        } else {
            // 已有权限,初始化媒体播放器
            initMediaPlayer();
        }
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        if (requestCode == REQUEST_PERMISSION_CODE) {
            if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                // 权限被授予,初始化媒体播放器
                initMediaPlayer();
            } else {
                // 权限被拒绝,显示提示并关闭应用
                Toast.makeText(this, "拒绝权限将无法使用程序", Toast.LENGTH_SHORT).show();
                finish();
            }
        }
    }

    private void initMediaPlayer() {
        // 获取音乐文件的路径
        File file = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MUSIC), "music.map3");
        
        // 检查文件是否存在
        if (!file.exists()) {
            Toast.makeText(this, "文件不存在: " + file.getAbsolutePath(), Toast.LENGTH_SHORT).show();
            return;
        }
        try {
            // 设置数据源并准备播放器
            mediaPlayer.setDataSource(file.getPath());
            mediaPlayer.prepare();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public void onClick(View v) {
        if (v.getId() == R.id.btn_start) {
            if (!mediaPlayer.isPlaying()) {
                mediaPlayer.start(); // 开始
            }
        } else if (v.getId() == R.id.btn_pause) {
            if (mediaPlayer.isPlaying()) {
                mediaPlayer.pause(); // 暂停
            }
        } else if (v.getId() == R.id.btn_stop) {
            if (mediaPlayer.isPlaying()) {
                mediaPlayer.reset(); // 停止
                initMediaPlayer();
            }
        }
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        // 确保在销毁活动时释放媒体播放器资源
        if (mediaPlayer != null) {
            mediaPlayer.stop();
            mediaPlayer.release();
        }
    }
}

MediaPlayer

MediaPlayer 是 Android 提供的一个类,用于播放各种音频和视频文件。你可以用它来播放本地文件、网络流媒体或资源文件。下面是一些基本的用法:

  1. 创建 MediaPlayer 实例:

    MediaPlayer mediaPlayer = new MediaPlayer();
    
  2. 设置数据源: 你可以使用本地文件路径、资源 ID 或网络 URL 作为数据源。

    // 设置本地资源文件
    mediaPlayer.setDataSource(context, Uri.parse("file:///path/to/your/audio/file.mp3"));
    
    // 设置网络流媒体
    mediaPlayer.setDataSource("http://www.example.com/audiofile.mp3");
    
    // 设置资源 ID(例如 raw 文件夹中的文件)
    mediaPlayer = MediaPlayer.create(this, R.raw.music);
    
  3. 准备和开始播放:

    mediaPlayer = MediaPlayer.create(this, R.raw.music);
    // 如果使用的是本地文件或资源 ID
    
    mediaPlayer.prepareAsync(); // 如果使用的是网络流媒体
    mediaPlayer.start();
    
    1. 控制播放: 你可以暂停、继续或停止播放。
  mediaPlayer.pause();
  mediaPlayer.start();
  mediaPlayer.stop();
  1. 释放资源: 播放结束后或不再需要时,要释放资源。

    mediaPlayer.release();
    
  2. 设置监听器: 你可以设置播放完成、错误等事件的监听器。

    mediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
        @Override
        public void onCompletion(MediaPlayer mp) {
            // 播放完成
        }
    });
    
    mediaPlayer.setOnErrorListener(new MediaPlayer.OnErrorListener() {
        @Override
        public boolean onError(MediaPlayer mp, int what, int extra) {
            // 处理错误
            return false;
        }
    });
    

使用 MediaPlayer 的时候,确保在合适的生命周期阶段(如 onPauseonResume)管理其状态,避免资源泄漏。

五、播放视频

image-20240801121909033

VideoView 是 Android 提供的一个控件,用于在应用中播放视频。以下是 VideoView 常用的方法和属性的介绍:

方法

  1. setVideoPath(String path)
    • 设置视频的路径。可以是一个文件路径、URL 或资源路径。
    • 示例: videoView.setVideoPath("android.resource://" + getPackageName() + "/" + R.raw.video_file);
  2. setVideoURI(Uri uri)
    • 设置视频的 URI(统一资源标识符),这可以是文件 URI、内容 URI 或网络 URI。
    • 示例: videoView.setVideoURI(Uri.parse("http://www.example.com/video.mp4"));
  3. start()
    • 开始播放视频。如果视频已经在播放,调用此方法会重新开始播放视频。
    • 示例: videoView.start();
  4. pause()
    • 暂停视频播放。如果视频当前正在播放,调用此方法会暂停播放。
    • 示例: videoView.pause();
  5. stopPlayback()
    • 停止视频播放并释放资源。调用此方法后,视频将停止播放,并且需要重新设置视频路径或 URI。
    • 示例: videoView.stopPlayback();
  6. seekTo(int msec)
    • 将视频进度跳转到指定的时间位置,单位是毫秒。
    • 示例: videoView.seekTo(30000); // 跳转到 30 秒处
  7. getCurrentPosition()
    • 获取视频的当前播放位置,单位是毫秒。
    • 示例: int currentPosition = videoView.getCurrentPosition();
  8. getDuration()
    • 获取视频的总时长,单位是毫秒。
    • 示例: int duration = videoView.getDuration();
  9. isPlaying()
    • 检查视频是否正在播放。返回 true 如果视频正在播放,返回 false 如果视频处于暂停状态或未播放。
    • 示例: boolean isPlaying = videoView.isPlaying();

属性

  • setMediaController(MediaController controller)

    • 设置媒体控制器,用于提供播放、暂停、进度条等控制界面。可以使用默认的 MediaController 或自定义控制器。
    • 示例:
      MediaController mediaController = new MediaController(this);
      videoView.setMediaController(mediaController);
      mediaController.setAnchorView(videoView);
      
  • setKeepScreenOn(boolean keepScreenOn)

    • 设置是否保持屏幕常亮。可以用来防止视频播放时屏幕变暗。
    • 示例: `videoView.setKeepScreenOn(true);

示例

使用资源文件中的资源,不需要再申请权限

public class SecondActivity extends AppCompatActivity implements View.OnClickListener {

    // VideoView 用于播放视频
    private VideoView videoView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_second);

        videoView = findViewById(R.id.video_view);

        Button btn1 = findViewById(R.id.btn_start2);
        Button btn2 = findViewById(R.id.btn_pause2);
        Button btn3 = findViewById(R.id.btn_stop2);
        btn1.setOnClickListener(this);
        btn2.setOnClickListener(this);
        btn3.setOnClickListener(this);

        // 初始化视频路径
        initVideoPath();
    }

    // 设置视频的路径
    private void initVideoPath() {
        // 使用资源文件中的视频路径
        videoView.setVideoPath("android.resource://" + getPackageName() + "/" + R.raw.xbox);
    }

    @Override
    public void onClick(View v) {
        // 根据点击的按钮 ID 执行相应的操作
        if (v.getId() == R.id.btn_start2) {
            // 播放视频
            if (!videoView.isPlaying())
                videoView.start();
        } else if (v.getId() == R.id.btn_pause2) {
            // 暂停视频播放
            if (videoView.isPlaying())
                videoView.pause();
        } else if (v.getId() == R.id.btn_stop2) {
            // 停止视频播放并重新设置视频路径
            if (videoView.isPlaying()) {
                videoView.stopPlayback();
                initVideoPath();
            }
        }
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        // 当活动销毁时,暂停视频播放
        if (videoView != null)
            videoView.suspend();
    }
}


感谢您的阅读
如有错误烦请指正


  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值