Android视频播放器

一、启动页

二、主要页面

2、实现本地页面

3、实现网络页面

4、实现推荐页面

5、自定义播放器



一、启动页

展示启动页,3秒后跳转至主页面,实现点击马上跳转到主页面。

1、创建一个名为My_player的项目

API 19:Android4.4

创建一个名为Start_Activity 的窗体

把PNG图片login_icon复制到drawable里面

编写activi_start的布局

xml version="1.0" encoding="utf-8"?>
xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"

    android:orientation="vertical"
    android:gravity="center">
            android:layout_width="60dp"
        android:layout_height="60dp"
        android:src="@drawable/login_icon"/>

            android:layout_width="wrap_content"
        android:layout_height="wrap_content">
                    android:layout_width="20dp"
            android:layout_height="20dp"
            />
                    android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="正在加载"/>

    



在Start_Activity创建一个名为StartToMain()的方法

在方法里面实例化Itent 并实现窗口跳转

在onCreate里面实例化Handler,通过handler.postDelayed,设置延迟3S调用StartToMain

优化:

重写onDestroy()方法

调用handler.removeCallbacks;在页面销毁时停止线程。释放资源

重写onTouchEvent()方法

调用StartToMain();实现点击页面马上跳转

package com.example.administrator.my_player;

import android.content.Intent;
import android.os.Handler;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.MotionEvent;

public class Start_Activity extends AppCompatActivity {
    private Handler handler;
    private boolean isFistStart=false;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_start_);
        handler=new Handler();
        handler.postDelayed(new Runnable() {
            @Override
            public void run() {
                StartToMain();
            }
        },3000);
    }
    private void StartToMain(){

        if(!isFistStart){

            isFistStart=true;
            Intent intent=new Intent(Start_Activity.this,MainActivity.class);
            startActivity(intent);
            finish();
        }
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        StartToMain();
        return super.onTouchEvent(event);
    }

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


修改AndroidManifest.xml清单文件,首先进入Start_Activity

xml version="1.0" encoding="utf-8"?>
xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.administrator.my_player">

            android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        android:name=".MainActivity">

        
        android:name=".Start_Activity">
            
                android:name="android.intent.action.MAIN" />

                android:name="android.intent.category.LAUNCHER" />
            
        
    


二、主要页面

创建顶部和底部的布局文件分别命名为titlebar.xml和bottombar.xml

titlebar.xml

xml version="1.0" encoding="utf-8"?>
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#ff3097fd"
    android:orientation="horizontal"
    android:gravity="center_vertical">
            android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginLeft="8dp"
        android:src="@drawable/ic_topbanner_logo"
        />


            android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:id="@+id/tv_search"
        android:background="@drawable/tv_search_bg_selector"
        android:drawableLeft="@drawable/tv_search_drawable_selector"
        android:textColor="@drawable/tv_search_textcolor_selector"
        android:layout_marginLeft="8dp"
        android:clickable="true"
        android:text="全网搜索"
        android:textSize="18sp"
        android:drawablePadding="3dp"/>

            android:id="@+id/rl_game"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginLeft="5dp"
        >
                    android:id="@+id/tv_game"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:drawableLeft="@drawable/ic_topbanner_game"/>

        
            android:layout_width="6dp"
            android:layout_height="6dp"
            android:layout_alignRight="@id/tv_game"
            android:background="@drawable/dot"/>


    

            android:id="@+id/iv_record"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:src="@drawable/ic_topbanner_record"
        android:layout_marginLeft="5dp"
        android:layout_marginRight="8dp"
        />

bottombar.xml

xml version="1.0" encoding="utf-8"?>

    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/myRg"
    android:layout_width="match_parent"
    android:orientation="horizontal"
    android:layout_height="0dp"
    android:layout_weight="1"
    android:background="#dadad8"
    >

            android:id="@+id/radioButtonTJ"
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:layout_weight="1"
        android:drawableTop="@drawable/rb_search_bg_drawable_recommend"

        style="@style/buttom_tag_styles"
        android:text="推荐页"


        />

            android:id="@+id/radioButtonBD"
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:layout_weight="1"
        android:drawableTop="@drawable/rb_search_bg_drawable_local"
        style="@style/buttom_tag_styles"
        android:text="本地页"


        />

            android:id="@+id/radioButtonWL"
        style="@style/buttom_tag_styles"
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:layout_weight="1"
        android:drawableTop="@drawable/rb_search_bg_drawable_network"
        android:text="网络页" />






\

其中有个

 style="@style/buttom_tag_styles"

要在styles.xlm




编写activity_main.xml的布局

xml version="1.0" encoding="utf-8"?>
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    >

    layout="@layout/titlebar"
        android:layout_height="0dp"
        android:layout_weight="1"
        android:layout_width="match_parent">

            android:id="@+id/fl_welcome_content"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="8"
        >

    


    layout="@layout/bootmmt"
        android:layout_height="0dp"
        android:layout_weight="1"
        android:layout_width="match_parent">



