Android 学习 09 DAY

Android 学习 09 DAY

【手机多媒体】通知、媒体调用

将程序运行到手机上

使用通知

通知的基本用法

通知的用法比较灵活,既可以在活动里创建,也可以在广播接收器里创建,相比于广播接收器和服务,在活动里创建通知的场景还是比较少的,一般只有当程序进入后台的时候我们才需要使用通知。不过,不论在哪里创建通知,整体的步骤都是相同的,下面我们就来学习一下创建通知的详细步骤。首先需要一个 NotificationManager 来对通知进行管理,可以调用 Context 的 getSystemService() 方法获取到。 getSystemService() 方法接收一个字符串参数用于确定获取系统的那个服务,这里我们传入 Context.NOTIFICATION_SERVICE 即可。因此获取 NotificationManager 的实例就可以写成:

NotificationManager manager = 
    	(NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE);

接下来需要使用一个 Builder 构造器来创建 Notification 对象

 Notification notification = new NotificationCompat.Builder(this)
                        .setContentTitle("this is content title")
                        .setContentText("This is content text")
                        .setWhen(System.currentTimeMillis())
                        .setSmallIcon(R.mipmap.ic_launcher)
                        .setContentIntent(pi)
                        .setPriority(NotificationCompat.PRIORITY_MAX)
                        .build();

setWhen() 方法用于指定通知被创建的时间,一毫秒为单位。

以上工作都完成后,只需调用 NotificationManager 的 notify() 方法就能让通知显示出来了。notify() 方法接收两个参数,一个参数是 id,要保证为每个通知所指定的 id 都是不同的,第二个参数则是 Notification 对象。以下未调用示例:

manager.notify(1, notification);

下面新建一个 NotificationTest 项目,并修改 activity_main.xml 中的代码,如下所示:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".MainActivity">

    <Button
        android:id="@+id/send_notice"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Send notice" />

</LinearLayout>

添加一个按钮,用于发出通知。下面修改 MainActivity.java 中的代码,如下

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 v) {
        switch (v.getId()) {

            case R.id.send_notice:
                NotificationManager manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
                Notification notification = new NotificationCompat.Builder(this)
                        .setContentTitle("this is content title")
                        .setContentText("This is content text")
                        .setWhen(System.currentTimeMillis())
                        .setSmallIcon(R.mipmap.ic_launcher)
                        .setPriority(NotificationCompat.PRIORITY_MAX)
                        .build();
                manager.notify(1, notification);
                break;
            default:
                break;
        }
    }
}

现在运行程序,点击按钮,就会看到系统状态栏中出现了一个通知。下面我们要为这个通知添加一个点击响应,这就涉及了一个新的概念:PendingIntent。

PendingIntent 于 Intent 有些相似,不同的是,Intent 更加倾向于去立即执行某个动作,而 PendingIntent 更加倾向于在某个合适的时机去执行某个动作。所以可以把PendingIntent 简单地理解为延时执行的 Intent。

PendingIntent 主要提供了几种静态调用方法用于获取 PendingIntent 的实例,根据需求可以选择使用 getActivity、getBroadcast、getService 这几种方法,这几种方法所接收的参数都是相同的,第一个是 Context。第二个参数一般用不到,通常传入 0 即可。第三个参数是一个 Intent 对象,我们可以通过这个对象构建出 PendingIntent 的意图。第四个参数用于确定 PendingIntent 的行为,有 FLAG_ONE_SHOT、FLAG_NO_CREATE、FLAG_CANCEL_CURRENT 和 FLAG_UPDATE_CURRENT 这 4 种值可选,通常情况下传入 0 就可以了。

NotificationCompat.Builder 这个构造器还可以再连缀一个 setContentIntent() 方法,接收的参数是一个 PendingIntent 对象。这里就可以通过 PendingIntent 对象构建出一个延迟执行的意图。

新建一个活动命名为 NotificationActivity 并添加一个布局命名为 notification_layout:

