利用videoView创建播放器,实现展示视频列表和搜索sd卡功能 以及android6.0的动态授权等功能

  最近无聊写了个播放器除了没实现解码功能大多的功能都实现了,主要是回顾一些android的知识点和andorid6.0的动态授权的学习。

1、android 6.0的动态授权问题。

  android 6.0后需要开发人员实现动态授权,不再像以前一样在mainfet的清单文件中加入权限就可以了(清单文件还是要申明下,不过无效),需要在代码中动态分配权限。如微信发送图片时候就需要访问图库,用户可以在setting里设置不能访问也可以设置为可以访问图库,以前的android系统在安装时候同意了后就一直可以访问图库否则就不能安装微信,现在的用户可以安装微信,只有在发送或者保存图片的时候才申请访问sd卡读写的权限,这样更灵活方便,不过这给我们开发人员就带了一点小小的麻烦了。

下面为就简单的介绍一下如何实现动态授权:

  (1)一些应用只是某些activitiy需要权限,因此我们首先就是构建一个需要检测权限的父类PermissionActivity实现ActivityCompat.OnRequestPermissionsResultCallback 接口。,在该类oncreate()启动的时候里我们进行权限的检测,当含有权限时才可以启动,否则就弹出对话框让用户授权。当授权成功后就可以启动activity,若授权失败则提示启动setting设置权限;当用户拒绝授权时候就直接退出finish()该activity。

  这里面主要的申请权限的方法:

    ActivityCompat.requestPermissions(this,permissions,PERMISSION_REQUEST_CODE);

this则是ActivityCompat.OnRequestPermissionsResultCallback 接口,因此这个类实现这个接口,即回调函数:

    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults)

在这个函数中我们可以判断授权是否成功。

PS:当应用中多种应用都需要动态授权时,可以将这个PermissionActivity定义为抽象类,然后添加个抽象方法abstract String[] getNeedPermission(),然后继承它的activity必须实现这个方法,返回当前需要的权限即可,当然也可以用接口的方法来实现这里就不讲了。下面的代码就是抽象类实现的。

  (2)当然是构建检测是否拥有权限的工具类,当然这些方法也可以集成当上面的activity中。

  这个类主要就是检测是否含有activity所需的权限,比如判断是否有所以权限,查找缺少的的权限等操作,其中都要用到的方法就是:

  ContextCompat.checkSelfPermission(context,permission)== PackageManager.PERMISSION_DENIED

前面的方法是检测permission权限,若没有就会返回 PackageManager.PERMISSION_DENIED,利用这个来进行一系列的权限判断。

  (3) 当我们某个activity运行时候需要检测权限时候就继承PermissionActivity即可。

<----------------2017 5 . 9 日跟新,主要是考虑2个类太麻烦将这2个类合并为一个类,并且想用的话继承该类,然后初始化权限数组即可---------- >

package com.example.user.myapplevideoplayer;

import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.provider.Settings;
import android.support.annotation.NonNull;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AlertDialog;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;

import java.util.ArrayList;