创建一个BasePager的抽象类

package com.example.administrator.my_player.Base;

import android.content.Context;
import android.view.View;

public abstract class BasePager {
    public Context context;
    public View rootView;
    public boolean isInt=false;

    public BasePager(Context context) {
        this.context = context;
        rootView=initView();
    }

    protected abstract View initView();

    public void initData(){}
}

创建一个BasePager的抽象类

package com.example.administrator.my_player.Base;

 

import android.content.Context;

import android.view.View;

 

public abstractclass BasePager {

    public Context context;

    public View rootView;

    public boolean isInt=false;

 

    public BasePager(Contextcontext) {

        this.context = context;

        rootView=initView();

    }

 

    protected abstract ViewinitView();

 

    public void initData(){}

}

创建三个继承BasePager的类

创建三个对应的布局

现在先对Local进行,创建布局文件activity_local_page

xml version="1.0" encoding="utf-8"?>

xmlns:android="http://schemas.android.com/apk/res/android"

    android:orientation="vertical" android:layout_width="match_parent"

    android:layout_height="match_parent">

    xmlns:android="http://schemas.android.com/apk/res/android"

        android:layout_width="match_parent"

        android:layout_height="match_parent">

 

       

            android:id="@+id/listView"

            android:divider="@null"

            android:layout_width="match_parent"

            android:layout_height="match_parent"/>

 

       

            android:id="@+id/tv_nomedia"

            android:layout_width="wrap_content"

            android:layout_height="wrap_content"

            android:layout_centerInParent="true"

            android:text="没有发现视屏..."

            android:textColor="#000"

            android:textSize="18sp"

            android:visibility="gone"/>

 

   

       

            android:id="@+id/pb_loading"

            android:layout_width="wrap_content"

            android:layout_height="wrap_content"

            android:layout_centerInParent="true"/>

 

   

 

接着对Local进行修改

package com.example.administrator.my_player.Frame;

 

import android.content.Context;

import android.util.Log;

import android.view.View;

import android.widget.ListView;

import android.widget.ProgressBar;

import android.widget.TextView;

 

import com.example.administrator.my_player.Base.BasePager;

import com.example.administrator.my_player.R;

 

public class Local extends BasePager{

    private ListView lv;

    private TextView tv_nomedia;

    private ProgressBar pb_loading;

    public Local(Contextcontext) {

        super(context);

    }

 

    @Override

    protected View initView() {

        Log.e("clm","Locat初始化");

        View view=View.inflate(context, R.layout.activity_local_page,null);

        lv =(ListView) view.findViewById(R.id.listView);

        tv_nomedia =(TextView) view.findViewById(R.id.tv_nomedia);

        pb_loading =(ProgressBar) view.findViewById(R.id.pb_loading);

        return view;

    }

 

    @Override

    public void initData() {

        super.initData();

    }

}

Network,Recommend都要在initView

 Viewview=View.inflate(context, R.layout.activity_newwork_page,null);

 Viewview=View.inflate(context, R.layout.activity_recomm,null)

并且给他们的布局文件添加一个TextView并赋值text

接着到MainActivity

package com.example.administrator.my_player;

 

 

import android.annotation.SuppressLint;

import android.support.annotation.Nullable;

import android.support.v4.app.Fragment;

import android.support.v4.app.FragmentActivity;

import android.support.v4.app.FragmentManager;

import android.support.v4.app.FragmentTransaction;

import android.os.Bundle;

import android.util.Log;

import android.view.LayoutInflater;

import android.view.View;

import android.view.ViewGroup;

import android.widget.RadioGroup;

 

import com.example.administrator.my_player.Base.BasePager;

import com.example.administrator.my_player.Frame.Local;

import com.example.administrator.my_player.Frame.Network;

import com.example.administrator.my_player.Frame.Recommend;

 

import java.util.ArrayList;

 

public class MainActivity extends FragmentActivity{

    private RadioGroup myRG;

    private static ArrayList basePagers;

    private static int position;

    @Override