NotificationActivity.java

public class NotificationActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.notification_layout);
        
        // 点击响应后自动清除通知
        NotificationManager manager = 
            (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
        manager.cancel(1);
    }
}

notification_layout.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".NotificationActivity">

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

下面修改 MainActivity.java 代码

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 v) {
        switch (v.getId()) {

            case R.id.send_notice:
                Intent intent = 
                    new Intent(this, NotificationActivity.class);
                PendingIntent pi = 
                    PendingIntent.getActivity(this, 0, intent, 0);
                NotificationManager manager = 
                    (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
                
                Notification notification = 
                    new NotificationCompat.Builder(this)
                        .setContentTitle("this is content title")
                        .setContentText("This is content text")
                        .setWhen(System.currentTimeMillis())
                        .setSmallIcon(R.mipmap.ic_launcher)
                        .setContentIntent(pi)
                        .setPriority(NotificationCompat.PRIORITY_MAX)
                        .build();
                manager.notify(1, notification);
                
                break;
            default:
                break;
        }
    }
}

点击响应清除通知还能在 NotificationCompat.Builder 这个构造器后面连缀一个 setAutoCancel(true) 来实现

Notification notification = new NotificationCompat.Builder(this)
    ...
    .setAutoCancel(true)
    .build();

通知的进阶技巧

实际上 NotificationCompat.Builder 中提供了丰富的 API 能够创建出更加多样的通知效果,下面将介绍一些比较常用的 API。

  • setSound() 方法 :可以在通知发出的时候播放一段音频,接收一个 Uri 参数,在指定音频文件的时候还需要先获取到音频文件对应的 URI。例如:
Notification notification = new NotificationCompat.Builder(this)
    ...
    .setSound(Uri.fromFile(
        new File("/system/media/audio/ringtones/Luna.ogg")))
    .build();

除了允许播放音频外,我们还可以在通知到来的时候让手机进行振动,使用的是 vibrate 这个属性。它是一个长整型的数组,用于设置手机静止和振动的时长,一毫秒为单位。下标为 0 的值表示手机静止的时长,下标为 1 的值表示手机振动的时长,下标为2的值又表示手机静止的时长,以此类推。例:让手机在通知到来的时候立刻振动1秒,然后静止1秒,再振动1秒:

Notification notification = new NotificationCompat.Builder(this)
    ...
    .setVibrate(new long[]{ 0, 1000, 1000, 1000 })
    .build();

不过,想要控制手机振动还需要声明权限。因此,还需要编辑 AndroidManifest.xml 加入以下声明:

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

通知的高级功能

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

长文字

在 setStyle() 方法中创建一个 NotificationCompat.BigTextStyle 对象,这个对象就是用于封账长文字信息的,我们调用它的 bigText() 方法并将文字传入就可以了。

Notification notification = new NotificationCompat.Builder(this)
    ...
    .setStyle(new NotificationCompat.BigTextStyle()
             .bigText("...................................\
                      ....................................\
                      ....................................")) 
    .build();

除了显示长文字,通知里还可以显示一张大图片,具体用法也是基本相似:

Notification notification = new NotificationCompat.Builder(this)
    ...
    .setStyle(new NotificationCompat.BigPictureStyle()
             .bigPicture(BitmapFactory.decodeResource(getResources(), 
             	R.drawable.big_image))) 
    .build();
  • setPriority() 方法接收一个整型参数用于设置这条通知的重要程度,一共有5个常量值可选:

PRIORITY_DEFAULT:表示默认重要程度,和不设置是一样的;

PRIORITY_MIN:表示最低的重要程度,系统可能只会在特定场景才显示这条通知;

PRIORITY_LOW:表示较低的重要程度,系统可能会将这类通知缩小,或改变显示顺序,将其排在更重要的通知之后;

PRIORITY_HIGH:表示较高的重要程度,系统可能会将这类通知放大或改变其显示顺序,并将其排在比较靠前的位置;

