1. 程式人生 > >Android自定義視訊播放器(網路/本地)

Android自定義視訊播放器(網路/本地)

最近因公司專案要求需要寫一個播放器,自帶的又不太好用,也不太好看。自能自定義啦。查看了很多資料,都沒有完善的,還好得以為前輩的指點得以完成感謝Yang。本篇裡面我有可能有些地方寫得不好(都附上了註釋)。希望各路大神指點,虛心受教。

先來個圖(原始碼在後面附上)

視訊列表裡面的資料是本地的,如果你需要使用網路的只需要在此獲取伺服器的資料展示就行了。播放頁面在後面。

package com.eteng.moblieplayer.video;

import android.content.ContentResolver;
import android.content.Intent;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.provider.MediaStore;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ListView;
import android.widget.TextView;

import com.eteng.moblieplayer.BaseActivity;
import com.eteng.moblieplayer.R;
import com.eteng.moblieplayer.adapter.VideoAdapter;
import com.eteng.moblieplayer.beans.VideoBenas;
import com.eteng.moblieplayer.utils.StringTimeUtil;

import org.xutils.view.annotation.ViewInject;

import java.util.ArrayList;
import java.util.Formatter;
import java.util.List;

/**
 * Created by zqf on 2016/7/6.
 */
public class VideoActivity extends BaseActivity implements AdapterView.OnItemClickListener {

    private ListView video_listview;

    private TextView noresources_tv;

    private VideoBenas beans;
    private List<VideoBenas> data = new ArrayList<VideoBenas>();
    private VideoAdapter adapter;

    private StringTimeUtil util;

    public Handler handler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            switch (msg.what) {
                case 0:
                    if (data != null && data.size() != 0) {
                        noresources_tv.setVisibility(View.GONE);
                        adapter = new VideoAdapter(data, VideoActivity.this, util);
                        video_listview.setAdapter(adapter);
                    } else {
                        noresources_tv.setVisibility(View.VISIBLE);
                    }

                    break;
            }
        }
    };


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        settabtitle("視訊列表");
        setrightvisible(View.GONE);
        video_listview = (ListView) findViewById(R.id.video_listviw);
        noresources_tv = (TextView) findViewById(R.id.noresources_tv);
        util = new StringTimeUtil();
        getAllVideo();

        video_listview.setOnItemClickListener(this);
    }

    private void getAllVideo() {
        new Thread(new Runnable() {
            @Override
            public void run() {
                ContentResolver resolver = getContentResolver();
                Uri uri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
                //查詢的條件
                String[] projection = {MediaStore.Video.Media.TITLE,   //標題
                        MediaStore.Video.Media.DESCRIPTION,     //描述
                        MediaStore.Video.Media.SIZE,        //大小
                        MediaStore.Video.Media.DURATION,    //時長
                        MediaStore.Video.Media.DATA};   //絕對路徑
                Cursor cursor = resolver.query(uri, projection, null, null, null);
                while (cursor.moveToNext()) {
                    //判斷視訊大小>3MB的才新增進來。
                    if (cursor.getLong(2) > 3 * 1024 * 1024) {
                        beans = new VideoBenas();
                        beans.setTitle(cursor.getString(0));
                        beans.setDescribe(cursor.getString(1));
                        beans.setSize(cursor.getLong(2));
                        beans.setLongtime(cursor.getString(3));
                        beans.setPath(cursor.getString(4));
                        data.add(beans);
                    }
                }
                handler.sendEmptyMessage(0);
            }
        }).start();


    }

    @Override
    public void leftonclick() {
        finish();
    }

    @Override
    public void rightonclick() {

    }

    //載入子佈局內容
    @Override
    public View setcontent() {
        return View.inflate(VideoActivity.this, R.layout.activity_video, null);
    }

    @Override
    public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
        VideoBenas item = data.get(position);
        Intent intent = new Intent(VideoActivity.this, VideoPlayerActivity.class);
        intent.setData(Uri.parse(item.getPath()));
        intent.putExtra("videotitle",item.getTitle());
        startActivity(intent);
    }
}