    protected void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_main);

        initView();

    }

    private void initView(){

        Log.e("clm","初始化数据");

        myRG=(RadioGroup) findViewById(R.id.myRg);

        basePagers = new ArrayList<>();

        basePagers.add(new Recommend(this));

        basePagers.add(new Local(this));

        basePagers.add(new Network(this));

        position=0;

 

        setFragment();

 

        myRG.setOnCheckedChangeListener(new MyOnCheckedChangeListener());

   myRG.check(R.id.radioButton_Recommend);

 

    }

 

    private void setFragment() {

        //1.得到FragmentManger

        FragmentManager manager = getSupportFragmentManager();

        //2.开启事物

        FragmentTransaction ft = manager.beginTransaction();

 

        //3.替换

        ft.replace(R.id.fl_welcome_content,new ReplaceFragment());

        //4.提交事物

        ft.commit();

    }

    @SuppressLint("ValidFragment")

    public static class ReplaceFragmentextends Fragment {

        public ReplaceFragment() {

        }

 

        @Nullable

        @Override

        public ViewonCreateView(LayoutInflater inflater, @NullableViewGroup container, @Nullable BundlesavedInstanceState) {

 

            BasePager basePager=getBasePager();

            return basePager.rootView;

 

        }

 

        private BasePagergetBasePager() {

            BasePager basePager = basePagers.get(position);

            if (basePager!=null&&!basePager.isInt){

                basePager.initData();

                basePager.isInt=true;

 

 

            }

            return basePager;

        }

    }

 

 

    private class MyOnCheckedChangeListenerimplements RadioGroup.OnCheckedChangeListener {

        @Override

        public void onCheckedChanged(RadioGroupradioGroup, int i) {

            switch (i){

                case R.id.radioButton_Recommend:

                    position = 0;

                    break;

                case R.id.radioButton_Local:

                    position = 1;

                    break;

                case R.id.radioButton_Network:

                    position = 2;

                    break;

 

            }

            setFragment();

        }

    }

}

 

接着继续对Local完善,首先创建一个JavaBean,用来保存视频信息

package com.example.administrator.my_player.Bean;

 

import java.io.Serializable;

 

public class Mediaitem implements Serializable{

    private String name;//视频文件在sdcard的名称

    private long duration;//视频总时长

    private long size;//视频的文件大小

    private String data;//视频的绝对地址

    private String artist;//歌曲的演唱者

    private String desc;//描述

    private String imageUrl;//图片地址

 

    public Mediaitem(String coverImg, StringhightUrl, String movieName, StringvideoTitle) {

        super();

        this.imageUrl= coverImg;

        this.data= hightUrl;

        this.name= movieName;

        this.desc= videoTitle;

    }

    public Mediaitem(){

 

    }

    @Override

    public String toString() {

        return "Mediaitem{"+

                "name='" + name+ '\'' +

                ", duration=" + duration+

                ", size=" + size+

                ", data='" + data+ '\'' +

                ", artist='" + artist+ '\'' +

                ", desc='" + desc+ '\'' +

                ", imageUrl='" + imageUrl+ '\'' +

                '}';

    }

 

    public String getName() {

        return name;

    }

 

    public void setName(String name) {

        this.name = name;

    }

 

    public long getDuration() {

        return duration;

    }

 

    public void setDuration(long duration) {

        this.duration = duration;

    }

 

    public long getSize() {

        return size;

    }

 

    public void setSize(long size) {

        this.size = size;

    }

 

    public String getData() {

        return data;

    }

 

    public void setData(String data) {

        this.data = data;

    }

    public String getArtist() {

        return artist;

    }

 

    public void setArtist(String artist) {

        this.artist = artist;

    }

 

    public String getDesc() {

        return desc;

    }

 

    public void setDesc(String desc) {

        this.desc = desc;

    }

 

    public String getImageUrl() {

        return imageUrl;

    }

 

    public void setImageUrl(String imageUrl) {

        this.imageUrl = imageUrl;

    }

}

接着去Local声明一个变量

private  ArrayList mediaItems;

声明一个Handler

private Handler handler=new Handler(){

    @Override

    public void handleMessage(Message msg) {

        super.handleMessage(msg);

       

    }

};

创建一个叫做getDataFromLocal的方法,目的是获得本地视频,通过子线程获得本地视频,获得完成后跳回到handler

public void getDataFromLocal(){

    new Thread(){

        @Override

        public void run() {

            Log.e("clm","Local子线程开启");

            mediaItems = new ArrayList();

            ContentResolver resolver = context.getContentResolver();

            Uri uri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;

            String[] objs = {

                    MediaStore.Video.Media.DISPLAY_NAME,//视频文件在sdcard的名称

                    MediaStore.Video.Media.DURATION,//视频总时长

                    MediaStore.Video.Media.SIZE,//视频的文件大小

                    MediaStore.Video.Media.DATA,//视频的绝对地址

                    MediaStore.Video.Media.ARTIST,//歌曲的演唱者

 

            };

            Cursor cursor = resolver.query(uri, objs, null, null, null);

 

            while (cursor.moveToNext()){

                Log.e("clm","开始循环获取数据");

                Mediaitem mediaItem = new Mediaitem();

                mediaItems.add(mediaItem)//要写在前面

 

                String name = cursor.getString(0);//视屏的名称

                mediaItem.setName(name);

 

                long duration = cursor.getLong(1);//视屏的时长

                mediaItem.setDuration(duration);

 

                long size = cursor.getLong(2);//视屏文件大小

                mediaItem.setSize(size);

 

                String data = cursor.getString(3);//视屏的播放地址

                mediaItem.setData(data);

 

                String artist = cursor.getString(4);//艺术家

                mediaItem.setArtist(artist);

            }

 

            cursor.close();

 

            handler.sendEmptyMessage(10);

 

 

        }

    }.start();

 

 

}