PRIORITY_MAX:表示最高的重要程度,这类通知必须要让用户立刻看到,甚至需要用户做出响应;

Notification notification = 
    new NotificationCompat.Builder(this)
		...
        .setPriority(NotificationCompat.PRIORITY_MAX)
        .build();

调用摄像头和相册

新建一个项目 CameraAlbumTest ,然后修改 activity_main.xml 中的代码

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".MainActivity">

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

添加了两个 Button 和一个 ImageView。Button 是分别用于打开摄像头和相册的,ImageView 是用于将图片显示出来的。然后开始编写摄像头的具体逻辑,修改 MainActivity.java 中的代码。

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 takePhoto = (Button) findViewById(R.id.take_photo);
        Button chooseFromAlbum = (Button) findViewById(R.id.choose_from_album);
        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();
                }

                imageUri = FileProvider.getUriForFile(
                    			MainActivity.this,
                    			"com.example.cameraalbumtest.fileprovider", 
                        		outputImage);
                
                // 启动相机程序
                Intent intent = 
                    new Intent("android.media.action.IMAGE_CAPTURE");
                
                intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);
                startActivityForResult(intent, TAKE_PHOTO);
            }
        });

        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[] permission, 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) {

        super.onActivityResult(requestCode, resultCode, 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;
            case CHOOSE_PHOTO:
                if (resultCode == RESULT_OK) {
                    handleImageOmKitKat(data); // 处理图片
                }
            default:
                break;
        }
    }

    @TargetApi(19)
    private void handleImageOmKitKat(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.dowloads.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 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();
        }
    }

    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;
    }


}

上述代码中调用相机部分,首先创建了一个 File 对象用于存放摄像头拍下的照片,我们把图片命名为output_image.jpg ,并将它存放在手机应用相关联的缓存目录下。调用 getExternalCacheDir() 方法可以得到这个目录,接着调用getUrifroFile() 方法接收三个参数,第一个参数要求是 Context 对象,第二个参数可以是任意唯一的字符串,第三个参数是刚刚创建的 File 对象。

接下来构建出一个 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 中显示出来。

对于图库的使用,我们需要动态申请 WRITE_EXTERNAL_STORAGE 这个危险权限,因为需要从 SD 卡中读取照片就需要申请这个权限。WRITE_EXTERNAL_STORAGE 表示同时授权程序对 SD 卡读和写的能力。当用户授权了权限申请之后会调用 openAlbum() 方法,这里先是构建了一个 Intent 对象,并将它的 action 指定为 android.intent.action.GET_CONTENT。接着给这个 Intent 对象设置一些必要的参数,然后调用 startActivityForResult() ,这样我们在 onActivityResult() 中添加图库调用的分支,如果读取图片成功,就执行 handleImageOmKitKat() 方法,这个方法中的逻辑基本内容是解析这个封装过的 Uri 。如果返回的 Uri 是 document 类型的话,那就取出 document id 进行处理,如果不是的话,那就使用普通的方式处理。另外,如果的 authority 是 media 格式的话,document id 还需要再进行一次解析,要通过字符串分割的方式取出后半部分才能得到真正的数字 id。取出的 id 用于构建新的 Uri 和条件语句,把这些值作为参数传入到 getImagePath() 方法中就可以获取到图片的真实路径了。拿到图片的路径之后,再调用 displayImage() 方法将图片显示到界面上。

接下来需要在 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/Theme.CameraAlbumTest">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <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>
    </application>

</manifest>

其中,android:name 属性值是固定的, android:authorities 属性值必须要和刚才 FileProvider.getURIForFile() 方法中的第二个参数一致。另外在 <provider> 标签的内部使用 <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 卡进行共享,当然你也可以仅共享我们存放 output_image.jpg 这张图片的路径。

运行程序,点击两个按钮测试,均可正常操作。

播放多媒体文件

播放音频

