手把手教你做视频播放器(四)-刷新与停止刷新列表

第5节 刷新与停止刷新列表

虽然经过我们的假设,忽略了很多不需要关注的视频文件,但设备上依然有可能有很多的满足了我们假设条件的视频存在,这时就需要一个“取消刷新”的功能。

如果视频还没有刷新完,就被取消了,然后又希望继续刷新,那么还需要一个手动开始“刷新”的功能。

因此,准备在ActionBar的右上角,设置一个菜单项,让用户可以“刷新”,也能“停止刷新”。

5.1 添加刷新菜单项

在制作“计算器”的文档里面,我们已经介绍了如何添加ActionBar菜单项,以及如何响应菜单项的点击,

定义菜单项到res\xml\menu.xml文件中,app:showAsAction属性设置成walways

<menu xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">

    <item android:id="@+id/menu_refresh"
        app:showAsAction="always"
        android:title="@string/refresh"/>
</menu>

5.2 实现“刷新”与“停止刷新”的功能

  1. onCreateOptionsMenu()函数中,使用定义的菜单,获取“刷新”功能的菜单项,根据当前VideoUpdateTask的状态,来确定要显示的菜单名字,

    private MenuItem mRefreshMenuItem;
    
    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.menu, menu);
    
        //获取“刷新”菜单项
        mRefreshMenuItem = menu.findItem(R.id.menu_refresh);
    
        //当VideoUpdateTask处于运行的状态时,菜单项的标题显示“停止刷新”,
        if((mVideoUpdateTask != null) && (mVideoUpdateTask.getStatus() == AsyncTask.Status.RUNNING)) {
            mRefreshMenuItem.setTitle(R.string.in_refresh);
        }
        //当VideoUpdateTask没有处于运行的状态时,菜单项的标题显示“刷新”,
        else {
            mRefreshMenuItem.setTitle(R.string.refresh);
        }
    
        return true;
    }
  2. onOptionsItemSelected()中,根据当前VideoUpdateTask的状态,来确定如何响应用户的点击操作,

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
    
        switch(item.getItemId())
        {
            case R.id.menu_refresh:
            {
                if((mVideoUpdateTask != null) && (mVideoUpdateTask.getStatus() == AsyncTask.Status.RUNNING)) {
                    //当VideoUpdateTask处于运行的状态时,取消VideoUpdateTask的工作
                    mVideoUpdateTask.cancel(true);
                    mVideoUpdateTask = null;
                }
                else {
                    //当VideoUpdateTask没有处于运行的状态时,启动VideoUpdateTask的工作
                    mVideoUpdateTask = new VideoUpdateTask();
                    mVideoUpdateTask.execute();
                    //修改菜单项的标题为“停止刷新”
                    if(mRefreshMenuItem != null) {
                        mRefreshMenuItem.setTitle(R.string.in_refresh);
                    }
                }
            }
            break;
    
    
            default:
                return super.onContextItemSelected(item);
    
        }
    
        return true;
    }
  3. VideoUpdateTask被成功取消工作后,它的onCancelled()函数会被调用;在VideoUpdateTask工作顺利完成后,它的onPostExecute()函数会被调用,它们是在主线程中运行的,所以可以在这里修改界面,

    @Override
    protected void onPostExecute(Void result) {
        updateResult()
    }
    
    @Override
    protected void onCancelled() {
        updateResult();
    }
    
    private void updateResult()
    {
        //修改菜单项的标题为“停止刷新”
        if(mRefreshMenuItem != null) {
            mRefreshMenuItem.setTitle(R.string.refresh);
        }
    }

5.3 刷新遗留的问题

5.3.1 问题1

当应用启动后,VideoUpdateTask开始更新视频信息,此时用户点击“暂停刷新”,任务停止了,然后用户又点击“刷新”。我们会发现以前被列出的视频再次被列了出来。

原来,刷新的时候,没有将已经显示的视频与没有显示的视频区分开,已经添加过的又被重新添加了。

解决的办法就是,在添加视频信息到数据列表里面之前,先检查一下这些视频是否已经被添加过了,如果添加过了,那就不用再添加了。

  1. 重写VideoItem的比较方法,让比较两个VideoItem的原则变成:只要文件所在的路径是相同的,就认为这两个比较项指的是同一个,

    @Override
    public boolean equals(Object o) {
        VideoItem another = (VideoItem) o;
    
        return another.path.equals(this.path);
    }
  2. VideoUpdateTaskdoInBackground()函数中,添加视频信息到ListView的数据集-mVideoItemList之前,先判断里面是否已经包含了这个视频,如果没有包含,才发送给主线程更新界面;比较视频是否相同的依据,就是前面重写的equals()函数,

    @Override
    protected Void doInBackground(Object... params) {
    
        ......
        if(cursor != null)
        {
            while(cursor.moveToNext())
            {
                ......
                VideoItem item = new VideoItem(path, name, createdTime);
    
                //判断出之前没有这个视频,才发送给主线程更新界面
                if(mVideoList.contains(data) == false) {
    
                    publishProgress(item);  
    
                }
            }
    
            cursor.close();
        }
    
        return null;
    }