public abstract class PermissionCheckerActivity extends AppCompatActivity {
    private static final int PERMISSION_REQUEST_CODE = 0;
    private String[] needPermissions;
    private ArrayList<String> lackPermissions = new ArrayList<>();
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        needPermissions = initNeedPermission();
        if(!isHasAllPermissions(needPermissions)) {//判断是否有所有权限,并初始化所差的权限
            requestLackPermissions(lackPermissions);
        }
    }

    @Override
    protected void onResume() {
        super.onResume();
    }

    private boolean isHasAllPermissions(String[] permissions)
    {
        boolean result = true;
        for(String permission:permissions)
        {
            if( ContextCompat.checkSelfPermission(this,permission)== PackageManager.PERMISSION_DENIED)
            {
                lackPermissions.add(permission);
                result = false;
            }
        }
        return result;
    }

    private void requestLackPermissions( ArrayList<String> lackPermissions )
    {
        int size = lackPermissions.size();
        //将链表转化数组
        String[] lackPermissionsArray = new String[size];
        for(int i = 0 ; i < size ; i ++)
        {
            lackPermissionsArray[i] = lackPermissions.get(i);
        }
        
        ActivityCompat.requestPermissions(this, lackPermissionsArray , PERMISSION_REQUEST_CODE);//申请所需的权限
    }

    //申请的回调函数
    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        if(requestCode==PERMISSION_REQUEST_CODE)
        {

            for(int result:grantResults){
                //如果有一个权限没通过都不能继续
                if(result== PackageManager.PERMISSION_DENIED)
                {
                    //申请权限不成功,弹出对话框设置
                    showMissingPermissionDialog();
                    System.out.println("申请权限不成功");
                    return;
                }
            }
//            System.out.println("申请权限成功");

        }

    }

    private void showMissingPermissionDialog() {
        AlertDialog.Builder builder = new AlertDialog.Builder(this);
        builder.setTitle("提示");
        builder.setMessage("当前应用缺少必要权限。请点击"设置"-"权限"-打开所需权限。");

        // 拒绝, 退出应用
        builder.setNegativeButton("取消",
                new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        finish();
                    }
                });

        builder.setPositiveButton("设置",
                new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        startAppSettings();
                    }
                });

        builder.setCancelable(false);

        builder.show();
    }

    /**
     *  启动应用的设置
     *
     * @since 2.5.0
     *
     */
    private void startAppSettings() {
        Intent intent = new Intent(
                Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
        intent.setData(Uri.parse("package:" + getPackageName()));
        startActivity(intent);
    }


    //继承该类的话必须初始化所需要的权限
    public abstract String[] initNeedPermission() ;

}
View Code

  注意:若在使用的activity中继承 这个activity 时候若在oncreate中直接跳转其他activity时就会导致忽略权限检查直接进入其他应用,从而应用报错,因此在回调函数中跳转应用。

 

  1、一般在方法中申请权限,在 onRequestPermissionsResult 回调函数中若申请成功启动需要权限的activity。

    2、若在主activity需要权限,则在resume 或者onCreate中申请权限,在回调函数onRequestPermissionsResult  中做一些需要权限才能做的事情

<--------------2017 5 . 9 日跟新,主要是考虑2个类太麻烦将这2个类合并为一个类,并且想用的话继承该类,然后初始化权限数组即可---------- >

下面给出这两个类:

package com.example.zp.my;

import android.Manifest;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Bundle;
import android.provider.Settings;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.app.ActivityCompat;
import android.support.v7.app.AlertDialog;
import android.support.v7.app.AppCompatActivity;
import android.view.KeyEvent;

import java.util.ArrayList;


public abstract  class PermissionActivity extends AppCompatActivity implements
        ActivityCompat.OnRequestPermissionsResultCallback {

    private static final int PERMISSION_REQUEST_CODE = 0;

    private String[] needPermissions;

    private PermissionChecker permissionChecker;

    abstract   String []  getNeedPermission();


    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        needPermissions = getNeedPermission();
        permissionChecker=new PermissionChecker(this,needPermissions);
        if (!permissionChecker.IsHasAllPermissions()) {
            /*申请权限,会弹出一个窗口,问是否授权,即此类实现的.OnRequestPermissionsResultCallback 的方法onRequestPermissionsResult
            */
            //申请缺少的权限
            requestPermissions(permissionChecker.getLacksPermissions(needPermissions));
        }
    }


    @Override
    protected void onResume() {
        super.onResume();
//            if (!permissionChecker.IsHasAllPermissions()) {
//            /*申请权限,会弹出一个窗口,问是否授权,即此类实现的.OnRequestPermissionsResultCallback 的方法onRequestPermissionsResult
//            */
//                //申请缺少的权限
//                requestPermissions(permissionChecker.getLacksPermissions(needPermissions));
//            }

    }

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults){
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        if(requestCode==PERMISSION_REQUEST_CODE)
        {

            for(int result:grantResults){
                //如果有一个权限没通过都不能继续
                if(result== PackageManager.PERMISSION_DENIED)
                {

                    //申请权限不成功,弹出对话框设置
                    showMissingPermissionDialog();
                    System.out.println("申请权限不成功");
                    System.out.println(result);
                    return;
                }
            }
//            System.out.println("申请权限成功");

        }


    }
    /**
     * 显示提示信息
     *
     * @since 2.5.0
     *
     */
    private void showMissingPermissionDialog() {
        AlertDialog.Builder builder = new AlertDialog.Builder(this);
        builder.setTitle("提示");
        builder.setMessage("当前应用缺少必要权限。请点击"设置"-"权限"-打开所需权限。");

        // 拒绝, 退出应用
        builder.setNegativeButton("取消",
                new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        finish();
                    }
                });

        builder.setPositiveButton("设置",
                new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        startAppSettings();
                    }
                });

        builder.setCancelable(false);

        builder.show();
    }

    /**
     *  启动应用的设置
     *
     * @since 2.5.0
     *
     */
    private void startAppSettings() {
        Intent intent = new Intent(
                Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
        intent.setData(Uri.parse("package:" + getPackageName()));
        startActivity(intent);
    }



    public void requestPermissions(String[] permissions)
    {
        ActivityCompat.requestPermissions(this,permissions,PERMISSION_REQUEST_CODE);
    }

}

  

  