在 Android 中音频文件一般都是使用 MediaPlayer 类来实现的,它对多种格式的音频文件提供了非常全面的控制方法,从而使得播放音乐的工作变动十分简单。下表列出了 MediaPlayer 类中一些较为常用的控制方法。

方法名功能描述
setDataSource()设置要播放的音频文件的位置
prepare()在开始播放之前调用这个方法完成准备工作
start()开始或继续播放音频
pause()暂停播放音频
reset()将MediaPlayer对象重置到刚刚创建的状态
seekTo()从指定的位置开始播放音频
stop()停止播放音频。调用这个方法后的MediaPlayer对象无法在播放音频
release()释放掉与MediaPlayer对象相关的资源
isPlaying()判断当前MediaPlayer是否正在播放音频
getDuration()获取载入的音频文件的时长

MediaPlayer 的工作流程。首先需要创建一个 MediaPlayer 对象,然后调用 setDataSource() 方法来设置音频文件的路径,再调用 pause() 方法就会暂停播放,调用 reset() 就会停止播放。

新建一个 PlayAudioTest 项目,然后修改 activity_main.xml 中的代码,如下:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".MainActivity">

    <Button
        android:id="@+id/play"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Play" />

    <Button
        android:id="@+id/pause"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Pause" />

    <Button
        android:id="@+id/stop"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Stop" />

</LinearLayout>

然后修改 MainActivity.java

public class MainActivity extends AppCompatActivity implements View.OnClickListener {

    private MediaPlayer mediaPlayer = new MediaPlayer();

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

        Button play = (Button) findViewById(R.id.play);
        Button pause = (Button) findViewById(R.id.pause);
        Button stop = (Button) findViewById(R.id.stop);

        play.setOnClickListener(this);
        pause.setOnClickListener(this);
        stop.setOnClickListener(this);
        
        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 {
            initMediaPlayer(); // 初始化 MediaPlayer 
        }
        

    }

    private void initMediaPlayer() {
        try {
            File file = new File(Environment.getDownloadCacheDirectory(),
                    "music.mp3");
            mediaPlayer.setDataSource(file.getPath()); // 指定音频文件的路径
            mediaPlayer.prepare(); // 让 MediaPlayer 进入到准备状态
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, String[] permissions,
                                           int[] grantResults) {
        switch (requestCode) {
            case 1:
                if(grantResults.length > 0
                && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                    initMediaPlayer();
                } else {
                    Toast.makeText(this, "拒绝权限无法使用",
                            Toast.LENGTH_SHORT).show();
                    finish();
                }
                break;
            default:
        }
    }

    @Override
    public void onClick(View view) {
        switch (view.getId()) {
            case R.id.play:
                if(!mediaPlayer.isPlaying()) {
                    mediaPlayer.start();
                }
                break;
            case R.id.pause:
                if(!mediaPlayer.isPlaying()) {
                    mediaPlayer.pause();
                }
                break;
            case R.id.stop:
                if(!mediaPlayer.isPlaying()) {
                    mediaPlayer.stop();
                }
                break;
            default:
                break;
        }
    }


    @Override
    protected void onDestroy() {
        super.onDestroy();
        if(mediaPlayer != null) {
            mediaPlayer.stop();
            mediaPlayer.release();
        }
    }


}

最后在 AndroidManifest.xml 中添加权限

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

播放视频

播放视频与播放音频类似,主要是使用 VideoView 类来实现的。这个类将视频的显示和控制集于一身,使得我们仅仅借助它就可以完成一个建议的视频播放器。主要用法如下:

方法名功能描述
setVideoPath()设置要播放的视频文件的位置
start()开始或继续播放视频
pause()暂停播放视频
seekTo()从指定的位置开始播放视频
isPlaying()判断当前是否正在播放视频
getDuration()获取载入的视频文件的时长
suspend()释放资源

新建项目 PlayVideoTest 项目,然后修改 activity_main 中的代码


接下修改 MainActivity.java 代码


最后在 AndroidManif.xml 添加权限


最后运行程序,符合预期。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值