创建一个自定义适配器继承自BaseAdapte,创建一个适配器的布局文件,创建一个工具类Utils用来转换时间单位

Utils代码

package com.example.administrator.my_player.Utils;

import android.content.Context;

import android.net.TrafficStats;

 

import java.util.Formatter;

import java.util.Locale;

 

public class Utils {

 

    private StringBuilder mFormatBuilder;

    private Formatter mFormatter;

 

    private long lastTotalRxBytes = 0;

    private long lastTimeStamp = 0;

 

    public Utils() {

        // 转换成字符串的时间

        mFormatBuilder = new StringBuilder();

        mFormatter = new Formatter(mFormatBuilder, Locale.getDefault());

 

    }

 

    /**

     * 把毫秒转换成:1:20:30这里形式

     * @param timeMs

     * @return

     */

    public StringstringForTime(int timeMs) {

        int totalSeconds= timeMs / 1000;

        int seconds = totalSeconds % 60;

 

        int minutes = (totalSeconds / 60) % 60;

 

        int hours = totalSeconds / 3600;

 

        mFormatBuilder.setLength(0);

        if (hours > 0) {

            return mFormatter.format("%d:%02d:%02d", hours, minutes, seconds)

                    .toString();

        } else{

            return mFormatter.format("%02d:%02d", minutes, seconds).toString();

        }

    }

 

    /**

     * 判断是否是网络的资源

     * @param uri

     * @return

     */

    public boolean isNetUri(String uri){

        boolean result= false;

        if(uri != null){

            if(uri.toLowerCase().startsWith("http")||uri.toLowerCase().startsWith("rtsp")||uri.toLowerCase().startsWith("mms")){

                result = true;

            }

        }

        return result;

    }

 

    /**

     * 得到网络速度

     * 每隔两秒调用一次

     * @param context

     * @return

     */

    public StringgetNetSpeed(Context context){

        String netSpeed = "0 kb/s";

        long nowTotalRxBytes = TrafficStats.getUidRxBytes(context.getApplicationInfo().uid)==TrafficStats.UNSUPPORTED ? 0 :(TrafficStats.getTotalRxBytes()/1024);//转为KB;

        long nowTimeStamp= System.currentTimeMillis();

        long speed = ((nowTotalRxBytes - lastTotalRxBytes) * 1000 / (nowTimeStamp - lastTimeStamp));//毫秒转换

 

        lastTimeStamp = nowTimeStamp;

        lastTotalRxBytes = nowTotalRxBytes;

        netSpeed  = String.valueOf(speed)+ " kb/s";

        return netSpeed;

    }

 

}

本地适配器代码

package com.example.administrator.my_player.Adapter;

 

import android.content.Context;

import android.text.format.Formatter;

import android.view.View;

import android.view.ViewGroup;

import android.widget.BaseAdapter;

import android.widget.ImageView;

import android.widget.TextView;

 

import com.example.administrator.my_player.Bean.Mediaitem;

import com.example.administrator.my_player.R;

import com.example.administrator.my_player.Utils.Utils;

 

import java.util.ArrayList;

 

public class Local_Adapter extends BaseAdapter{

    private Context context;

    private ArrayList mediaitem_list;

    private Mediaitem mediaitem;

    private Utils utils;

    public Local_Adapter(Context context, ArrayList mediaitem_list){

        this.context = context;

        this.mediaitem_list= mediaitem_list;

        utils=new Utils();

    }

    @Override

    public int getCount() {

        return mediaitem_list.size();

    }

 

    @Override

    public Object getItem(int i) {

        return null;

    }

 

    @Override

    public long getItemId(int i) {

        return 0;

    }

 

    @Override

    public View getView(int i, View view, ViewGroup viewGroup) {

        local_adapter myView;

        if(view==null){

            view=View.inflate(context, R.layout.local_adapter,null);

            myView=new local_adapter();

            myView.img= (ImageView) view.findViewById(R.id.imageview);

            myView.tv1= (TextView) view.findViewById(R.id.tv1);

            myView.tv2= (TextView) view.findViewById(R.id.tv2);

            myView.tv3= (TextView) view.findViewById(R.id.tv3);

            view.setTag(myView);

        }else{

            myView=(Local_Adapter.local_adapter) view.getTag();

        }

 

        mediaitem=mediaitem_list.get(i);

 

        String name=mediaitem.getName()+"";

        myView.tv1.setText("名字:"+name);

        myView.tv2.setText("时间:"+utils.stringForTime((int) mediaitem.getDuration()));

        myView.tv3.setText(Formatter.formatFileSize(context,mediaitem.getSize()));

        return view;

    }

    private static class local_adapter{

        ImageView img;

        TextView tv1;