package com.example.zp.my;

import android.Manifest;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AppCompatActivity;

import java.util.ArrayList;

/**
 * Created by lenovo on 2016/8/9.
 */
public class PermissionChecker  {

    private final  Context context;
    //应用需要的所有权限

    private String[] needPermissions;

    public  PermissionChecker(Context context, String[] needPermissions)
    {
        this.context=context.getApplicationContext();
        this.needPermissions=needPermissions;
    }

    //获得权限数组中缺少的权限
    public  ArrayList<String> getLacksPermissionList (String[] permissions)
    {
        ArrayList<String> lacksPermissions=new ArrayList<String>();
        for(String permission:permissions )
        {
        if(lacksPermission(permission))
            lacksPermissions.add(permission);

        }
        return lacksPermissions;
    }

    public  String[] getLacksPermissions (String[] permissions)
    {
        ArrayList <String> lacksPermissions=getLacksPermissionList(permissions);
        String[] lacksPermissions2 = new String[lacksPermissions.size()];
        for(int i = 0 ; i < lacksPermissions.size() ; i ++ )
        {
            lacksPermissions2[i] = lacksPermissions.get(i);
        }
        return  lacksPermissions2;
    }

    //是否已有所有的权限
    public boolean IsHasAllPermissions()
    {
        for(String permission:needPermissions ) {
            if (lacksPermission(permission))
                return false;
        }
        return true;
    }

    //是否已有所有的权限
    public boolean IsHasPermissions(String...permissions)
    {
        for(String permission:permissions ) {
            if (lacksPermission(permission))
                return false;
        }
        return true;
    }

    //判断是否有某个权限
    public boolean lacksPermission(String permission)
    {
       return  ContextCompat.checkSelfPermission(context,permission)== PackageManager.PERMISSION_DENIED;
    }


}

  

2、下面就是给出播放器的实现代码(也用到了前面2个类的授权),主要是回顾以前的知识和新的android 授权问题的学习:以前主要是自己写的算法来搜索内存卡里的所有文件来获取文件路径和存储下来的加载的,现在一般用的是contentprovider查询图库的数据然后加载视频的,这样更简单方便,在后面的博客中会讲到:

package com.example.zp.my;

import android.Manifest;
import android.content.DialogInterface;
import android.content.Intent;
import android.media.MediaPlayer;
import android.os.Handler;
import android.os.Message;
import android.os.Bundle;
import android.support.v7.app.AlertDialog;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.MediaController;
import android.widget.SeekBar;
import android.widget.TextView;
import android.widget.Toast;
import android.widget.VideoView;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.util.ArrayList;

import static android.media.MediaPlayer.*;

public class MainActivity extends  PermissionActivity{// AppCompatActivity

    //button
    private VideoView vView;
    private Button bt_play,bt_previous,bt_next;
    private SeekBar seekbar;

    // videos信息
    private int currentVideoNumber=0;
    public ArrayList<Video> videos = new ArrayList<Video>();
    public ArrayList<String> videosItem = new ArrayList<String>();

    //播放信息
    private  int INVISIBLE_TIME=5000;
    private int ClickNumber=0;
    private static final int CHOOSEVIDEO          = 0;
    private int position=0;
    private  boolean IsFirstInstall=true;
    File vide0sInformationFile;
//    private Thread updateProgress;
    private boolean videoPlayerOnScree = false;



    //  为了防止手不停点击时候控件消失,利用点击次数与睡眠前msg赋值,等睡3秒后发送消息与此时按键的次数是
// 否相同,如果相同则证明3秒内没点击按键,否则证明按了后三秒又对按键操作过
    public Handler handler=new Handler(){
        @Override
        public void handleMessage(Message msg) {
            if(msg.arg1==ClickNumber&&vView.isPlaying())
            {
                bt_play.setVisibility(View.INVISIBLE);
                bt_previous.setVisibility(View.INVISIBLE);
                bt_next.setVisibility(View.INVISIBLE);
                seekbar.setVisibility(View.INVISIBLE);
                ClickNumber=0;
            }
            super.handleMessage(msg);
        }
    };


