9.Android学习之动画与多媒体(二)

目录

9.动画与多媒体(二)

2.播放音频与视频

2-1.使用MediaPlayer类播放音频

2-2.使用SoundPool类播放音频

2-3.使用 VideoView组件播放视频

4.难点解答

4-1.MediaPlayer 与SoundPool的区别

4-2.MediaController 的作用

9.动画与多媒体(二)

2.播放音频与视频

Android提供了对常用音频和视频格式的支持,它所支持的音频格式有MP3 ( .mp3)、3GPP(.3gp)、Ogg (.ogg)和WAVE (.wav)等,支持的视频格式有3GPP (.3gp) 和MPEG-4 (.mp4)等。通过Android API提供的相关方法,可以在Android中实现音频与视频的播放。

2-1.使用MediaPlayer类播放音频

在Android中,提供了MediaPlayer 类来播放音频。使用MediaPlayer 类播放音频比较简单,只需创建该类的对象,并为其指定要播放的音频文件,然后调用该类的start()方法播放即可。MediaPlayer中有许多方法,其中比较常用的方法及其描述如表9.6 所示。

表9.6 MediaPlayer 类中的常用方法

方法描述
create(Context context, int resid)根据指定的资源ID创建一个 MediaPlayer 对象
create(Context context, Uri uri)根据指定的URI创建一个 MediaPlayer 对象
setDataSource()指定要装载的资源
prepare()准备播放(在播放前调用)
start()开始播放
stop()停止播放
pause()暂停播放
reset()恢复MediaPlayer到未初始化状态

下面对如何使用MediaPlayar类播放音频进行详细介绍。

1.创建MediaPlayer对象并装载音频文件

创建MediaPlayer对象并装载音频文件,可以使用MediaPlayer类提供的静态方法create()来实现,也可以通过其无参构造方法来创建并实例化该类的对象来实现。

(1)使用create()方法创建MediaPlayer对象并装载音频文件。

MediaPlayer类的静态方法create()常用的语法格式有以下两种:

◆create(Context context, int resid)

用于从资源ID所对应的资源文件中装载音频,并返回新创建的MediaPlayer对象。例如,要创建装载音频资源(res\raw\d.wav) 的MediaPlayer对象,可以使用下面的代码:

MediaPlayer player=MediaPlayer.create(this,R.raw.d);

◆create(Context context, Uri uri)

用于根据指定的URI来装载音频并返回新创建的MediaPlayer对象。例如要创建装载了音频文件(URI地址为https://www.hhh.com/sound/hhh.mp3)的MediaPlayer对象,可以使用下面的代码:

MediaPlayer player=MediaPlayer.create(this,Uri.parse("https://www.hhh.com/sound/hhh.mp3"));

注:在访问网络中的资源时,要在AndroidManifest.xml文件中授于该程序访问网络的权限,具体的授权代码如下:

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

(2)通过无参的构造方法来创建MediaPlayer对象并装载音频文件。

使用无参的构造方法来创建MediaPlayer对象时,需要单独指定要装载的资源,这可以使用MediaPlayer类的setDataSource()方法实现。

在使用setDataSource()方法装载音频文件后,实际上MediaPlayer并未真正装载该音频文件,还需要调用MediaPlayer的prepare()方法去真正装载音频文件。使用无参的构造方法来创建MediaPlayer对象并装载指定的音频文件,可以使用下面的代码:

MediaPlayer player1=new MediaPlayer();
try {
    player1.setDataSource("/sdcard/music.mp3");//指定要装载的音频文件
    player1.prepare();//预加载音频
}catch (I0Exception e) {
    e.printStackTrace();
}

注:通过MediaPlayer类的静态方法create()来创建MediaPlayer对象时,已经装载了要播放的音频,所以这种方法适用于播放单独的音频文件时。而通过无参的构造方法来创建MediaPlayer对象并装载音频文件时,可以根据需要来随时改变要加载的文件,所以这种方法适用于连续播放多个文件时。

2.开始或恢复播放

在获取到MediaPlayer对象后,就可以使用MediaPlayer类提供的start()方法来开始播放音频或恢复播放已经暂停的音频。例如,已经创建了一 个名称为“player” 的对象,并且装载了要播放的音频,可以使用下面的代码播放该音频:

player.start();//开始播放

3.停止播放

使用MediaPlayer类提供的stop()方法可以停止正在播放的音频。例如,已经创建了一个名称为“player” 的对象,并且已经开始播放装载的音频,可以使用下面的代码停止播放该音频:

player.stop();//停止播放

4.暂停播放

使用MediaPlayer类提供的pause()方法可以暂停正在播放的音频。例如,已经创建了一个名称为“player”的对象,并且已经开始播放装载的音频,可以使用下面的代码暂停播放该音频:

player.pause();//暂停播放

例:

MainActivity.java

package com.example.musicplayer;
​
import androidx.appcompat.app.ActionBar;
import androidx.appcompat.app.AppCompatActivity;
​
import android.media.MediaParser;
import android.media.MediaPlayer;
import android.net.Uri;
import android.os.Bundle;
import android.view.View;
import android.view.WindowManager;
import android.widget.ImageButton;
import android.widget.Toast;
​
import java.io.File;
import java.io.IOException;
​
public class MainActivity extends AppCompatActivity {
    private MediaPlayer mediaPlayer;//定义MediaPlayer对象
    private boolean isPause = false;//定义是否暂停
    private File file;//定义要播放的音频文件
​
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        ActionBar actionBar=getSupportActionBar();
        actionBar.hide();
        //设置全屏显示
        getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
                WindowManager.LayoutParams.FLAG_FULLSCREEN);
        //获取“播放/暂停”按钮
        final ImageButton btn_play=(ImageButton) findViewById(R.id.main_ib1);
        //获取“停止”按钮
        final ImageButton btn_stop=(ImageButton) findViewById(R.id.main_ib2);
        file=new File("/sdcard/music.mp3");
        //如果音频文件存在
        if(file.exists()){
            //创建MediaPlayer对象,并解析要播放的音频文件
            mediaPlayer=MediaPlayer.create(this, Uri.parse(file.getAbsolutePath()));
        }else{
            //提示音频文件不存在
            Toast.makeText(MainActivity.this, "要播放的音频文件不存在!", Toast.LENGTH_SHORT).show();
            return;
        }
​
        //为MediaPlayer添加完成事件监听器,实现当音频播放完毕后,重新开始播放音频
        mediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
            @Override
            public void onCompletion(MediaPlayer mediaPlayer) {
                play();//调用play()方法,实现播放功能
            }
        });