        TextView tv2;

        TextView tv3;

 

    }

}

本地适配器布局代码

xml version="1.0" encoding="utf-8"?>

xmlns:android="http://schemas.android.com/apk/res/android"

    android:layout_width="match_parent"

    android:layout_height="wrap_content"

    android:paddingTop="10dp">

   

        android:padding="2dp"

        android:scaleType="fitXY"

        android:layout_width="80dp"

        android:layout_height="80dp"

        android:id="@+id/imageview"

        android:src="@drawable/ic_launcher"/>

   

        android:layout_width="wrap_content"

        android:layout_height="wrap_content"

        android:layout_weight="1"

        android:orientation="vertical">

       

            android:layout_width="wrap_content"

            android:layout_height="wrap_content"

            android:id="@+id/tv1"

            android:text="tv1"/>

       

            android:layout_width="wrap_content"

            android:layout_height="wrap_content"

            android:id="@+id/tv2"

            android:text="tv2"/>

 

   

 

   

        android:layout_width="wrap_content"

        android:layout_height="wrap_content"

        android:orientation="vertical"

        >

       

            android:layout_width="wrap_content"

            android:layout_height="60dp"

            >

       

            android:layout_width="wrap_content"

            android:layout_height="0dp"

            android:layout_weight="1"

            android:id="@+id/tv3"

            android:text=" "/>

 

   

 

 

 

然后在Local的handler里面,进行数据绑定

public void handleMessage(Message msg) {

    super.handleMessage(msg);

    Log.e("clm", "获取本地的数据为-> "+ mediaItems.toString());

    if(mediaItems != null &&mediaItems.size() > 0){

        //有数据

 

 

        local_adapter=new Local_Adapter(context,mediaItems);

        lv.setAdapter(local_adapter);

        //设置适配器

 

 

 

        Log.e("clm","Local有数据!");

        //隐藏文本

        tv_nomedia.setVisibility(View.GONE);

    }else{

        Log.e("clm","Local没数据!!!");

        //没有数据

        //文本显示

        tv_nomedia.setVisibility(View.VISIBLE);

    }

 

        //隐藏ProgressBar

    pb_loading.setVisibility(View.GONE);

}

并在initData调用getDataFromLocal,获得本地视频信息

 

然后在清单文件里面添加权限

android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

android:name="android.permission.READ_EXTERNAL_STORAGE"/>

android:name="android.permission.INTERNET"/>

记得给模拟器添加视频,这里不详说了,可以通过DDMS等方法导入MP4视频。

然后现在运行的结果是:

接着继续对Local的initView的lv添加监听事件

lv.setOnItemClickListener(new AdapterView.OnItemClickListener() {
    @Override
    public void onItemClick(AdapterView adapterView, View view, int i, long l) {
        Toast.makeText(context,"你选择的是:"+mediaItems.get(i).getName(),Toast.LENGTH_SHORT).show();
        Intent intent=new Intent(Intent.ACTION_VIEW);
        Uri uri=Uri.parse(mediaItems.get(i).getData());
        intent.setDataAndType(uri,"video/*");

        context.startActivity(intent);

    }
});

 到这一步,基本可以播放本地视频了


接着我们要使用时光网的接口用来访问网络数据

接口是:

http://api.m.mtime.cn/PageSubArea/TrailerList.api

接着我们去到Network,这里跟Local里面差不多,多了解析JSON,这里我们采用手动的方式解析,先给布局文件

xml version="1.0" encoding="utf-8"?>
xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="match_parent"
    android:layout_height="match_parent">
    xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

                    android:id="@+id/listView"
            android:divider="@null"
            android:layout_width="match_parent"
            android:layout_height="match_parent"/>

                    android:id="@+id/tv_nomedia"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerInParent="true"
            android:text="没有发现视屏..."
            android:textColor="#000"
            android:textSize="18sp"
            android:visibility="gone"/>



                    android:id="@+id/pb_loading"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerInParent="true"/>

    

接着是具体代码,这里我们先用Loacl的Adapter。

package com.example.administrator.my_player.Frame;

import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ListView;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.VideoView;

import com.example.administrator.my_player.Adapter.Local_Adapter;
import com.example.administrator.my_player.Base.BasePager;
import com.example.administrator.my_player.Bean.Mediaitem;
import com.example.administrator.my_player.MainActivity;
import com.example.administrator.my_player.R;

import org.json.JSONArray;
import org.json.JSONObject;

import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.ArrayList;

public class Network extends BasePager {
    private String json;
    private ArrayList mediaItems;
    private ListView lv;
    private TextView tv_nomedia;
    private ProgressBar pb_loading;
    private Local_Adapter wl_adapter;

    private Handler handler = new Handler(){
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);

