• 使用Vitamio打造自己的Android万能播放器(7)——在线播放(下载视频)



    前言

      本章将实现非常实用的功能——下载在线视频。涉及到多线程、线程更新UI等技术,还需思考产品的设计,如何将新加的功能更好的融入到现有的产品中,并不是简单的加一个界面就行了,欢迎大家交流产品设计和技术细节实现!
     
    声明
      欢迎转载,但请保留文章原始出处:) 
        博客园:http://www.cnblogs.com
        农民伯伯: http://over140.cnblogs.com 
     
    系列
      4、使用Vitamio打造自己的Android万能播放器(4)——本地播放(快捷搜索、数据存储)
      5、使用Vitamio打造自己的Android万能播放器(5)——在线播放(播放优酷视频)
    正文
      一、目标

        本章实现视频下载的功能

          

        使用说明:进入在线视频,点击播放时将弹出选择框询问播放还是下载,点击下载后进度条将在本地视频顶部显示。如果想边看便下载,请直接点击本地播放列表中正在下载的视频。

      二、实现(部分主要实现代码)
        FileDownloadHelper
    public class FileDownloadHelper {
        private static final String TAG = "FileDownloadHelper";
        /** 线程池 */
        private ThreadPool mPool = new ThreadPool();
        /** 开始下载 */
        public static final int MESSAGE_START = 0;
        /** 更新进度 */
        public static final int MESSAGE_PROGRESS = 1;
        /** 下载结束 */
        public static final int MESSAGE_STOP = 2;
        /** 下载出错 */
        public static final int MESSAGE_ERROR = 3;
        /** 中途终止 */
        private volatile boolean mIsStop = false;
        private Handler mHandler;
        public volatile HashMap<String, String> mDownloadUrls = new HashMap<String, String>();

        public FileDownloadHelper(Handler handler) {
            if (handler == null)
                throw new IllegalArgumentException("handler不能为空!");

            this.mHandler = handler;
        }

        public void stopALl() {
            mIsStop = true;
            mPool.stop();
        }

        public void newDownloadFile(final String url) {
            newDownloadFile(url, Environment.getExternalStorageDirectory() + "/" + FileUtils.getUrlFileName(url));
        }

        /**
         * 下载一个新的文件
         * 
         * 
    @param url
         * 
    @param savePath
         
    */
        public void newDownloadFile(final String url, final String savePath) {
            if (mDownloadUrls.containsKey(url))
                return;
            else
                mDownloadUrls.put(url, savePath);
            mPool.start(new Runnable() {

                @Override
                public void run() {
                    mHandler.sendMessage(mHandler.obtainMessage(MESSAGE_START, url));
                    HttpClient client = new DefaultHttpClient();
                    HttpGet get = new HttpGet(url);
                    InputStream inputStream = null;
                    FileOutputStream outputStream = null;
                    try {
                        HttpResponse response = client.execute(get);
                        HttpEntity entity = response.getEntity();
                        final int size = (int) entity.getContentLength();
                        inputStream = entity.getContent();
                        if (size > 0 && inputStream != null) {
                            outputStream = new FileOutputStream(savePath);
                            int ch = -1;
                            byte[] buf = new byte[1024];
                            //每秒更新一次进度
                            new Timer().schedule(new TimerTask() {

                                @Override
                                public void run() {
                                    try {
                                        FileInputStream fis = new FileInputStream(new File(savePath));
                                        int downloadedSize = fis.available();
                                        if (downloadedSize >= size)
                                            cancel();
                                        mHandler.sendMessage(mHandler.obtainMessage(MESSAGE_PROGRESS, downloadedSize, size, url));
                                    } catch (Exception e) {

                                    }
                                }
                            }, 50, 1000);

                            while ((ch = inputStream.read(buf)) != -1 && !mIsStop) {
                                outputStream.write(buf, 0, ch);
                            }
                            outputStream.flush();
                        }
                    } catch (Exception e) {
                        Log.e(TAG, e.getMessage(), e);
                        mHandler.sendMessage(mHandler.obtainMessage(MESSAGE_ERROR, url + ":" + e.getMessage()));
                    } finally {
                        try {
                            if (outputStream != null)
                                outputStream.close();
                        } catch (IOException ex) {
                        }
                        try {
                            if (inputStream != null)
                                inputStream.close();
                        } catch (IOException ex) {
                        }
                    }
                    mDownloadUrls.remove(url);
                    mHandler.sendMessage(mHandler.obtainMessage(MESSAGE_STOP, url));
                }
            });
        }

        代码说明:
          a. ThreadPool是线程池,请参照项目代码。
          b. 这里使用了Time定时来刷进度,而没有直接在write数据时更新进度,这样的原因时每秒write较高,更新UI过于频繁,可能导致超时等问题。

        Handle

        public Handler mDownloadHandler = new Handler() {
            @Override
            public void handleMessage(Message msg) {
                PFile p;
                String url = msg.obj.toString();
                switch (msg.what) {
                case FileDownloadHelper.MESSAGE_START://开始下载
                    p = new PFile();
                    p.path = mParent.mFileDownload.mDownloadUrls.get(url);
                    p.title = new File(p.path).getName();
                    p.status = 0;
                    p.file_size = 0;
                    if (mDownloadAdapter == null) {
                        mDownloadAdapter = new FileAdapter(getActivity(), new ArrayList<PFile>());
                        mDownloadAdapter.add(p, url);
                        mTempListView.setAdapter(mDownloadAdapter);
                        mTempListView.setVisibility(View.VISIBLE);
                    } else {
                        mDownloadAdapter.add(p, url);
                        mDownloadAdapter.notifyDataSetChanged();
                    }
                    break;
                case FileDownloadHelper.MESSAGE_PROGRESS://正在下载
                    p = mDownloadAdapter.getItem(url);
                    p.temp_file_size = msg.arg1;
                    p.file_size = msg.arg2;
                    int status = (int) ((msg.arg1 * 1.0 / msg.arg2) * 10);
                    if (status > 10)
                        status = 10;
                    p.status = status;
                    mDownloadAdapter.notifyDataSetChanged();
                    break;
                case FileDownloadHelper.MESSAGE_STOP://下载结束
                    p = mDownloadAdapter.getItem(url);
                    FileBusiness.insertFile(getActivity(), p);
                    break;
                case FileDownloadHelper.MESSAGE_ERROR:
                    Toast.makeText(getActivity(), url, Toast.LENGTH_LONG).show();
                    break;
                }
                super.handleMessage(msg);
            }

        }; 

        代码说明:
          a. mTempListView是新增的,默认是隐藏,请参见项目代码layout部分。
          b. 下载流程:开始(显示mTempListView) -> 正在下载(更新进度图片和大小)  -> 完成(入裤)

        Dialog

                    if (FileUtils.isVideoOrAudio(url)) {
                        Dialog dialog = new AlertDialog.Builder(getActivity()).setIcon(android.R.drawable.btn_star).setTitle("播放/下载").setMessage(url).setPositiveButton("播放", new OnClickListener() {
                            @Override
                            public void onClick(DialogInterface dialog, int which) {
                                Intent intent = new Intent(getActivity(), VideoPlayerActivity.class);
                                intent.putExtra("path", url);
                                startActivity(intent);
                            }
                        }).setNeutralButton("下载", new OnClickListener() {
                            @Override
                            public void onClick(DialogInterface dialog, int which) {
                                MainFragmentActivity activity = (MainFragmentActivity) getActivity();
                                activity.mFileDownload.newDownloadFile(url);
                                Toast.makeText(getActivity(), "正在下载 .." + FileUtils.getUrlFileName(url) + " ,可从本地视频查看进度!", Toast.LENGTH_LONG).show();
                            }
                        }).setNegativeButton("取消", null).create();
                        dialog.show();
                        return true;

                    } 

      三、下载
        至本章节往后,代码均不再提供下载,请移步Google Code:
        http://code.google.com/p/android-oplayer

      四、Vitamio公告

          正式建立Vitamio开发者联盟QQ群!群号为:246969281

          注意:目前仅接受已经开发基于Vitamio产品的开发者申请加入,申请理由请填写产品的名词和链接,获取最新进展以及与Vitamio作者直接交流机会!
    结束
      有BUG不可怕,改了就行,大胆设计、放手写代码,谨慎处理已知细节,这样的软件才会越来越好。写了一上午代码,难免有出错的地方,欢迎反馈~


  • 相关阅读:
    Windows脚本转换Liunx识别并执行
    分布式事物常见解决方案
    SIMD加速计算矩阵(组成原理实验5)
    Code-server搭建web IDE
    CentOS 8 修改SSH端口
    Floyd算法的原理和实现代码
    initNativeTransServiceId . ntrans:object componentId :-368613127 微信小程序
    对象搜索算法挑战
    微信小程序小窗无效
    《六层楼》--宋东野
  • 原文地址:https://www.cnblogs.com/over140/p/2561244.html
Copyright © 2020-2023  润新知