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

前言

本章将实现非常实用的功能——下载在线视频。涉及到多线程、线程更新UI等技术,还需思考产品的设计,如何将新加的功能更好的融入到现有的产品中,并不是简单的加一个界面就行了,欢迎大家交流产品设计和技术细节实现!
声明
此文转载自:
博客园:http://www.cnblogs.com
农民伯伯: http://over140.cnblogs.com 
系列
1、使用Vitamio打造自己的Android万能播放器(1)——准备
2、使用Vitamio打造自己的Android万能播放器(2)—— 手势控制亮度、音量、缩放
3、使用Vitamio打造自己的Android万能播放器(3)——本地播放(主界面、视频列表)

  4、使用Vitamio打造自己的Android万能播放器(4)——本地播放(快捷搜索、数据存储)
  5、使用Vitamio打造自己的Android万能播放器(5)——在线播放(播放优酷视频)

6、使用Vitamio打造自己的Android万能播放器(6)——在线播放(播放列表)

 

正文
一、目标

    本章实现视频下载的功能

      

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

 

二、实现(部分主要实现代码)
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));
    }

    /**
     * 下载一个新的文件
     * 
     * @paramurl
     * @paramsavePath
     */
    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

转载于:https://www.cnblogs.com/kingtao/archive/2012/07/19/2599390.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/461859.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Hibernate上路_16-继承关系映射

2019独角兽企业重金招聘Python工程师标准>>> 例&#xff1a;员工Employee分为正式工SalaryEmployee和临时工HourEmployee。子类表的字段都不能使用非空约束。 1.三种继承关系的建表方式&#xff1a; 1&#xff09;父类、子类在同一张表&#xff0c;表中有“辨别者…

C++起航篇——bool类型,输入输出,命名空间

以下内容源于慕课网http://www.imooc.com/course/list?ccplusplus的学习整理&#xff0c;如有侵权&#xff0c;请告知删除。 慕课网学习内容 一、起航 二、离航 三、远征 封装继承多态模板 1、c的新特征 &#xff08;1&#xff09;新数据类型 bool &#xff08;true和fals…

C++离航篇——引用,const

以下内容源于http://www.imooc.com/learn/381的学习整理&#xff0c;如有侵权&#xff0c;请告知删除。 一、引用 &#xff08;1&#xff09;引用即定义别名 对引用进行操作即对本身操作&#xff1b;int a10; int &ba; //定义了a的别名b&#xff1b;注意别名是不包括&…

【广搜】棋盘游戏

题目描述 在一个4*4的棋盘上有8个黑棋和8个白棋&#xff0c;当且仅当两个格子有公共边&#xff0c;这两个格子上的棋是相邻的。移动棋子的规则是交换相邻两个棋子。现在给出一个初始棋盘和一个最终棋盘&#xff0c;要求你找出一个最短的移动序列使初始棋盘变为最终棋盘。Klux说…

C++离航篇——函数默认参数、函数重载、内敛函数

1、函数的默认参数 2、函数的重载 &#xff08;1&#xff09;在相同的作用域内&#xff0c;用同一个函数名定义的多个函数&#xff0c;其中每个函数的参数个数、参数类型不同。 3、内联函数 &#xff08;1&#xff09;编译的时候&#xff0c;将函数体代码和相应的实参直接在函…

C++离航篇——内存的申请释放

1、内存的申请和释放 使用关键字new&#xff0c;紧接申请的类型&#xff0c;以及用中括号标明申请多大的内存空间。 2、内存的初始化 注意和块内存申请不同&#xff0c;初始化是&#xff08;&#xff09;&#xff0c;块内存是[ ]。

C++远征之封装篇——类和封装、实例化和对象成员访问

一、封装篇的学习内容数据成员 成员函数构造函数 析构函数对象复制 对象赋值对象数组 对象指针this指针二、类与封装三、实例化和对象成员访问&#xff08;1&#xff09;从栈中实例化对象&#xff08;2&#xff09;从堆中实例化对象 &#xff08;3&#xff09;对象成员的访…

C++远征之封装篇——字符串类型

一、c中的字符串操作函数 二、字符串类型string 1、c中没有字符串类型&#xff0c;只有字符类型 因此对于字符串的操作&#xff0c;一般是用上面的函数来操作。 2、字符串的初始化 3、字符串相关的操作

C++远航之封装篇——数据的封装