            switch (msg.what){
                case 1:
                    Log.e("clm","接收成功!");

                    wl_adapter= new Local_Adapter(context,mediaItems);
                    lv.setAdapter(wl_adapter);
                    tv_nomedia.setVisibility(View.GONE);


                    break;
                case 2:
                    Log.e("clm","没数据!!!");
                    //没有数据
                    //文本显示
                    tv_nomedia.setVisibility(View.VISIBLE);
                    break;
            }



//隐藏 ProgressBar
            pb_loading.setVisibility(View.GONE);

        }
    };

    public Network(Context context) {
        super(context);
    }

    @Override
    public void initData() {
        super.initData();
        getDataFromNetwork();
    }

    @Override
    protected View initView() {
        View view=View.inflate(context, R.layout.activity_network_page,null);
        lv = (ListView) view.findViewById(R.id.listView);
        tv_nomedia = (TextView) view.findViewById(R.id.tv_nomedia);
        pb_loading = (ProgressBar) view.findViewById(R.id.pb_loading);
        lv.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView adapterView, View view, int i, long l) {
                Intent intent=new Intent(Intent.ACTION_VIEW);
                Uri uri=Uri.parse(mediaItems.get(i).getData());
                intent.setDataAndType(uri,"video/*");

                context.startActivity(intent);
            }

        });

        return view;
    }
    private ArrayList StrToList(String str) throws Exception {

        JSONObject jsobj=new JSONObject(str);
        JSONArray jsonArray= jsobj.getJSONArray("trailers");
        Log.e("clm","StrToList!!!!"+jsonArray);


        ArrayList list=new ArrayList();


        for (int i = 0; i; i++){
            Log.e("clm","循环写入Json===StrToList");
            JSONObject jsonObject=jsonArray.getJSONObject(i);

            String coverImg=jsonObject.getString("coverImg");
            String hightUrl=jsonObject.getString("hightUrl");
            String movieName=jsonObject.getString("movieName");
            String videoTitle=jsonObject.getString("videoTitle");

            Mediaitem mediaitem=new Mediaitem(coverImg,hightUrl,movieName,videoTitle);
            list.add(mediaitem);

        }




        return list;
    }
    private String getHttpStr() throws Exception {
        String path="http://api.m.mtime.cn/PageSubArea/TrailerList.api";
        Log.e("clm","这是->getHttpStr");
//        创建连接
        URL url=new URL(path);
//        获得连接
        HttpURLConnection connet= (HttpURLConnection) url.openConnection();
//         设置连接等待时间
        connet.setConnectTimeout(5000);
        connet.setReadTimeout(5000);
//          获取响应编码
        Log.e("clm","开始得到网络数据connect:"+connet);
        int respCode=connet.getResponseCode();
        Log.e("clm","开始得到网络数据2");
        if(respCode==200){
//            获得输入流
            InputStream input=connet.getInputStream();
//            创建字符输出流
            ByteArrayOutputStream byteout=new ByteArrayOutputStream();
//            创建字符缓冲区
            byte[]  bytes=new byte[1024];

            int lean=-1;
            while ((lean=input.read(bytes))!=-1){
                byteout.write(bytes,0,lean);
                Log.e("clm","写入ing");

            }

//            释放资源
            byteout.close();
            input.close();
            connet.disconnect();

//            字节转换字符串
            json=byteout.toString();

            Log.e("clm","Json:"+json);
            return  json;



        }else{
            Log.e("clm","奇怪的地方");
        }





        return null;
    }
    private void getDataFromNetwork() {
        new Thread(){
            @Override
            public void run() {

                try {
                    Log.e("clm","获取字符串");
                    String str=  getHttpStr();
                    mediaItems =StrToList(str);
                    Log.e("clm","获得网络字符串 ->"+mediaItems);



                    handler.sendEmptyMessage(1);
                } catch (Exception e) {
                    Log.e("clm","WL子线程异常");
                    e.printStackTrace();
                    handler.sendEmptyMessage(2);
                }







            }
        }.start();
    }
}

运行后,网络页面大概这样

Android视频播放器_第1张图片


点击能够播放,基本可以确定拿到了网络数据

接着,我们编写一个名为Network的适配器,并为他创建一个布局文件,特别注意,这里要用到网络图片,因此要用到一个工具类,解析网络图片,

package com.example.administrator.my_player.Utils;

import java.io.FileOutputStream;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Bitmap.CompressFormat;
import android.graphics.BitmapFactory;
import android.os.AsyncTask;
import android.widget.ImageView;

/**
 * 用于加载图片并显示的类
 * @author C_Fran
 *
 */
/*
   String iamgePath = http://192.168.10.165:8080//L05_Web/images/f10.jpg和ImageView对象
   1). 根据url从一级缓存中取对应的bitmap对象
      如果有, 显示(结束)
      如果没有, 进入2)
   2). 从二级缓存中查找: 得到文件名并在sd卡的缓存目录下加载对应的图片得到Bitmap对象
      如果有: 显示, 缓存到一级缓存中(结束)
      如果没有, 进入3)
   3). 显示代表提示正在加载的图片, 启动分线程联网请求得到Bitmap对象
         如果没有: 显示提示错误的图片(结束)
         如果有:
            显示
            缓存到一级缓存
            缓存到二级缓存
 */
