美文网首页
Android之简易多媒体应用

Android之简易多媒体应用

作者: bbchond | 来源:发表于2017-12-02 10:21 被阅读48次
    Android老师布置了个播放音乐跟视频的小实验,本来看了下感觉没啥难度......但是自己写的时候一直告诉我获取不到指定的文件路径,这才想起来Android M(即Android 6.0及以上)版本以上让人蛋疼的权限问题。

    Tip:模拟器在Android 6.0一下的可以暂时不用考虑动态权限的申请,然后,不管你模拟器是什么版本,都请在注册文件中先申明读SD卡的权限。

    首先,根据作业要求要实现一个淡入淡出的动画效果,那我们就新建一个Activity,并且命名为SplashActivity:

    public class SplashActivity extends Activity {
    
        Animation animation;
        ImageView img;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_splash);
            img= (ImageView) findViewById(R.id.welcome);
            animation = new AlphaAnimation(0,1);
            animation.setDuration(2000);
            img.startAnimation(animation);
            Timer timer=new Timer();
            TimerTask task=new TimerTask() {
                @Override
                public void run() {
                    Thread t=new Thread(){
                        @Override
                        public void run() {
                            super.run();
                            Intent intent=new Intent(SplashActivity.this,TabHostDemo.class);
                            startActivity(intent);
                            //防止点击返回键之后停止在登录欢迎界面,因此跳转完成后直接结束该Activity
                            finish();
                        }
                    };
                    runOnUiThread(t);
                }
            };
            timer.schedule(task,2000);
        }
    }
    

    这部分要注意的是,在跳转Activity完成之后,需要在startActivity的下一行执行finish操作,将该Activity结束掉,否则跳转完成之后,用户点击返回按钮,将会卡在该欢迎页面。

    淡入淡出的动画效果实现:

    animation = new AlphaAnimation(0,1);
    animation.setDuration(2000);
    img.startAnimation(animation);
    

    这部分其实就是将图片从透明变成不透明......
    该Activity的layout文件:

    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
    
        <ImageView
            android:id="@+id/welcome"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:background="@mipmap/pic01"/>
    
    </LinearLayout>
    

    然后就是实验要求使用的TableHostDemo部分(仅为满足实验要求,使用了该已过时的Activity,在实际开发中建议使用Fragment+ViewPager替代)

    如果你的模拟器是Android 6.0以下,请直接看下列的代码部分即可:

    public class TabHostDemo extends TabActivity {
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_tab_host_demo);
    
            TabHost tabHost=getTabHost();
            TabHost.TabSpec spec;
            spec=tabHost.newTabSpec("0");
            spec.setIndicator("帧动画");
            Intent intent;
            intent=new Intent(TabHostDemo.this,FrameActivity.class);
            spec.setContent(intent);
            tabHost.addTab(spec);
    
            spec=tabHost.newTabSpec("1");
            spec.setIndicator("播放音乐");
            Intent intent1;
            intent1=new Intent(TabHostDemo.this,PlayMusicActivity.class);
            spec.setContent(intent1);
            tabHost.addTab(spec);
    
            spec=tabHost.newTabSpec("3");
            spec.setIndicator("播放视频");
            Intent intent2;
            intent2=new Intent(TabHostDemo.this,PlayVideoActivity.class);
            spec.setContent(intent2);
            tabHost.addTab(spec);
        }
    }
    

    就是简单的TabHost的使用。

    重点来了,如果你的模拟器是Android 6.0及以上的Android版本的,请看这里的代码部分:

    
    public class TabHostDemo extends TabActivity {
    
        private String[] permissions = {Manifest.permission.READ_EXTERNAL_STORAGE};
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_tab_host_demo);
    
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M){
                //检查该权限是否已经获取
                int i = ContextCompat.checkSelfPermission(this, permissions[0]);
                // 权限是否已经 授权 GRANTED---授权  DENIED---拒绝
                if (i != PackageManager.PERMISSION_GRANTED){
                    // 如果没有授予该权限,就去提示用户请求
                    showDialogTipUserRequestPermission();
                }
            }
    
            TabHost tabHost=getTabHost();
            TabHost.TabSpec spec;
            spec=tabHost.newTabSpec("0");
            spec.setIndicator("帧动画");
            Intent intent;
            intent=new Intent(TabHostDemo.this,FrameActivity.class);
            spec.setContent(intent);
            tabHost.addTab(spec);
    
            spec=tabHost.newTabSpec("1");
            spec.setIndicator("播放音乐");
            Intent intent1;
            intent1=new Intent(TabHostDemo.this,PlayMusicActivity.class);
            spec.setContent(intent1);
            tabHost.addTab(spec);
    
            spec=tabHost.newTabSpec("3");
            spec.setIndicator("播放视频");
            Intent intent2;
            intent2=new Intent(TabHostDemo.this,PlayVideoActivity.class);
            spec.setContent(intent2);
            tabHost.addTab(spec);
        }
    
        // 提示用户该请求权限的弹出框
        private void showDialogTipUserRequestPermission(){
            new AlertDialog.Builder(this)
                    .setTitle("没有SD卡读取权限!")
                    .setMessage("没有SD卡读权限将造成程序异常")
                    .setPositiveButton("立即开启", new DialogInterface.OnClickListener() {
                        @Override
                        public void onClick(DialogInterface dialog, int which) {
                            startRequestPermission();
                        }
                    })
                    .setNegativeButton("取消", new DialogInterface.OnClickListener() {
                        @Override
                        public void onClick(DialogInterface dialog, int which) {
                            finish();
                        }
                    }).setCancelable(false).show();
        }
    
        private void startRequestPermission(){
            ActivityCompat.requestPermissions(this,permissions,321);
        }
    
        @Override
        public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
            super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    
            if (requestCode == 321){
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M){
                    if (grantResults[0] != PackageManager.PERMISSION_GRANTED){
                        //判断用户是否点击了不再提醒
                        boolean b = shouldShowRequestPermissionRationale(permissions[0]);
                        if (!b){
                            //提示用户去设置界面手动开启权限
                            showDialogTipUserGoToAppSetting();
                        } else {
                            finish();
                        }
                    } else {
                        Toast.makeText(this, "权限获取成功", Toast.LENGTH_SHORT).show();
                    }
                }
            }
        }
    
        private void showDialogTipUserGoToAppSetting(){
            new AlertDialog.Builder(this)
                    .setTitle("存储权限不可用!")
                    .setMessage("请在设置中立即开启!")
                    .setPositiveButton("确认", new DialogInterface.OnClickListener() {
                        @Override
                        public void onClick(DialogInterface dialog, int which) {
                            Intent intent = new Intent();
                            intent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
                            Uri uri = Uri.fromParts("package",getPackageName(),null);
                            intent.setData(uri);
    
                            startActivityForResult(intent,123);
                        }
                    })
                    .setNegativeButton("取消", new DialogInterface.OnClickListener() {
                        @Override
                        public void onClick(DialogInterface dialog, int which) {
                            finish();
                        }
                    }).setCancelable(false).show();
        }
    
        @Override
        protected void onActivityResult(int requestCode, int resultCode, Intent data) {
            super.onActivityResult(requestCode, resultCode, data);
    
            if (requestCode == 123){
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M){
                    int i = ContextCompat.checkSelfPermission(this,permissions[0]);
                    //权限是否已经授权:GRANTED--授权 DENIED--拒绝
                    if (i != PackageManager.PERMISSION_GRANTED){
                        //如果没有授权
                        Toast.makeText(this, "请到设置界面允许授权", Toast.LENGTH_SHORT).show();
                    }
                }
            }
        }
    }
    

    考虑到部分同学IDE不是Android Studio的情况,因此在这里没有直接compile封装好的权限包,而是遵照百度到的教程老老实实的敲了一遍。大体上就是打开app时,会弹出窗口叫用户进行权限授予:由于读写SD卡被认为是危险权限,因此必须进行动态权限的申请。

    具体过程不再赘述,想要了解的请看下方链接中的文章。
    具体链接:https://www.cnblogs.com/xmcx1995/p/5870191.html

    该Activity的layout文件:

    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:orientation="vertical"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
    
        <TabHost
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:id="@android:id/tabhost">
    
            <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:orientation="vertical">
    
                <TabWidget
                    android:id="@android:id/tabs"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content">
                </TabWidget>
    
                <FrameLayout
                    android:id="@android:id/tabcontent"
                    android:layout_width="match_parent"
                    android:layout_height="match_parent">
    
                </FrameLayout>
    
            </LinearLayout>
    
        </TabHost>
    
    </LinearLayout>
    

    后面便是多媒体文件应用的几个Activity了

    第一个FrameActivity:

    public class FrameActivity extends Activity {
    
        private SoundPool sp;
        private int id1;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_frame);
    
            ImageView imageView = (ImageView) findViewById(R.id.frame_image);
            imageView.setImageResource(R.drawable.frame_animation);
    
            Button buttonStart = (Button) findViewById(R.id.start);
            Button buttonPause = (Button) findViewById(R.id.pause);
    
            sp=new SoundPool(2, AudioManager.STREAM_MUSIC,0);
            id1=sp.load(FrameActivity.this,R.raw.readygo,1);
    
            final AnimationDrawable frameAnimation = (AnimationDrawable) imageView
                    .getDrawable();
    
            buttonStart.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    frameAnimation.start();
                    sp.play(id1,1,1,1,0,1);
                }
            });
    
            buttonPause.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    frameAnimation.stop();
                }
            });
        }
    }
    

    layout文件:

    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
    
        <ImageView
            android:id="@+id/frame_image"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:src="@drawable/frame_animation"
            android:layout_alignParentTop="true"
            android:layout_centerHorizontal="true"
            android:layout_marginTop="168dp" />
    
        <Button
            android:id="@+id/start"
            android:text="开始播放动画"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="16dp"
            android:layout_below="@+id/frame_image"
            android:layout_centerHorizontal="true" />
    
        <Button
            android:id="@+id/pause"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="停止播放动画"
            android:layout_marginTop="15dp"
            android:layout_below="@+id/start"
            android:layout_alignStart="@+id/start" />
    
    </RelativeLayout>
    

    根据实验的要求,在我们点击开始按钮的时候,同时要播放一次"ready go"这个mp3文件,因此我们需要实例化一个SoundPool,用于播放该音乐文件。

    首先,我们在res文件夹下新建一个raw文件夹,用于存放音乐文件:

    raw文件夹的新建
    之后将音乐文件放入raw文件夹,然后用id1=sp.load(FrameActivity.this,R.raw.readygo,1);这行代码获取音乐文件的SoundId。

    接下来是动画部分:我们可以看到,在layout文件中我们给imageView的src指定的是android:src="@drawable/frame_animation"这样一行代码,@drawable/frame_animation其实是我们在drawable文件夹下新建的一个XML文件,其实就是多张图片连起来显示让人认为是动画的一个效果;

    frame_animation下的代码:
    <animation-list xmlns:android="http://schemas.android.com/apk/res/android"
        android:oneshot="false">
    
        <item android:drawable="@drawable/m1" android:duration="50"/>
        <item android:drawable="@drawable/m2" android:duration="50"/>
        <item android:drawable="@drawable/m3" android:duration="50"/>
        <item android:drawable="@drawable/m4" android:duration="50"/>
        <item android:drawable="@drawable/m5" android:duration="50"/>
        <item android:drawable="@drawable/m6" android:duration="50"/>
        <item android:drawable="@drawable/m7" android:duration="50"/>
        <item android:drawable="@drawable/m8" android:duration="50"/>
    
    </animation-list>
    

    我们给每张图片通过duration来指定显示时间为50ms,来达到多张图片连续播放像是在播放动画的效果,其实就是“帧动画”。

    然后是播放音乐部分的Activity:
    public class PlayMusicActivity extends Activity {
    
        ListView listView;
        List<String> listName,listPath;
        MediaPlayer mediaPlayer;
        SeekBar seekBar;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_play_music);
    
            listView = (ListView) findViewById(R.id.listView);
            //指定要播放的音乐文件的路径
            File path = new File(Environment.getExternalStorageDirectory()+"/Music");
            listName = new ArrayList<String>();
            listPath = new ArrayList<String>();
            getMusicLists(path);
            ArrayAdapter<String> adapter = new ArrayAdapter<String>(PlayMusicActivity.this,
                    android.R.layout.simple_list_item_1,listName);
            listView.setAdapter(adapter);
    
            mediaPlayer = new MediaPlayer();
            seekBar = (SeekBar) findViewById(R.id.seekBar);
            setListener();
    
            //拖动SeekBar改变歌曲进度
            seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
                @Override
                public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
    
                }
    
                @Override
                public void onStartTrackingTouch(SeekBar seekBar) {
    
                }
    
                @Override
                public void onStopTrackingTouch(SeekBar seekBar) {
                    //用seekTo直接跳转进度条进度到seekBar当前拖动到的进度位置
                    mediaPlayer.seekTo(seekBar.getProgress());
                }
            });
        }
    
        //listView的单击事件,根据点击到的item来播放对应的歌曲
        private void setListener() {
            listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
                @Override
                public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                    try {
                        if( mediaPlayer != null){
                            mediaPlayer.stop();
                            mediaPlayer.reset();
                        }
                        //根据position来播放点击到的歌曲
                        mediaPlayer.setDataSource(PlayMusicActivity.this, Uri.parse(listPath.get(position)));
                        //mediaPlayer的准备过程
                        mediaPlayer.prepare();
                        mediaPlayer.start();
                        //seekBar获取进度条最大值、设置进度条初始进度为0
                        seekBar.setMax(mediaPlayer.getDuration());
                        seekBar.setProgress(0);
                        ChangeSeekBar();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            });
        }
    
        //进度条当前位置的获取
        private void ChangeSeekBar() {
            final Handler handler = new Handler(){
                @Override
                public void handleMessage(Message msg) {
                    super.handleMessage(msg);
                    //用msg.arg1来传递进度值
                    seekBar.setProgress(msg.arg1);
                }
            };
            Thread t = new Thread(){
                @Override
                public void run() {
                    super.run();
                    while (seekBar.getProgress() < seekBar.getMax()){
                        //获取当前进度
                        int progress = mediaPlayer.getCurrentPosition();
                        Message msg = handler.obtainMessage();
                        //设置msg.arg1的值为progress,实现进度获取
                        msg.arg1 = progress;
                        handler.sendMessage(msg);
    
                        try {
                            Thread.sleep(100);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }
            };
    
            t.start();
        }
    
        //将获取到的音乐文件的名字显示在listView中
        private void getMusicLists(File path) {
            if (path != null){
                if (path.isDirectory()){
                    File[] files = path.listFiles();
                    for (int i = 0; i < files.length; i++) {
                        getMusicLists(files[i]);
                    }
                } else {
                    String musicName = path.getName();
                    String musicPath = path.getAbsolutePath();
                    if (musicName.endsWith(".mp3")){
                        listName.add(musicName);
                        listPath.add(musicPath);
                    }
                }
            }
        }
    }
    

    该说的我都写在注释里了......文章最下面会给出源码文件的链接。
    layout布局:

    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:orientation="vertical"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:weightSum="1">
    
        <TextView
            android:textSize="20sp"
            android:layout_marginTop="20sp"
            android:text="音乐列表"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />
    
        <ListView
            android:layout_marginTop="10sp"
            android:id="@+id/listView"
            android:layout_width="match_parent"
            android:layout_height="377dp"
            android:layout_weight="0.75">
        </ListView>
    
        <SeekBar
            android:id="@+id/seekBar"
            android:layout_width="match_parent"
            android:layout_height="wrap_content" />
    
    </LinearLayout>
    

    这里ListView的大小我是在IDE内直接拖动更改的,不同的人显示的效果不一样,有需要还麻烦自己更改大小了。

    接下来是播放视频的PlayVideoActivity:
    public class PlayVideoActivity extends Activity {
    
        ListView listView;
        List<String> listName,listPath;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_playvideo);
    
            listView = (ListView) findViewById(R.id.videoList);
            //指定要读的视频文件存放的路径
            final File path = new File(Environment.getExternalStorageDirectory()+"/Movies");
            listName = new ArrayList<String>();
            listPath = new ArrayList<String>();
            getVideoLists(path);
            ArrayAdapter<String> video_adapter = new ArrayAdapter<String>(PlayVideoActivity.this,
                    android.R.layout.simple_list_item_1,listName);
            listView.setAdapter(video_adapter);
    
            //listView点击事件
            listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
                @Override
                public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                    Intent intent = new Intent(PlayVideoActivity.this, VideoPlayTest.class);
                    //获取当前ListView中被选中的item的text值,其中text1是simple_list_item_1中的textView的id
                    TextView name = (TextView) view.findViewById(android.R.id.text1);
                    String getName = name.getText().toString();
                    //传递选中的视频文件的路径
                    intent.putExtra("path",path+"/"+getName);
                    startActivity(intent);
                }
            });
        }
    
        //将视频文件的名字显示在listView中
        private void getVideoLists(File path) {
            if (path != null){
                if (path.isDirectory()){
                    File[] files = path.listFiles();
                    for (int i = 0; i < files.length; i++) {
                        getVideoLists(files[i]);
                    }
                } else {
                    String movieName = path.getName();
                    String moviePath = path.getAbsolutePath();
                    if (movieName.endsWith(".3gp")){
                        listName.add(movieName);
                        listPath.add(moviePath);
                    }
                }
            }
        }
    }
    

    (没啥好说的,看注释吧...)
    对应的layout文件:

    <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:textSize="20sp"
            android:layout_marginTop="20sp"
            android:text="视频列表"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />
    
        <ListView
            android:id="@+id/videoList"
            android:layout_width="match_parent"
            android:layout_height="match_parent">
        </ListView>
    
    </LinearLayout>
    

    该activity中单击视频名字之后,将会跳转到一个视频播放的VideoPlayTest:

    public class VideoPlayTest extends Activity {
    
        private VideoView videoView;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_video_play_test);
            videoView = (VideoView) findViewById(R.id.video_view);
            initVideoPath();
        }
    
        private void initVideoPath() {
            //获取刚才的Activity传输过来的播放路径
            String filePath = getIntent().getStringExtra("path");
            File file = new File(filePath);
            videoView.setVideoPath(file.getPath()); // 指定视频文件的路径
            videoView.start();//播放视频
        }
    
        @Override
        protected void onDestroy() {
            super.onDestroy();
            if (videoView != null) {
                videoView.suspend();
            }
        }
    }
    

    对应的layout:

    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:orientation="vertical"
        android:layout_width="match_parent"
        android:layout_height="match_parent" >
    
        <VideoView
            android:id="@+id/video_view"
            android:layout_width="match_parent"
            android:layout_height="wrap_content" />
    
    </LinearLayout>
    

    其中yout中就放了一个VideoView,然后JAVA代码只管播放就好了,基本上能满足本次安卓作业的需求吧。

    附带实验5的源码文件连接:https://gitee.com/bbchond/Exp5_Media_Frame_Video

    相关文章

      网友评论

          本文标题:Android之简易多媒体应用

          本文链接:https://www.haomeiwen.com/subject/afagbxtx.html