​
        btn_play.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                if(mediaPlayer.isPlaying() && !isPause){//暂停播放
                    mediaPlayer.pause();
                    isPause=true;
                    //更换为播放图标
                    ((ImageButton) view).setImageDrawable(getResources()
                    .getDrawable(R.drawable.play,null));
                }else{//继续播放
                    mediaPlayer.start();
                    //更换为暂停图标
                    ((ImageButton) view).setImageDrawable(getResources()
                            .getDrawable(R.drawable.pause,null));
                    isPause=false;
                }
            }
        });
​
        btn_stop.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                mediaPlayer.stop();//停止播放
                //更换为播放图标
                btn_play.setImageDrawable(getResources()
                        .getDrawable(R.drawable.play,null));
            }
        });
    }
    //音频播放
    private void play(){
        try{
            mediaPlayer.reset();//重置MediaPlayer对象
            mediaPlayer.setDataSource(file.getAbsolutePath());//重新设置要播放的音频
            mediaPlayer.prepare();//预加载音频
            mediaPlayer.start();//开始播放
        } catch (Exception e) {
            e.printStackTrace();//输出异常信息
        }
    }
​
    //当前Activity销毁时
    protected void onDestory(){
        if(mediaPlayer.isPlaying()){
            mediaPlayer.stop();
        }
        mediaPlayer.release();//释放资源
        super.onDestroy();
    }
​
}

注:要访问SD卡的文件,需要在AndroidManifest.xml文件中赋予程序访问SD卡的权限,关键代码如下:

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

application节点下

android:requestLegacyExternalStorage="true"

2-2.使用SoundPool类播放音频

Android还提供了另一个播放音频的类——SoundPool (即音频池),可以同时播放多个短小的音频,而且占用的资源较少。使用SoundPool类播放音频,首先需要创建SoundPool对象,然后加载所要播放的音频,最后调用play()方法播放音频。

1.创建SoundPool对象

SoundPool类提供了一个构造方法,用来创建SoundPool对象,该构造方法的语法格式如下:

SoundPool(int maxStreams,int streamType,int srcQuality)

参数说明如下:

◆maxStreams:指定可以容纳多少个音频。

◆streamType::指定声音类型,可以通过AudioManager类提供的常量进行指定,通常使用STREAM_MUSIC。

◆srcQuality:指定音频的品质,默认值为0。

例如,创建个可以容纳 10个音频的SoundPool对象,可以使用下面的代码:

//创建一个SoundPoo1对象, 该对象可以容纳10个音频流
oundPool soundpool = new SoundPool(10,AudioManager.STREAM_SYSTEM, 0);

2.加载所要播放的音频

创建SoundPool 对象后,可以调用load()方法来加载要播放的音频。load()方法的语法格式有以下4种:

◆public int load (Context context, int resld, int priority):通过指定的资源ID来加载音频。

◆public int load (String path, int priority):通过音频文件的路径来加载音频。

◆public int load (AssetFileDescriptor afd, int priority):从AssetFileDescriptor所对应的文件中加载音频。

◆public int load (FileDescriptor fd, long offset, long length, int priority):加载FileDescriptor对象中从offset开始,长度为length的音频。

例如,要通过资源ID来加载音频文件ding.wav,可以使用下面的代码:

soundpool.load(this,R.raw.ding,1);

注:为了更好地管理所加载的每个音频,一般使用HashMap<Integer, Integer>对象来管理这些音频。这时可以先创建一个HashMap<Integer, Integer>对象,然后应用该对象的put()方法将加载的音频保存到该对象中。例如,创建一个HashMap<Integer, Integer>对象,并应用put() 方法添加一个音频,可以使用下面的代码:

//创建一个HashMap对象
HashMap<Integer,Integer> soundmap = new HashMap<Integer,Integer>();
soundmap.put(1, soundpool.load(this, R.raw.chimes, 1));

3.播放音频

调用SoundPool对象的play()方法可播放指定的音频。play() 方法的语法格式如下:

play (int soundID, float leftVolume, float rightVolume, int priority, int loop, float rate)

play()方法各参数的说明如表9.7 所示。

表9.7 play() 方法的参数说明

参数描述
soundID指定要播放的音频,该音频为通过load() 方法返回的音频
leftVolume指定左声道的音量,取值范围为0.0~1.0
rightVolume指定右声道的音量,取值范围为0.0~1.0
priority指定播放音频的优先级,数值越大,优先级越高
loop指定循环次数,0为不循环,-1 为循环
rate指定速率,正常为1,最低为0.5, 最高为2

例如,要播放raw资源中保存的音频文件notify.wav,可以使用下面的代码:

//播放指定的音频
soundpool.play(soundpool.load(MainActivity.this,R.raw.notify, 1), 1, 1, 0, 0, 1);

例:

activity_main.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=".MainActivity">
​
​
    <ListView
        android:id="@+id/main_lv1"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>
​
</RelativeLayout>

main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:padding="10dp"
        android:layout_gravity="center"
        android:id="@+id/title"
        android:textSize="22sp"
        />
</LinearLayout>

MainActivity.java

package com.example.selectringtone;
​
import androidx.appcompat.app.ActionBar;
import androidx.appcompat.app.AppCompatActivity;
​
import android.media.AudioAttributes;
import android.media.SoundPool;
import android.os.Bundle;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ListView;
import android.widget.SimpleAdapter;
​
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
​
public class MainActivity extends AppCompatActivity {
​
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        ActionBar actionBar=getSupportActionBar();
        actionBar.hide();
​
        ListView listView=(ListView) findViewById(R.id.main_lv1);//获取列表视图
        String[] title=new String[]{"江南","关键词","爱不会绝迹","修炼爱情",
        "那些你很冒险的梦","爱笑的眼睛","一千年以后"};//定义并初始化保存列表项文字的数组
        //创建一个list集合
        List<Map<String,Object>> listItems=new ArrayList<Map<String,Object>>();
        //通过for循环将列表项文字保存到Map中,并添加到List集合中
        for(int i=0;i<title.length;i++){
            Map<String,Object> map=new HashMap<String,Object>();//实例化Map对象
            map.put("name",title[i]);
            listItems.add(map);//将Map对象添加到List集合中
        }
​
        AudioAttributes attr=new AudioAttributes.Builder()//设置音效相关属性
                .setUsage(AudioAttributes.USAGE_GAME)//设置音效使用场景
                .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)//设置音效的类型
                .build();
        final SoundPool soundPool=new SoundPool.Builder()//创建SoundPool对象
                .setAudioAttributes(attr)//设置音效池的属性
                .setMaxStreams(10)//设置最多可容纳10个音频流
                .build();
​
        final HashMap<Integer,Integer> soundmap=new HashMap<Integer,Integer>();
        //保存要播放的音频流到HashMap对象中
        soundmap.put(0,soundPool.load(this,R.raw.jiangnan,1));
        soundmap.put(1,soundPool.load(this,R.raw.guanjianci,1));
        soundmap.put(2,soundPool.load(this,R.raw.aibuhuijueji,1));
        soundmap.put(3,soundPool.load(this,R.raw.xiulianaiqing,1));
        soundmap.put(4,soundPool.load(this,R.raw.naxienihenmaoxiandemeng,1));
        soundmap.put(5,soundPool.load(this,R.raw.aixiaodeyanjing,1));
        soundmap.put(6,soundPool.load(this,R.raw.yiqiannianyihou,1));