好了,接下來就是播放器頁面了。

package com.eteng.moblieplayer.video;

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.os.Handler;
import android.os.Message;
import android.util.Log;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.View;
import android.view.WindowManager;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ProgressBar;
import android.widget.RelativeLayout;
import android.widget.SeekBar;
import android.widget.TextView;
import android.widget.Toast;

import com.eteng.moblieplayer.BaseActivity;
import com.eteng.moblieplayer.R;
import com.eteng.moblieplayer.utils.StringTimeUtil;
import com.eteng.moblieplayer.view.VideoView;

/**
 * Created by zqf on 2016/7/6.
 * 播放頁面
 */
public class VideoPlayerActivity extends BaseActivity implements MediaPlayer.OnPreparedListener, MediaPlayer.OnInfoListener {
    private VideoView videoView;
    //--播放的地址uri
    private Uri uri;
    private ImageView play_imag, fullview_imag, back_imag, battery_imag;
    private SeekBar mseekBar;
    private TextView videoTitle, SystemTime;
    private TextView videocurrent_time, videototal_time;
    private StringTimeUtil utils;
    private MyBrodCastReceiver receiver;
    //設定電量
    private int leave;
    //手勢識別器
    private GestureDetector detector;
    //頂部佈局
    private RelativeLayout top_layout;
    //底部佈局
    private LinearLayout bottom_layout;
    /**
     * 判斷是否播放
     */
    private boolean isPlayer = false;
    /***
     * 判斷Activity是否被銷燬
     * --true-->銷燬
     * --false -->沒有銷燬
     */
    private boolean isDestory = false;
    //
    private static final int PROGRESS = 1;
    //隱藏頂部和底部的變數
    private static final int HIDE_TOPBOTTOMLAYOUT = 2;

    /**
     * 網路載入等待佈局
     */
    private LinearLayout ll_loading;

    /***
     * 出現卡的緩衝載入
     */
    private ProgressBar pg_buff;