以对象为中心&#xff0c;具体来说&#xff0c;以谁做什么来代表程序的逻辑。所有操作都通过调用自己的函数来完成。 数据成员暴露了&#xff0c;不好的设计&#xff1a; 数据的封装&#xff1a;

游戏大厅 从基础开始(7)--绕回来细说聊天室(中间偏下)之女仆编年史2

老少爷们儿反击战 上一篇中 我们的女仆终于可以做一些像阳光下其他人一样的事情了&#xff0c;少爷们可以和女仆酱一起参加下午茶~ 难得的上流社会啊 这是永远1v1被人私有的女奴 和 喝茶时被人共有的女仆酱最明显的差异~ 明媚的午后阳光下&#xff0c;庭院里白色长餐桌两旁&am…

【转载】App.config/Web.config 中特殊字符的处理

写一个网站&#xff0c;遇到一个问题&#xff0c;发布以后&#xff0c;提示错误&#xff0c;但是即使打开错误提示&#xff08;在web.config中打开&#xff09;&#xff0c;还是只提示错误&#xff0c;没提示什么地方错误&#xff0c;这让我知道了&#xff1a;是webconfig本身的…

C++远航之封装篇——类外定义和::

1、类内定义是把函数的具体实现写在类内部&#xff0c;默认是inline函数。 2、类外定义包含两种情况&#xff1a; &#xff08;1&#xff09;同文件类外定义 &#xff08;2&#xff09;不同文件类外定义

pipeline代码自动生成

如图所示&#xff0c;安装完插件后&#xff0c;Sample Step里就有相应的选项&#xff0c;选择某个选项后&#xff0c;点击Generate Pipeline Script按钮&#xff0c;就可以自动生成代码片段&#xff0c;然后放入pipeline流水线里就可以了 pipeline使用的是groovy脚本&#xff0…

一个简单的基于socket的通讯处理程序

2019独角兽企业重金招聘Python工程师标准>>> 这几天看书看得java网络编程&#xff0c;看到一个不错的&#xff0c;适合新手的&#xff0c;部分代码借鉴书上的&#xff0c;可能有地方还不是很成熟&#xff0c;不过可以借鉴一下&#xff0c;分为客户端和服务端&#x…

C++远航之封装篇——构造函数

1、为什么需要构造函数&#xff1f; 见博客http://blog.csdn.net/zhhymh/article/details/6236317 2、c中的内存分区 &#xff08;1&#xff09;栈区 int x0&#xff1b;int *pNULL&#xff1b; &#xff08;2&#xff09;堆区 int *p new int[20]; &#xff08;3&#xff0…

安装win_server_2012的方法

1、从微软官网下载评估版。 2、查看你的当前版本。以管理员身份运行cmd&#xff0c;然后输入“DISM /online /Get-CurrentEdition”。如果是评估版&#xff0c;例如Standard&#xff0c;把“ServerStandardEval”中的Eval这四个字母去掉&#xff0c;就是你的当前版本。下图表明…

DHCP中继处理办法

这两天一直在客户这边测试DHCP&#xff0c;由于客户的网络是现成的server 2008 是后来加上去的&#xff0c;所以没有多的IP地址用于测试&#xff0c;只好拿客户的楼层网段来测试&#xff0c;由于需要跨VLAN实行DHCP地址分配&#xff0c;所有需要做DHCP中继。废话不多说&#xf…

C++远航之封装篇——默认构造函数、初始化列表、拷贝构造函数

1、默认构造函数 没有参数&#xff1b;若有参数&#xff0c;则一定全部都有默认的参数值。 2、初始化列表 &#xff08;1&#xff09;概念 &#xff08;2&#xff09;特性 建议用初始化列表来初始化数据成员。初始化列表先于构造函数执行&#xff1b;初始化列表只能用于构造函…

C++远航之封装篇——析构函数

一、为什么需要析构函数&#xff1f; 见博客&#xff1a;http://blog.csdn.net/zhhymh/article/details/6239832 二、析构函数的理解 1、格式 2、必要性 释放资源。 3、什么时候调用&#xff1f; delet p时会调用析构函数&#xff1b;程序返回时&#xff0c;也会调用析构函数…

生成的数据库脚本没有注释?

1,选择Database->Generate Database 选中Generate name in empty comment就可以了转载于:https://www.cnblogs.com/hongjiumu/archive/2012/08/02/2620379.html