5.3.2 问题2

问题1的解法又引入了另一个问题:如果有的视频是重复的,那么能不能在给它创建视频缩略图的时候,先忽略掉它,因为创建视频缩略图是个非常消耗内存和时间的事情。

所以我们要修改一下创建缩略图的策略,不要让它已开始就创建,而是让我们根据条件来决定是否要创建缩略图。

  1. 修改VideoItem的设计成,

    VideoItem(String strPath, String strName, String createdTime) {
    
        this.path = strPath;
        this.name = strName;
    
        SimpleDateFormat sf = new SimpleDateFormat("yy年MM月dd日HH时mm分");
        Date d = new Date(Long.valueOf(createdTime)*1000);
        this.createdTime = sf.format(d);;
    }
    
    //将创建缩略图的功能独立出来
    void createThumb()
    {
        if(this.thumb == null)
        {
            this.thumb = ThumbnailUtils.createVideoThumbnail(this.path, MediaStore.Images.Thumbnails.MINI_KIND);
        }
    }
    
    //与createThumb()对应,需要一个释放bitmap资源的方法
    void releaseThumb()
    {
        if(this.thumb != null){
            this.thumb.recycle();
            this.thumb = null;
        }
    }
  2. VideoUpdateTaskdoInBackground()函数中,

    @Override
    protected Void doInBackground(Object... params) {
    
        ......
        if(cursor != null)
        {
            while(cursor.moveToNext())
            {
                ......
                VideoItem item = new VideoItem(path, name, createdTime);
    
                if(mVideoList.contains(data) == false) {
                    //判断需要添加,才创建缩略图
                    item.createThumb();
                    publishProgress(item);  
    
                }
            }
    
            cursor.close();
        }
    
        return null;
    }

5.3.3 问题3

如果用户暂停刷新后,设备中的视频因为别的原因被删除了一个,即使采用问题1的解决办法也不会有效果,因为ListView中的保存的视频信息个数比真实刷新到的要多,没有把ListView中多余的数据给清除掉。

所以,要把ListView中所有多余的视频清除,只能在视频查询完成后才能进行,而且这些真正存在的视频信息还得保存下来,在最后的比较中会使用到。

  1. 将真正存在的视频信息,再保存一份,

    List<VideoItem> mDataList = new ArrayList<VideoItem>();
    
    @Override
    protected Void doInBackground(Object... params) {
    
        ......
        if(cursor != null)
        {
            while(cursor.moveToNext())
            {
                ......
                VideoItem item = new VideoItem(path, name, createdTime);
    
                if(mVideoList.contains(data) == false) {
                    data.createThumb();
                    publishProgress(item);  
    
                }
    
                //保存起来
                mDataList.add(data);
    
            }
    
            cursor.close();
        }
    
        return null;
    }
  2. VideoUpdateTask结束工作以后(无论是取消还是顺利完成),会调用到onCancelled() onPostExecute(),所以可以在它们共同调用的updateResult()中清除ListView中多余的视频信息,

    private void updateResult() {
    
        ......
        for(int i = 0; i < mVideoList.size(); i++)
        {
            if(!mDataList.contains(mVideoList.get(i)))
            {
                //释放缩略图占用的内存资源
                mVideoList.get(i).releaseThumb();
                //从ListView的数据集中移除多余的视频信息
                mVideoList.remove(i);
                //因为移除了一个视频项,下一个视频项的序号就被减小了一个1
                i--;
            }
        }
        mDataList.clear();
    
        //通知`ListView`数据有改变,需要刷新
        VideoItemAdapter adapter = (VideoItemAdapter) mVideoListView.getAdapter();
        adapter.notifyDataSetChanged();
    }

至此,视频刷新的功能就完成了。


/*******************************************************************/
* 版权声明
* 本教程只在CSDN安豆网发布,其他网站出现本教程均属侵权。

*另外,我们还推出了Arduino智能硬件相关的教程,您可以在我们的网店跟我学Arduino编程中购买相关硬件。同时也感谢大家对我们这些码农的支持。

*最后再次感谢各位读者对安豆的支持,谢谢:)
/*******************************************************************/

  • 0
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值