videoview实现视频引导页及从assets文件中读取文件到本地SD卡

来源:互联网 发布:神机妙算造价软件价格 编辑:程序博客网 时间:2024/05/21 06:39

视频放在assets文件下,这里的文件不会被编辑,但是使用的时候,需要用流转到本地,然后再使用

关于视频的相关测试数据,在文章最后

需要权限:

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

目录结构:
这里写图片描述
代码:
1、准备工作:
1.1、

import android.os.Environment;/** * 全局变量 */public class CHEN {    // 引导视频存放路径    public static String GuideVideoSavePath = Environment.getExternalStorageDirectory().getAbsolutePath()            + "/chen/guide_video/";    // 引导视频播放路径    public static String GuideVideoPlayPath = "";}

1.2、工具类

import android.text.TextUtils;public class Utils {    /**     * 检查字符串是否是空     *     * @param str     * @return true:字符串为空     */    public static boolean checkStringIsEmpty(String str) {        if (TextUtils.isEmpty(str) || "null".equals(str)) {            return true;        } else {            return false;        }    }}

1.3、styles.xml文件下:这个属性给展示视频的activity,让视频全屏播放

    <style name="fullscreen" parent="AppTheme">        <item name="android:windowFullscreen">true</item>    </style>

2、自定义的videoview(保证能全屏的videoview)

import android.content.Context;import android.util.AttributeSet;import android.widget.VideoView;public class CustomVideoView extends VideoView {    private Context context;    public CustomVideoView(Context context) {        this(context, null);    }    public CustomVideoView(Context context, AttributeSet attrs) {        this(context, attrs, -1);    }    public CustomVideoView(Context context, AttributeSet attrs, int defStyle) {        super(context, attrs, defStyle);        this.context = context;        init();    }    private void init() {       //do something...    }    @Override    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {        //重新计算高度。保证全屏显示        int width = getDefaultSize(0, widthMeasureSpec);        int height = getDefaultSize(0, heightMeasureSpec);        setMeasuredDimension(width, height);    }}

3、使用:
3.1、一开始的MainActivity,布局文件我不做任何处理,就用新建时默认的就行,核心是下一个展示视频的activity

import android.app.Activity;import android.content.Intent;import android.content.res.AssetManager;import android.os.Bundle;import android.os.Handler;import android.util.Log;import java.io.File;import java.io.FileOutputStream;import java.io.IOException;import java.io.InputStream;public class MainActivity extends Activity {    private int time = 3000;    public Handler mHandler = new Handler() {        public void handleMessage(android.os.Message msg) {            switch (msg.what) {                case 100:                    if (!Utils.checkStringIsEmpty(CHEN.GuideVideoPlayPath)) {                        //播放视频成功生成了                        startActivity(new Intent(MainActivity.this, VideoGuideActivity.class));                        MainActivity.this.finish();                    } else {                        //引导视频没有生成                        //do something...                    }                    break;            }        }    };    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        creatGuideVideo();        //sendEmptyMessageDelayed(int what, long delayMillis)        //延时time,发送一个what=100的值        mHandler.sendEmptyMessageDelayed(100, time);    }    /**     * 创建视频引导页文件     */    private void creatGuideVideo() {        new Thread() {            public void run() {                try {                    File path_file = new File(CHEN.GuideVideoSavePath);                    if (!path_file.exists()) {                        try {                            path_file.mkdirs();                        } catch (Exception e) {                            CHEN.GuideVideoPlayPath = "";                        }                    }                    long start = System.currentTimeMillis();                    //第二个参数是生成的文件的名字(包括后缀名),一般和assets文件中要打开的一致                    File file = new File(CHEN.GuideVideoSavePath, "guide_video.mp4");                    if (!file.exists()) {                        AssetManager assetManager = getAssets();// 获取asset管理者                        InputStream in = null;                        FileOutputStream out = null;                        try {                            //assets文件中要打开的文件的名字(包括后缀名)                            in = assetManager.open("guide_video.mp4");                            out = new FileOutputStream(file);                            byte[] b = new byte[1024];                            int len = -1;                            while ((len = in.read(b)) != -1) {                                out.write(b, 0, len);                            }                        } catch (IOException e) {                            e.printStackTrace();                            CHEN.GuideVideoPlayPath = "";                        } finally {                            if (out != null) {                                out.close();                            }                            if (in != null) {                                in.close();                            }                        }                    }                    long end = System.currentTimeMillis();                    Log.e("创建视频引导页播放视频用时===", "" + (end - start));                    CHEN.GuideVideoPlayPath = file.getAbsolutePath();                } catch (Exception e) {                    CHEN.GuideVideoPlayPath = "";                }            }        }.start();    }}

3.2、VideoGuideActivity(为了保证全屏,在清单文件中)

    <!--android:screenOrientation="portrait"是让屏幕旋转时视频不变-->    <!--android:theme="@style/fullscreen"是让这个activity全屏,没有状态栏和标题栏-->    <activity        android:name=".VideoGuideActivity"        android:screenOrientation="portrait"        android:theme="@style/fullscreen"/>
import android.app.Activity;import android.content.BroadcastReceiver;import android.content.Context;import android.content.Intent;import android.content.IntentFilter;import android.media.MediaPlayer;import android.net.Uri;import android.os.Bundle;import android.text.TextUtils;import android.util.Log;import android.widget.Toast;/** * 视频引导页 */public class VideoGuideActivity extends Activity {    CustomVideoView video_view;    private int videoIndex = -1;    /**     * 监听是否点击了home键将客户端推到后台     */    private BroadcastReceiver homeAndLockReceiver = new BroadcastReceiver() {        String SYSTEM_REASON = "reason";        String SYSTEM_HOME_KEY = "homekey";        @Override        public void onReceive(Context context, Intent intent) {            String action = intent.getAction();            if (action.equals(Intent.ACTION_CLOSE_SYSTEM_DIALOGS)) {                String reason = intent.getStringExtra(SYSTEM_REASON);                if (TextUtils.equals(reason, SYSTEM_HOME_KEY)) {                    //表示按了home键,程序到了后台                    video_view.pause();                    //得到当前视频播放的位置。单位是毫秒                    videoIndex = video_view.getCurrentPosition();                    Log.e("videoIndex", videoIndex + "");                }            } else if (action.equals(Intent.ACTION_SCREEN_OFF)) {                //按下锁屏键                video_view.pause();                //得到当前视频播放的位置。单位是毫秒                videoIndex = video_view.getCurrentPosition();                Log.e("videoIndex", videoIndex + "");            }        }    };    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.video_guide_layout);        try {            //注册广播,监听home键及锁屏键的按下            IntentFilter filter = new IntentFilter();            //锁屏广播,由系统发出            filter.addAction(Intent.ACTION_SCREEN_ON);            //锁屏广播,由系统发出            filter.addAction(Intent.ACTION_SCREEN_OFF);            //点击home键广播,由系统发出            filter.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);            registerReceiver(homeAndLockReceiver, filter);            //注册广播结束            video_view = (CustomVideoView) findViewById(R.id.video_view);            /**             * 视频或者音频到结尾时触发的方法             */            video_view.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {                @Override                public void onCompletion(MediaPlayer mp) {                    doSomething();                }            });            /**             * 视频或者音频播放出错触发的方法             */            video_view.setOnErrorListener(new MediaPlayer.OnErrorListener() {                @Override                public boolean onError(MediaPlayer mp, int what, int extra) {                    doSomething();                    return false;                }            });            video_view.setVideoURI(Uri.parse(CHEN.GuideVideoPlayPath));            //播放            video_view.start();        } catch (Exception e) {            doSomething();        }    }    @Override    protected void onRestart() {       super.onRestart();       Log.e("onRestart", videoIndex + "");       //video_view.start();       video_view.seekTo(videoIndex == -1 ? 0 : videoIndex);       //先start,再seekTo,home键回来是重播;先seekTo,再start,都是续播。但是如果距离开始时间较短(经测试,大约10以内,可能有误差),还是会出现重播现象。这些细节,在用的时候,多测试测试。对效果影响不大       video_view.start();    }    @Override    protected void onDestroy() {        super.onDestroy();        if (homeAndLockReceiver != null) {            unregisterReceiver(homeAndLockReceiver);        }    }    //对返回键的监听    @Override    public void onBackPressed() {        super.onBackPressed();        doSomething();    }    /**     * 播放失败、异常时做的事。一般都是跳转到下个页面     */    private void doSomething() {        //do something...        Toast.makeText(this, "do something...", Toast.LENGTH_SHORT).show();    }}

4、测试数据:
一般的使用视频引导页,之前还会有一个图片启动页,最好在图启动页展示的时候,在本地创建视频,然后在视频引导页直接展示。时间上有要求,既要展示启动页,还要尽可能的给本地生成视频文件留下时间:
我测试了3组数据(单位毫秒):

assets中视频文件大小为5.6M时:创建视频引导页播放视频用时===: 570assets中视频文件大小为6.6M时:创建视频引导页播放视频用时===: 648assets中视频文件大小为16M时:创建视频引导页播放视频用时===: 1697

注:我使用的是小米Note,我再使用魅族系列的一个低配手机的时候,出现过一次6.6M视频,在本地创建,时间为2700毫秒左右的情况。同一个手机,每次创建也会有差距,以上数据仅供参考

1 0
原创粉丝点击