public class ImageLoader {

    private Context context;
    private int loadingImageRes;
    private int errorImageRes;

    public ImageLoader(Context context, int loadingImageRes, int errorImageRes) {
        super();
        this.context = context;
        this.loadingImageRes = loadingImageRes;
        this.errorImageRes = errorImageRes;
    }

    //用于缓存bitmap的容器对象
    private Map, Bitmap> cacheMap = new HashMap, Bitmap>();

    /**
     * 加载图片并显示
     * @param imagePath
     * @param imageView
     */
    public void loadImage(String imagePath, ImageView imageView) {

        //将需要显示的图片url保存到视图上
        imageView.setTag(imagePath);

      /*
       1). 根据url从一级缓存中取对应的bitmap对象
         如果有, 显示(结束)
         如果没有, 进入2)
       */
        Bitmap bitmap = getFromFirstCache(imagePath);
        if(bitmap!=null) {
            imageView.setImageBitmap(bitmap);
            return;
        }
      /*
      2). 从二级缓存中查找: 得到文件名并在sd卡的缓存目录下加载对应的图片得到Bitmap对象
            如果有: 显示, 缓存到一级缓存中(结束)
            如果没有, 进入3)

         /storage/sdcard/Android/data/packageName/files/图片文件名(xxx.jpg)
       */
        bitmap = getFromSecondCache(imagePath);
        if(bitmap!=null) {
            imageView.setImageBitmap(bitmap);
            cacheMap.put(imagePath, bitmap);
            return;
        }

      /*
       3). 显示代表提示正在加载的图片, 启动分线程联网请求得到Bitmap对象
         如果没有: 显示提示错误的图片(结束)
         如果有:
            缓存到一级缓存(分线程)
            缓存到二级缓存(分线程)
            显示(主线程)

       */

        loadBitmapFromThirdCache(imagePath, imageView);
    }

    /**
     * 根据图片url从三级缓存中取对应的bitmap对象并显示
     * @param imagePath
     * @param imageView
     * AsyncTask
     * loadBitmapFromThirdCache("../b.jpg", imageView)
     * loadBitmapFromThirdCache("../f.jpg", imageView)--->imageView.setTag("../f.jpg")
     */
    private void loadBitmapFromThirdCache(final String imagePath, final ImageView imageView) {
        new AsyncTask, Void, Bitmap>() {
            protected void onPreExecute() {
                imageView.setImageResource(loadingImageRes);
            }

            //联网请求得到bitmap对象
            @Override
            protected Bitmap doInBackground(Void... params) {
                //在分线程执行, 可能需要等待一定时间才会执行
                //在等待的过程中imageView中的tag值就有可能改变了
                //如果改变了, 就不应该再去加载图片(此图片此时不需要显示)

                Bitmap bitmap = null;
                try {

                    //在准备请求服务器图片之前, 判断是否需要加载
                    String newImagePath = (String) imageView.getTag();
                    if(newImagePath!=imagePath) {//视图已经被复用了
                        return null;
                    }

                    //得到连接
                    URL url = new URL(imagePath);
                    HttpURLConnection connection = (HttpURLConnection) url.openConnection();
                    //设置
                    connection.setConnectTimeout(5000);
                    connection.setReadTimeout(5000);
                    //连接
                    connection.connect();
                    //发请求读取返回的数据并封装为bitmap
                    int responseCode = connection.getResponseCode();
                    if(responseCode==200) {
                        InputStream is = connection.getInputStream();//图片文件流
                        //将is封装为bitmap
                        bitmap = BitmapFactory.decodeStream(is);
                        is.close();

                        if(bitmap!=null) {
                            //缓存到一级缓存(分线程)
                            cacheMap.put(imagePath, bitmap);
                            //缓存到二级缓存(分线程)
                            // /storage/sdcard/Android/data/packageName/files/
                            String filesPath = context.getExternalFilesDir(null).getAbsolutePath();
                            // http://192.168.10.165:8080//L05_Web/images/f10.jpg
                            String fileName = imagePath.substring(imagePath.lastIndexOf("/")+1);//  f10.jpg
                            String filePath = filesPath+"/"+fileName;
                            bitmap.compress(CompressFormat.JPEG, 100, new FileOutputStream(filePath));
                        }
                    }
                    connection.disconnect();
                } catch (Exception e) {
                    e.printStackTrace();
                }


                return bitmap;
            }

            protected void onPostExecute(Bitmap bitmap) {//从联网请求图片到得到图片对象需要一定的时间, 视图可能被复用了,不需要显示
                //在主线程准备显示图片之前, 需要判断是否需要显示
                String newImagePath = (String) imageView.getTag();
                if(newImagePath!=imagePath) {//视图已经被复用了
                    return;
                }

                //如果没有: 显示提示错误的图片(结束)
                if(bitmap==null) {
                    imageView.setImageResource(errorImageRes);
                } else {//如果有, 显示
                    imageView.setImageBitmap(bitmap);
                }
            }
        }.execute();
    }