    private Handler mhandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            switch (msg.what) {
                case PROGRESS:
                    //設定進度
                    int currenttime = videoView.getCurrentPosition();
                    videocurrent_time.setText(utils.stringfortime(currenttime));
                    //更新seekbar
                    mseekBar.setProgress(currenttime);
                    //更新電量          //電量顯示和系統時間可自行設定多久時間更新一次
                    setBattery();
                    //設定系統時間
                    setsystemTime();

                    /***
                     * 得到視訊快取度
                     * --快取比例值-0~100
                     */
                    int Percentage = videoView.getBufferPercentage();
                    int total = Percentage * mseekBar.getMax();
                    int secondaryprogress = total / 100;
                    mseekBar.setSecondaryProgress(secondaryprogress);

                    if (!isDestory) {
                        mhandler.removeMessages(PROGRESS);
                        //訊息的死迴圈--用於更新播放進度
                        mhandler.sendEmptyMessageDelayed(PROGRESS, 1000);
                    }
                    break;
                case HIDE_TOPBOTTOMLAYOUT:
                    hidelayout();
                    break;
            }
        }
    };


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        settabvisible(View.GONE);
        initView();
        initData();
        setonclick();
        //得到播放地址
        uri = getIntent().getData();
        videoView.setVideoURI(uri); //設定路徑
        videoView.setOnPreparedListener(this);  //準備好的監聽事件
    }

    private void setsystemTime() {
        SystemTime.setText(utils.getSystemTime());
    }


    private void setBattery() {
        if (leave <= 5) {
            battery_imag.setImageResource(R.mipmap.icv_power_00);
        } else if (leave <= 20) {
            battery_imag.setImageResource(R.mipmap.icv_power_01);
        } else if (leave <= 40) {
            battery_imag.setImageResource(R.mipmap.icv_power_02);
        } else if (leave <= 60) {
            battery_imag.setImageResource(R.mipmap.icv_power_03);
        } else if (leave <= 80) {
            battery_imag.setImageResource(R.mipmap.icv_power_04);
        } else if (leave <= 100) {
            battery_imag.setImageResource(R.mipmap.icv_power_05);
        }
    }

    /***
     * true--顯示--false--隱藏
     */
    private boolean isShowLayout = false;


    private void initData() {
        videoTitle.setText(getIntent().getStringExtra("videotitle"));
        isDestory = false;
        utils = new StringTimeUtil();
        //註冊電量監聽的廣播
        IntentFilter intentFilter = new IntentFilter();
        intentFilter.addAction(Intent.ACTION_BATTERY_CHANGED);
        receiver = new MyBrodCastReceiver();
        registerReceiver(receiver, intentFilter);
        //例項化
        detector = new GestureDetector(VideoPlayerActivity.this, new GestureDetector.OnGestureListener() {
            //單擊
            @Override
            public boolean onDown(MotionEvent e) {
                Log.e("TAG", "onDown");
                if (isShowLayout) {
                    removeHideTopBottomLayoutMessage();
                    hidelayout();
                } else {
                    sendDelayedHideTopBottomLayout();
                    showLayout();
                }
                return true;
            }

            //長按執行的順序---1.onDown-->2.onShowPress-->onLongPress
            @Override
            public void onShowPress(MotionEvent e) {
                Log.e("TAG", "onShowPress");
            }

            //單擊後執行onDown接著執行的方法
            @Override
            public boolean onSingleTapUp(MotionEvent e) {
                Log.e("TAG", "onSingleTapUp");
                return false;
            }

            //滑動
            @Override
            public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
                Log.e("TAG", "onScroll");
                return false;
            }

            //長按
            @Override
            public void onLongPress(MotionEvent e) {
                Log.e("TAG", "onLongPress");
            }

            @Override
            public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
                return false;
            }
        });
    }


    /***
     * 傳送延遲隱藏
     */
    private void sendDelayedHideTopBottomLayout() {
        mhandler.sendEmptyMessageDelayed(HIDE_TOPBOTTOMLAYOUT, 5000);
    }

    /***
     * 移除延遲隱藏的Handler訊息
     */
    private void removeHideTopBottomLayoutMessage() {
        mhandler.removeMessages(HIDE_TOPBOTTOMLAYOUT);
    }

    /***
     * 顯示的方法
     */
    private void showLayout() {
        isShowLayout = true;
        top_layout.setVisibility(View.VISIBLE);
        bottom_layout.setVisibility(View.VISIBLE);

    }

    /***
     * 隱藏的方法
     */
    private void hidelayout() {
        isShowLayout = false;
        top_layout.setVisibility(View.GONE);
        bottom_layout.setVisibility(View.GONE);
    }

    /***
     * 使用手勢介面卡
     *
     * @param event
     * @return
     */
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        super.onTouchEvent(event);
        detector.onTouchEvent(event);
        return true;    //返回true視交由人為處理
    }

    /***
     * 卡或者拖動卡時候出現的回撥
     *
     * @param mp
     * @param what
     * @param extra
     * @return
     */
    @Override
    public boolean onInfo(MediaPlayer mp, int what, int extra) {
        switch (what) {
            case MediaPlayer.MEDIA_INFO_BUFFERING_START:    //開始出現卡或者拖動卡
                pg_buff.setVisibility(View.VISIBLE);
                break;
            case MediaPlayer.MEDIA_INFO_BUFFERING_END:      //結束卡或者拖動卡情況
                pg_buff.setVisibility(View.GONE);
                break;
        }
        return true;
    }

    private class MyBrodCastReceiver extends BroadcastReceiver {
        @Override
        public void onReceive(Context context, Intent intent) {
            //返回一個電量的範圍值
            leave = intent.getIntExtra("level", 0);
        }
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        isDestory = true;
        unregisterReceiver(receiver);
        receiver = null;
        videoView.stopPlayback();
    }

    public void initView() {
        pg_buff = (ProgressBar) findViewById(R.id.pg_buff);
        videoView = (VideoView) findViewById(R.id.videoview);
        ll_loading = (LinearLayout) findViewById(R.id.ll_loading);
        top_layout = (RelativeLayout) findViewById(R.id.topLayout);
        bottom_layout = (LinearLayout) findViewById(R.id.bottomLayout);
        SystemTime = (TextView) findViewById(R.id.videosystemTime);
        battery_imag = (ImageView) findViewById(R.id.videoPower);
        back_imag = (ImageView) findViewById(R.id.videoBack);
        play_imag = (ImageView) findViewById(R.id.videoPlay);
        fullview_imag = (ImageView) findViewById(R.id.videoFullScreen);
        mseekBar = (SeekBar) findViewById(R.id.videoPlayProgress);
        videoTitle = (TextView) findViewById(R.id.videoTitle);
        videocurrent_time = (TextView) findViewById(R.id.videoCurrentProgress);
        videototal_time = (TextView) findViewById(R.id.videototalTime);

    }

    public void setonclick() {
        back_imag.setOnClickListener(onclicklistener);
        play_imag.setOnClickListener(onclicklistener);
        fullview_imag.setOnClickListener(onclicklistener);
        videoView.setOnInfoListener(this);
        mseekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
            /***
             *
             * @param seekBar-->自身的seekba
             * @param progress-->seekbar的位置,視訊的長度和seekbar的位置一一對應
             * @param fromUser-->如果是人為的拖動值為--true,如seekbar自身在改變的值--false
             */
            @Override
            public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
                if (fromUser) {
                    videoView.seekTo(progress);
                }
            }

            /**
             * 手指開始拖動時進行回撥
             * @param seekBar
             */
            @Override
            public void onStartTrackingTouch(SeekBar seekBar) {
                removeHideTopBottomLayoutMessage();
            }

            /**
             * 手指離開回調
             * @param seekBar
             */
            @Override
            public void onStopTrackingTouch(SeekBar seekBar) {
                sendDelayedHideTopBottomLayout();
            }
        });


        /***
         * 視訊加載出錯時進行回掉
         * --true-->人為處理出錯的結果
         */
        videoView.setOnErrorListener(new MediaPlayer.OnErrorListener() {
            @Override
            public boolean onError(MediaPlayer mp, int what, int extra) {
                Toast.makeText(VideoPlayerActivity.this, "視訊出錯了", Toast.LENGTH_LONG).show();
                finish();
                return true;
            }
        });
    }


    View.OnClickListener onclicklistener = new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            switch (v.getId()) {
                case R.id.videoPlay:
                    if (isPlayer) {
                        videoView.pause();
                        play_imag.setImageResource(R.mipmap.icv_play);
                    } else {
                        videoView.start();
                        play_imag.setImageResource(R.mipmap.icv_pause);
                    }
                    isPlayer = !isPlayer;
                    break;
                case R.id.videoBack:
                    finish();
                    videoView.stopPlayback();
                    break;
            }
        }
    };


    @Override
    public void leftonclick() {

    }

    @Override
    public void rightonclick() {

    }

    //設定子佈局
    @Override
    public View setcontent() {
        return View.inflate(VideoPlayerActivity.this, R.layout.activity_videoplayer, null);
    }

    /***
     * 監聽是否準備好了
     *
     * @param mp
     */
    @Override
    public void onPrepared(MediaPlayer mp) {
        videoView.start();
        play_imag.setImageResource(R.mipmap.icv_pause);
        isPlayer = true;
        //獲取總時長
        int duration = videoView.getDuration();
        videototal_time.setText("/" + utils.stringfortime(duration));
        //設定seekbar的最大值
        mseekBar.setMax(duration);
        setsystemTime();
        mhandler.sendEmptyMessageDelayed(PROGRESS, 1000);
        sendDelayedHideTopBottomLayout();
        ll_loading.setVisibility(View.GONE);
    }
}
最後結尾來個圖吧!

上次忘記發源碼地址啦,給補上,抱歉。

原始碼地址