    @Override
    String[] getNeedPermission() {
       String[] needPermissions
        ={
            Manifest.permission.WRITE_EXTERNAL_STORAGE,
            Manifest.permission.READ_EXTERNAL_STORAGE,
         };
        return  needPermissions;
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        init();

        Intent intent = getIntent();

            currentVideoNumber = intent.getIntExtra("chooseVideoNumber", -1);

          if(currentVideoNumber!=-1)
          {
              play(videos.get(currentVideoNumber));
          }
        else
              currentVideoNumber=0;


        /**
         * VideoView控制视频播放的功能相对较少,具体而言,它只有start和pause方法。为了提供更多的控制,
         * 可以实例化一个MediaController,并通过setMediaController方法把它设置为VideoView的控制器。
         */
        // 使用这种方式创建MediaController将不会显示“快进”和“快退”两个按钮
//        MediaController mediaController = new MediaController(this,false);
//        vView.setMediaController(mediaController);
        MediaController mediaController=new MediaController(this);
        mediaController.setVisibility(View.INVISIBLE);//以藏mediaplayer带的进度条和播放按钮
        vView.setMediaController(mediaController);
        //设置播放完后事件监听器
        vView.setOnCompletionListener(new OnCompletionListener(){
            @Override
            public void onCompletion(MediaPlayer mp) {
                // TODO Auto-generated method stub
                if(currentVideoNumber<videos.size()-1)
                    currentVideoNumber=currentVideoNumber+1;
                else
                    currentVideoNumber=0;

                bt_play.setText(R.string.pause);
                play(videos.get(currentVideoNumber));
            }
        });

        seekbar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener(){
            @Override
            public void onProgressChanged(SeekBar seekBar, int progress,
                                          boolean fromUser) {
                // TODO Auto-generated method stub
                int currentPosition = vView.getCurrentPosition();
                //第二个条件是以进度条的变化值来判断用户拖动还是进度条自动更新的,更新进度条的线程也会使得该监听器执行该方法
                if(vView.isPlaying()&&Math.abs(currentPosition-progress)>1000)
                {
                    position=progress;
                    vView.seekTo(progress);
                    vView.start();
//                    sendInvisibleMessage();
                }
                else if(!vView.isPlaying()&&Math.abs(currentPosition-progress)>1000)
                {
                    position=progress;
                    vView.seekTo(progress);
//                    sendInvisibleMessage();
                }


            }
            @Override
            public void onStartTrackingTouch(SeekBar seekBar) {
                // TODO Auto-generated method stub

            }
            @Override
            public void onStopTrackingTouch(SeekBar seekBar) {
                // TODO Auto-generated method stub

            }

        });


//        vView.setVideoURI();


    }

    @Override
    protected void onPause() {
        super.onPause();
        //在按home键时候记录下position,回来时候继续播放
        position=vView.getCurrentPosition();
        bt_play.setText("播放");
        videoPlayerOnScree=false;


    }
    @Override
    protected void onResume() {
        super.onResume();
        //当播放器在界面时候开启更新进度条线程,不在屏幕显示时候停止。
        videoPlayerOnScree=true;
        new UpdateSeekbarProgress().start();

//        if(vide0sInformationFile.exists())
//            getVideos();//因为是在resume里申请的权限,因此不能在oncreate()里读取视频信息文件
    }


    @Override
    protected void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        outState.putInt("position",vView.getCurrentPosition());
        outState.putInt("currentVideoNumber" ,currentVideoNumber);

    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        System.out.println("onDestroy");
    }


    @Override
    public boolean onTouchEvent(MotionEvent event) {
            // TODO Auto-generated method stub
            switch (event.getAction()) {
                case MotionEvent.ACTION_MOVE:
                    bt_next.setVisibility(View.VISIBLE);
                    bt_previous.setVisibility(View.VISIBLE);
                    bt_play.setVisibility(View.VISIBLE);
                    seekbar.setVisibility(View.VISIBLE);
                    sendInvisibleMessage();
                    break;
                case MotionEvent.ACTION_DOWN:
                    bt_next.setVisibility(View.VISIBLE);
                    bt_previous.setVisibility(View.VISIBLE);
                    bt_play.setVisibility(View.VISIBLE);
                    seekbar.setVisibility(View.VISIBLE);
                    sendInvisibleMessage();
                    break;

                default:
                    break;
            }
            return super.onTouchEvent(event);
        }


    //控件的初始化,以及视频文件的选择
    private void init()
    {
        vView=(VideoView) this.findViewById(R.id.VView);
        bt_play=(Button) findViewById(R.id.playButton);
        bt_play.setText(R.string.start);
        bt_previous=(Button) findViewById(R.id.previousButton);
        bt_next=(Button) findViewById(R.id.nextButton);
        seekbar=(SeekBar) findViewById(R.id.seekBar);
        seekbar.setEnabled(true);


        String cashFilePath=getExternalCacheDir().toString();
        vide0sInformationFile = new File(cashFilePath+"/videos.txt");


        if(vide0sInformationFile.exists())
        {
            IsFirstInstall=false;
            getVideos();
        }
    }

    class UpdateSeekbarProgress extends  Thread
    {
        @Override
        public void run() {
            try {
                while (videoPlayerOnScree) {
                    // 如果正在播放,每1毫秒更新一次进度条,若不sleep则会不停的申请占用cpu,导致视频播放卡顿
                    if(vView.isPlaying())
                    {
                        //vView.getDuration()得到视频的长度,以毫秒为单位
                        seekbar.setMax(vView.getDuration());
                        position=vView.getCurrentPosition();
                        seekbar.setProgress(position);
                    }
                    sleep(500);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }


    //播放暂停按钮
    public void playVideoButton(View v) {

        if (IsFirstInstall) {
            Toast.makeText(MainActivity.this, "第一次使用,正在为您扫描播放的文件,请稍候...", Toast.LENGTH_SHORT).show();
            Intent intent = new Intent();
            intent.setAction("android.intent.reSearchVideo");
            intent.addCategory("android.intent.category.DEFAULT");
            startActivity(intent);
        } else {
            if (!vView.isPlaying()) {
                if (vView.getDuration() <= 0)//判断是暂停了,还是没有开始播放过
                {
                    bt_play.setText(R.string.pause);
                    play(videos.get(currentVideoNumber));

                } else {
                    bt_play.setText(R.string.pause);
                    vView.seekTo(position);
                    vView.start();
                }
//                sendInvisibleMessage();

//    	//下面的输出的是未播放时 -1,该输出语句证明了播放器的视频还没准备好就执行了vView.getDuration()得到的值为-1,
//    	//因此这里设置seekbar.max()将导致设置的值为-1,进度条无法拖动,因此在更新进度条的线程中去设置了seekbar的最大值
//    	if(vView.isPlaying())
//    	System.out.println("播放时:"+vView.getDuration());
//    	else
//    		System.out.println("未播放时:"+vView.getDuration());
            } else {
                bt_play.setText("播放");
                vView.pause();
//                sendInvisibleMessage();
            }
        }
    }

    //播放一个视频
    public void play(Video video) {
            vView.setVideoPath(video.path);
            vView.requestFocus();
            vView.start();
            bt_play.setText(R.string.pause);
            sendInvisibleMessage();
           if(video.getTime()==0)
               video.setTime(vView.getDuration());

    }
    //下一集
    public void nextVideoButton(View v)
    {
        if(currentVideoNumber<videos.size()-1)
            currentVideoNumber=currentVideoNumber+1;
        else
            currentVideoNumber=0;

        bt_play.setText(R.string.pause);
        play(videos.get(currentVideoNumber));
    }
    //上一集
    public void previousVideoButton(View v)
    {
        bt_play.setText(R.string.pause);
        if(currentVideoNumber>0)
            currentVideoNumber-=1;
        else
            currentVideoNumber=videos.size()-1;
            play(videos.get(currentVideoNumber));
    }

    //发送按键隐藏消息
    public void sendInvisibleMessage()
    {
        ClickNumber++;
        new SendInvisibleMsg().start();
    }

    //选择播放文件夹
    public void chooseVideo(View v)//chooseVideo
    {
        if(!IsFirstInstall) {
            bt_play.setText(R.string.pause);
            vView.pause();
            Intent intent = new Intent();
            intent.setAction("android.intent.chooseVideo");
            intent.putStringArrayListExtra("videosItem", videosItem);
            intent.addCategory("android.intent.category.DEFAULT");
            startActivity(intent);
            finish();
        }
        else
        {
            Toast.makeText(MainActivity.this, "第一次使用,正在为您扫描播放的文件,请稍候...", Toast.LENGTH_SHORT).show();
            Intent intent=new Intent();
            intent.setAction("android.intent.reSearchVideo");
            intent.addCategory("android.intent.category.DEFAULT");
            startActivity(intent);
            finish();
        }

    }

    //从缓存文件中获取视频信息
    private void getVideos()
    {

        if(vide0sInformationFile.exists())
        {
            try {
                BufferedReader reader2=new BufferedReader(new FileReader(vide0sInformationFile));
                String value ;
                while ( (value = reader2.readLine())!= null)
                {
                   int pointer = value.lastIndexOf(":");
                    String name = value.substring(0,pointer);
                    String path = value.substring(pointer+1,value.length());
                    videosItem.add(value);
                    videos.add(new Video(name,path));
                }
                reader2.close();

            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    class SendInvisibleMsg extends Thread
    {
        @Override
        public void run() {
            try {
                //注意顺序,必须在睡前对msg赋值
                    Message msg = new Message();
                    msg.arg1 = ClickNumber;
                    sleep(INVISIBLE_TIME);
                    handler.sendMessage(msg);


            } catch (InterruptedException e) {
                e.printStackTrace();
            }

        }
    }

    @Override
    public void onBackPressed() {


        AlertDialog.Builder builder = new AlertDialog.Builder(this);
        builder.setTitle("提示");
        builder.setMessage("确定推出吗?");

        // 拒绝, 退出应用
        builder.setNegativeButton("确定",
                new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        finish();
                    }
                });

        builder.setPositiveButton("取消",
                new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {

                    }
                });

        builder.setCancelable(false);

        builder.show();


    }


}

  

  

package com.example.zp.my;


import android.content.Intent;
import android.os.Environment;
import android.os.Handler;
import android.os.Message;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.LinearLayout;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;

public class searchVideoActivity extends AppCompatActivity {

    private ArrayList<Video> videos = new ArrayList<Video>();
    private LinearLayout dians;
    private boolean isShow=true;
    private  File rootFile;
    private  int pointsNumber = 5;
    private View [] points = new View[pointsNumber];
    public Handler handler=new Handler(){
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);

            if(msg.arg1!=0)
            {
                for(int i = 0 ; i < pointsNumber ; i ++)
                {
                    if(i<msg.arg1-1)
                        points[i].setVisibility(View.VISIBLE);
                    else
                        points[i].setVisibility(View.INVISIBLE);
                }
            }

        }
    };


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_search_video);
        init();
        DiansShow dianshow=new DiansShow();
        dianshow.start();

        SerchVideo serchVideo = new SerchVideo();
        serchVideo.start();


    }

    private void init()
    {
        //初始化显示加载的点
        dians= (LinearLayout) findViewById(R.id.dians);
        for(int i=0;i<pointsNumber;i++) {
            View v = new View(this);
            //注意这里先引进了ActionBar.LayoutParams导致设置的leftMargin失效
            LinearLayout.LayoutParams la = new  LinearLayout.LayoutParams(8, 8);
            la.leftMargin = 10;
            v.setLayoutParams(la);
            v.setBackgroundResource(R.drawable.dian_normal);
            points[i] = v;
            dians.addView(v);
        }

        //初始化,搜索的根目录
//        rootFile=new File("data/zp2");
        rootFile = Environment.getExternalStorageDirectory();

    }



    class SerchVideo extends Thread
    {
        @Override
        public void run() {

            findVideos(rootFile);
            new WriteVideo().start();

            try {
                sleep(2000);
                Intent intent = new Intent();
                intent.setAction("android.intent.chooseVideo");
                intent.addCategory("android.intent.category.DEFAULT");
                startActivity(intent);
                isShow=false;
                finish();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    class DiansShow extends Thread
    {
        int showingPointsNumber=0;
        @Override
        public void run() {
            while (isShow) {
                try {

                    sleep(500);
                    if (showingPointsNumber < pointsNumber )
                        showingPointsNumber++;
                    else
                        showingPointsNumber = 0;

                    Message msg = new Message();
                    //arg1默认为0,为在handler里好判断收到的信息,所以+1;
                    msg.arg1 = showingPointsNumber + 1;
                    handler.sendMessage(msg);


                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }


        }
    }
    private  void findVideos(File rootFile)
    {
        if (rootFile.isDirectory()&&rootFile.canRead()) {
            File files[] = rootFile.listFiles();
            if (files != null) {
                for (int i = 0; i < files.length; i++) {
                    File file = files[i];
                    if (file.isDirectory()) {
                        findVideos(file);
                    } else {
                        if (isVideo(file)) {
//                            System.out.println(file.toString());
                            String path = file.toString();
                            String name = file.getName();
                            videos.add(new Video(name, path));
                        }
                    }

                }

            }


        }
    }
    private boolean isVideo(File file)
    {
        String filename=file.toString();

        String videoStyle [] ={"3gp","mp4"};
        for(int i = 0 ; i < videoStyle.length ; i ++){
            if(filename.endsWith(videoStyle[i]))
                return true;
        }
        return  false;
    }

    class WriteVideo extends Thread {
        @Override
        public void run() {
            String cashFilePath = getExternalCacheDir().toString();
            File videosFile = new File(cashFilePath + "/videos.txt");
            if (!videosFile.exists())
                try {
                    videosFile.createNewFile();
                } catch (IOException e) {
                    e.printStackTrace();
                }

            try {
                BufferedWriter out = new BufferedWriter(new FileWriter(videosFile, false));

                for (Video video : videos) {
                    out.write(video.name);
                    out.write(":");
                    out.write(video.path);
                    out.newLine();
                }
                out.flush();
                out.close();
            } catch (IOException e) {
                e.printStackTrace();
            }

        }

    }



}

  

package com.example.zp.my;

import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.media.ThumbnailUtils;
import android.os.Handler;
import android.os.Message;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.util.ArrayList;


public class ChooseVideoActivity extends AppCompatActivity {

    File file;
    private String imageStyle=".jpg";
    private ListView videoList;
    private ArrayList<Video> videos =new ArrayList<Video>();
    public static final int CHOOSE_VIDEO_NUMBER_RESULT_CODE = 100;
    public Handler handler=new Handler(){
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);

            ImageView imageView = (ImageView) msg.obj;
            int  videoNumber =  msg.arg1;


            File imageFile = new File(file.toString()+"/"+videos.get(videoNumber).name+imageStyle);
            if(imageFile.exists()){
                imageView.setImageBitmap( BitmapFactory.decodeFile(imageFile.toString()));
            }
            else
            {
            Bitmap bitmap = videos.get(videoNumber).getVideoFirstBitmap();
            Bitmap bitmap2 =  ThumbnailUtils.extractThumbnail(bitmap,200,100);
            saveThePicture(bitmap2,videos.get(videoNumber).name,file);
            imageView.setImageBitmap(bitmap);
        }
        }
    };


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_choose_video);
        Intent intent=getIntent();
        ArrayList <String> videosItem = intent.getStringArrayListExtra("videosItem");
        if (videosItem != null)
            {
            getVideos(videosItem);
            }
        else
        {
            String cashFilePath=getExternalCacheDir().toString();
            File videosFile = new File(cashFilePath+"/videos.txt");
            try {
                BufferedReader reader2=new BufferedReader(new FileReader(videosFile));
                String value ;
                while ( (value = reader2.readLine())!= null)
                {
                    int pointer = value.lastIndexOf(":");
                    String name = value.substring(0,pointer);
                    String path = value.substring(pointer+1,value.length());
                    videos.add(new Video(name,path));
                }
                reader2.close();

            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        init();
    }
    private void init()
    {
        videoList= (ListView) findViewById(R.id.list_view);
        videoList.setAdapter(new VedioAdapter());

        file = new File(getExternalCacheDir().toString()+"videoImage");
        if(!file.exists())
        {
            file.mkdir();
        }


    }

    private void getVideos(ArrayList <String> videosItem)
    {
        for(String videoItem:videosItem) {
            int pointer = videoItem.lastIndexOf(":");
            String name = videoItem.substring(0, pointer);
            String path = videoItem.substring(pointer + 1, videoItem.length());
            videos.add(new Video(name, path));
        }
    }
    public int getItemNumber()
    {
        int videosNumber = videos.size();
        return videosNumber%2==1 ? (videosNumber/2+1) : (videosNumber/2);
    }

    class VedioAdapter extends BaseAdapter {

        @Override
        public int getCount() {
           return  getItemNumber();
        }

        @Override
        public Object getItem(int position) {
            return null;
        }

        @Override
        public long getItemId(int position) {
            return position;
        }

        @Override
        public View getView(final int position, View convertView, ViewGroup parent) {

            ViewHolder viewHolder = new ViewHolder();

            if(convertView==null) {
                convertView = getLayoutInflater().inflate(R.layout.vedeo_item, null);
                TextView tx_view1 = (TextView) convertView.findViewById(R.id.tx_video1);
                TextView tx_view2 = (TextView) convertView.findViewById(R.id.tx_video2);
                ImageView imageView1 = (ImageView) convertView.findViewById(R.id.image_view1);
                ImageView imageView2 = (ImageView) convertView.findViewById(R.id.image_view2);

                viewHolder.imageView_video1 = imageView1;
                viewHolder.imageView_video2 = imageView2;
                viewHolder.tx_view1 = tx_view1;
                viewHolder.tx_view2 = tx_view2;

                convertView.setTag(viewHolder);
            }
            else {
                viewHolder = (ViewHolder) convertView.getTag();
            }

                setImageViewMessage(viewHolder.imageView_video1 , position*2);
                 viewHolder.tx_view1.setText(videos.get(position * 2).name);

                if (position == getItemNumber() - 1) {
                    if (videos.size() % 2 == 0) {
                        setImageViewMessage(viewHolder.imageView_video2 , position*2+1);
                        viewHolder.tx_view2.setText(videos.get(position * 2 + 1).name);
                        viewHolder.imageView_video1.setOnClickListener(new ImageViewOnclickListener(position*2+1));
                    }
                } else {
                    setImageViewMessage(viewHolder.imageView_video2 , position*2+1);
                    viewHolder.tx_view2.setText(videos.get(position * 2 + 1).name);
                    viewHolder.imageView_video2.setOnClickListener(new ImageViewOnclickListener(position*2+1));
                }
            viewHolder.imageView_video1.setOnClickListener(new ImageViewOnclickListener(position*2));


            return convertView;
        }

        class ImageViewOnclickListener implements View.OnClickListener
        {
             private int videoNumber;
          public ImageViewOnclickListener(int videoNumber)
            {
                this.videoNumber=videoNumber;
            }
            @Override
            public void onClick(View v) {
                Intent intent = new Intent();
                intent.putExtra("chooseVideoNumber",videoNumber);
                intent.setAction("android.intent.action.VideoPlayer");
                intent.addCategory("android.intent.category.DEFAULT");
                startActivity(intent);
                finish();
            }
        }

        public void setImageViewMessage(ImageView imageView , int videoNumber){
            Message msg = new Message();
            msg.obj = imageView;
            msg.arg1 = videoNumber;
            handler.sendMessage(msg);
        }
    }
    static  class ViewHolder
    {
        TextView tx_view1;
        TextView tx_view2;
        ImageView imageView_video1;
        ImageView imageView_video2;
    }

    public void reSearchVideo(View v)
    {
        Intent intent=new Intent();
        intent.setAction("android.intent.reSearchVideo");
        intent.addCategory("android.intent.category.DEFAULT");
        startActivity(intent);
        finish();
    }


    //图片保存
    private void saveThePicture(Bitmap bitmap,String imageName,File fileDir)
    {
        File file =new File(fileDir.toString()+"/"+imageName+imageStyle);

       try {
            FileOutputStream fos=new FileOutputStream(file);
            if(bitmap.compress(Bitmap.CompressFormat.JPEG, 100, fos))
            {
                fos.flush();
                fos.close();
            }
        }
        catch(Exception e1)
        {
            e1.printStackTrace();
        }

    }

    @Override
    public void onBackPressed() {
        super.onBackPressed();

        Intent intent = new Intent();
        intent.setAction("android.intent.action.VideoPlayer");
        intent.addCategory("android.intent.category.DEFAULT");
        startActivity(intent);

    }
}

  

package com.example.zp.my;

import android.graphics.Bitmap;
import android.media.MediaMetadataRetriever;

/**
 * Created by lenovo on 2016/8/10.
 */
class Video
{
    public String name;
    public String  path;
    private Bitmap image;
    private int time;
    Video(String name,String path)//,Bitmap image
    {
        this.name = name;
        this.path = path;
    }

    public void setImage(Bitmap image)
    {
        this.image=image;
    }
    public void setTime(int time)
    {
      this.time=time;
    }

    public int getTime()
    {
        return this.time;
    }
    public Bitmap getVideoFirstBitmap()
    {
        MediaMetadataRetriever media = new MediaMetadataRetriever();
        media.setDataSource(this.path);
        Bitmap bitmap = media.getFrameAtTime();
        return bitmap;

    }
}

  

原文地址:https://www.cnblogs.com/bokeofzp/p/5979282.html