    /**
     * 根据图片url从二级缓存中取对应的bitmap对象
     * @param imagePath
     * @return
     */
    private Bitmap getFromSecondCache(String imagePath) {

        // /storage/sdcard/Android/data/packageName/files/
        String filesPath = context.getExternalFilesDir(null).getAbsolutePath();
        // http://192.168.10.165:8080//L05_Web/images/f10.jpg
        String fileName = imagePath.substring(imagePath.lastIndexOf("/")+1);//  f10.jpg
        String filePath = filesPath+"/"+fileName;

        return BitmapFactory.decodeFile(filePath);
    }

    /**
     * 根据图片url从一级缓存中取对应的bitmap对象
     * @param imagePath
     * @return
     */
    private Bitmap getFromFirstCache(String imagePath) {
        return cacheMap.get(imagePath);
    }
}

然后到布局文件

xml version="1.0" encoding="utf-8"?>
xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:paddingTop="10dp">
            android:padding="2dp"
        android:scaleType="fitXY"
        android:layout_width="80dp"
        android:layout_height="80dp"
        android:id="@+id/imageview"
        android:src="@drawable/ic_launcher"/>
            android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:orientation="vertical">
                    android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:id="@+id/tv1"
            android:text="tv1"/>
                    android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:id="@+id/tv2"
            android:text="tv2"/>

    

            android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        >
                    android:layout_width="wrap_content"
            android:layout_height="60dp"
            >
                    android:layout_width="wrap_content"
            android:layout_height="0dp"
            android:layout_weight="1"
            android:id="@+id/tv3"
            android:text=" "/>

    





接着是适配器,同样创建一个静态的内部类,用来实现单例模式

package com.example.administrator.my_player.Adapter;

import android.content.Context;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.TextView;

import com.example.administrator.my_player.Bean.Mediaitem;
import com.example.administrator.my_player.R;
import com.example.administrator.my_player.Utils.ImageLoader;
import com.example.administrator.my_player.Utils.Utils;

import java.util.ArrayList;

public class Network_Adapter extends BaseAdapter {
    private Context context;
    private ArrayList list;
    private Mediaitem wlBean;
    private ImageLoader imageLoader;
    private Utils utils;
    public Network_Adapter(Context context, ArrayList list) {
        this.context = context;
        this.list = list;
        utils=new Utils();
        imageLoader=new ImageLoader(context, R.drawable.loading, R.drawable.error);
    }
    @Override
    public int getCount() {
        return list.size();
    }

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

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

    @Override
    public View getView(int i, View view, ViewGroup viewGroup) {
        Network_View network_view;
        if (view==null){
            view=View.inflate(context,R.layout.network_adapter,null);
            network_view=new Network_View();
            network_view.img= (ImageView) view.findViewById(R.id.imageview);
            network_view.tv1= (TextView) view.findViewById(R.id.tv1);
            network_view.tv2= (TextView) view.findViewById(R.id.tv2);
            network_view.tv3= (TextView) view.findViewById(R.id.tv3);
            view.setTag(network_view);
        }else {
            network_view= (Network_View) view.getTag();
        }

        wlBean=list.get(i);

        String name=wlBean.getName()+"";
        network_view.tv1.setText(name);
        network_view.tv2.setText(wlBean.getDesc());

        imageLoader.loadImage(wlBean.getImageUrl(),network_view.img);
        Log.e("clm","Network图片获取成功!");
        return view;
    }
    private static class Network_View {
        ImageView img;
        TextView tv1;
        TextView tv2;
        TextView tv3;

    }
}


然后回到我们的Network的handler的绑定适配器里更换适配器

network_adapter= new Network_Adapter(context,mediaItems);
lv.setAdapter(network_adapter);

然后再次运行

Android视频播放器_第2张图片


功能已基本实现。可以自己扩展,我自己完成了自定义播放器,实现了SeekBar拖拉进度,音量,触摸屏幕左边亮度,右边音量,左右滑屏拖动进度等。而且实现了网速实时显示。历史记录,推荐页的轮播等。由于不想写了,就到此为止吧,附上我的源代码,那时候是写着玩的,所以并不规范,上面的是我重新整理然后再写的。都附上吧!其实还有个推荐页,是解析豆瓣TOP250的API的,这里就不附上了,大体上一样不过采用一些JAVA的网页爬取。

上面的整理的代码:链接:https://pan.baidu.com/s/1USDF1AFbsQNicnjJ8ZbfFg 密码:vyui

前段时间写着玩的代码:

你可能感兴趣的:(Android视频播放器)