​
        //创建SimpleAdapter适配器
        SimpleAdapter adapter=new SimpleAdapter(this,listItems,
                R.layout.main,new String[]{"name",},new int[]{R.id.title});
        listView.setAdapter(adapter);//将适配器与ListView关联
​
        listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
                //获取选项的值
                Map<String,Object> map=(Map<String, Object>) adapterView.getItemAtPosition(i);
                //播放所选音频
                soundPool.play(soundmap.get(i),1,1,0,0,1);
            }
        });
    }
}

2-3.使用 VideoView组件播放视频

在Android中提供了VideoView组件用于播放视频文件。要想使用VideoView组件播放视频,首先需要在布局文件中添加该组件, 然后在Activity 中获取该组件,并应用其setVideoPath()方法或setVideoURI()方法加载要播放的视频,最后调用start()方法来播放视频。另外,VideoView组件还提供了stop()和pause()方法,分别用于停止和暂停视频的播放。

在布局文件中添加VideoView组件的基本语法格式如下:

<VideoView
           属性列表>
</VideoView>

VideoView组件支持的XML属性如表9.8所示。

表9.8 VideoView 组件支持的XML 属性

XML属性描述
android:id设置组件的ID
android:background设置背景,可以设置背景图片,也可以设置背景颜色
android:layout_gravity设置对齐方式
android:layout_width设置宽度
android:layout_height设置高度

在Android中还提供了一个可以与VideoView组件结合使用的MediaController组件。MediaController组件用于通过图形控制界面来控制视频的播放。

例:

activity_main.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=".MainActivity">
​
    <VideoView
        android:id="@+id/main_vv1"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>
</RelativeLayout>

MainActivity.java

package com.example.videoviewandmediacontroller;
​
import androidx.appcompat.app.ActionBar;
import androidx.appcompat.app.AppCompatActivity;
​
import android.media.MediaPlayer;
import android.os.Bundle;
import android.os.Environment;
import android.view.WindowManager;
import android.widget.MediaController;
import android.widget.Toast;
import android.widget.VideoView;
​
import java.io.File;
​
public class MainActivity extends AppCompatActivity {
​
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        ActionBar actionBar=getSupportActionBar();
        actionBar.hide();
​
        //设置全屏显示
        getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
                WindowManager.LayoutParams.FLAG_FULLSCREEN);
        VideoView videoView=(VideoView) findViewById(R.id.main_vv1);
        //指定播放模拟器SD卡上的视频文件
        File file=new File(Environment.getExternalStorageDirectory()+"/aishang.mp4");
        //创建android.widget.MediaController对象,控制视频的播放
        MediaController mediaController=new MediaController(MainActivity.this);
​
        if(file.exists()){//判断要播放的视频文件是否存在
            videoView.setVideoPath(file.getAbsolutePath());//指定要播放的视频
            videoView.setMediaController(mediaController);//设置VideoView与MediaController相关联
            videoView.requestFocus();//让VideoView获得焦点
            try {
                videoView.start();//开始播放视频
            } catch (Exception e) {
                e.printStackTrace();//输出异常信息
            }
            //为VideoView添加完成事件监听器,实现视频播放结束后的提示信息
            videoView.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
                @Override
                public void onCompletion(MediaPlayer mediaPlayer) {
                    //弹出消息提示框显示播放完毕
                    Toast.makeText(MainActivity.this, "视频播放完毕!", Toast.LENGTH_SHORT).show();
                }
            });
        }
        else {
            //弹出消息提示框提示文件不存在
            Toast.makeText(MainActivity.this,"要播放的视频文件不存在", Toast.LENGTH_SHORT).show();
        }
    }
}

AndroidManifest.xml

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
    <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"
        tools:ignore="ProtectedPermissions" />

AndroidManifest.xml的application节点下:

android:requestLegacyExternalStorage="true"

4.难点解答

4-1.MediaPlayer 与SoundPool的区别

使用MediaPlayer每次只能播放一-个音频,适用于播放长音乐或是背景音乐;使用SoundPool可以同时播放多个短小的音频,而且占用的资源较少,适用于播放按键音或者消息提示音等。

4-2.MediaController 的作用

MediaController是一个与MediaPlayer相匹配的Android控件,它主要集合了媒体播放器的控制功能,用于控制MediaPlayer播放状态的同步。通常包含“播放/暂停”“后退”“快进”和进度滑块等按钮。实例化此类后,MediaController 将创建一组默认的控件, 并且浮动在界面的最上层。如果空闲3秒钟,窗口将消失,当用户触摸锚定视图时,窗口将重新出现。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值