1、界面分析

        三个界面:主界面,视频列表界面,视频播放界面,如下图所示:

android studio 音乐播放 androidstudio音乐播放器完整教程_xml

android studio 音乐播放 androidstudio音乐播放器完整教程_android studio 音乐播放_02

android studio 音乐播放 androidstudio音乐播放器完整教程_android studio_03

 2、实现思路

        (1)主界面设计

           很简单,就一个背景和一个控件,然后为控件设置点击事件,然后跳转到视频列表界面

   activity_main.xml界面

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity"
    android:background="@drawable/action"
    android:orientation="vertical">
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="进入视频列表"
        android:textColor="@color/white"
        android:textStyle="bold"
        android:textSize="30sp"
        android:layout_marginTop="50dp"
        android:layout_gravity="center"
        android:id="@+id/btlogin"/>

</LinearLayout>

 MainActivity.java类

public class MainActivity extends AppCompatActivity {
    private TextView textView;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        textView=(TextView) findViewById(R.id.btlogin);
        textView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Intent intent=new Intent(MainActivity.this,MovieActivity.class);
                startActivity(intent);
            }
        });
    }
}

         (2)视频列表界面

        每次跳转都需要建立一个新的Activity,所以先建立一个MovieActivity,然后在对应的xml文件设置列表,因为此界面用到的控件是RecycleView,此控件属于新增的控件,因此需要手动添加依赖项。

        在app/build.gradle文件中添加依赖项,在闭包dependencies中添加如下语句

implementation 'com.android.support:recyclerview-v7:33.0.0'

        注意添加的版本要和此文件中上面代码中显示的版本要一致,否则就会报红,且项目也运行不了。 

android studio 音乐播放 androidstudio音乐播放器完整教程_音视频_04

 activity_movie.xml文件

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MovieActivity"
    android:orientation="vertical"
    android:background="@drawable/back">
    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="视频列表"
        android:textSize="30sp"
        android:gravity="center"
        android:textStyle="bold"
        android:background="@color/black"
        android:textColor="@color/white"/>
    <androidx.recyclerview.widget.RecyclerView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:id="@+id/recyclerview"/>
</LinearLayout>

         列表框架就如下所示,所以看图就可以知道我们还需要对此界面列表中的每一行进行具体的设计

android studio 音乐播放 androidstudio音乐播放器完整教程_音视频_05

         新建一个xml文件,名为movie_item_layout.ml,具体如下所示:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="horizontal" >
        <ImageView
            android:layout_width="80dp"
            android:layout_height="80dp"
            android:background="@drawable/image"
            android:id="@+id/movievideo"/>
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:id="@+id/moviename"
            android:text="dianyinm"
            android:textSize="25sp"
            android:layout_marginLeft="10dp"
            android:layout_gravity="center_vertical"/>
</LinearLayout>

        我自己在写的时候,犯了一个小错误,就是在此界面我又添加了背景图,然后就导致了列表里的照片无论怎么设计,每一行的数据都显示在此背景图上,然后另一个数据会显示在另一张图上,就好像分页一样,及其不美观,所以如果在 activity_movie.xml文件中设置了背景图的话,就不用在此xml文件下再次设置了,这个界面是上一个界面的子布局。

        

        界面设置完之后,我们分析以下,视频列表界面有哪些属性呢,有视频名,视频地址,因为此次设计使用的照片都是统一的,所以就不用写在属性里了。

        所以在这里建立实体类Movie.java

public class Movie {
    private String moviename;
    private String movieuri;
    public Movie(String moviename,String movieuri){
        this.moviename=moviename;
        this.movieuri=movieuri;
    }
    public String getMoviename(){
        return moviename;
    }
    public String getMovieuri(){
        return movieuri;
    }
}

        然后就是需要为RecyclerView自定义一个适配器,所以建立一个适配器类,代码如下:

MovieAdapter.java

public class MovieAdapter extends RecyclerView.Adapter<MovieAdapter.ViewHolder> {
    List<Movie> mymovieList;
    public class ViewHolder extends RecyclerView.ViewHolder{
        View movieview;
        TextView moviename;
        public ViewHolder(@NonNull View view){
            super(view);
            moviename=itemView.findViewById(R.id.moviename);
            movieview=view;
        }
    }
    //利用适配器的构造函数传入要展示的数据
    public MovieAdapter(List<Movie> mymovieList){
        this.mymovieList=mymovieList;
    }
    //创建实例,把每一行的布局加载进来,创建一个ViewHolder实例,将布局传入到构造函数中,最后将实例返回
    public MovieAdapter.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType){
        View view= LayoutInflater.from(parent.getContext()).inflate(R.layout.movie_item_layout,parent,false);
        final ViewHolder holder=new ViewHolder(view);
        //单击任意视频跳转到播放界面
        holder.movieview.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                //获取位置
                int position=holder.getAdapterPosition();
                Movie movie=mymovieList.get(position);
                String mymoviename=movie.getMoviename();
                String mymovievideo=movie.getMovieuri();
                //获取位置后跳转
                Intent intent=new Intent(view.getContext(),PlayActivity.class);
                //然后根据位置传递信息
                intent.putExtra("my",mymoviename);
                intent.putExtra("movieurl",mymovievideo);
                view.getContext().startActivity(intent);
            }
        });
        return holder;
    }
    //对recyclerview中子项目进行赋值,通过位置得到当前的实例,然后电影名和视频显示在控件上
    public void onBindViewHolder(@NonNull MovieAdapter.ViewHolder holder,int position){
        Movie movie=mymovieList.get(position);
        holder.moviename.setText(movie.getMoviename());
    }
    public int getItemCount(){
        return mymovieList.size();
    }
}

        MovieAdapter继承RecyclerView.Adapter,并将泛型指定为MovieAdapter.ViewHolder,因为继承了RecyclerView.Adapter类,所以必须对onCreateViewHolder()、onBindViewHolder、getItemCount()这3个方法重写。

        因为要读取SD卡和访问网络上的视频资源,所以要在androidmanifest.xml文件中设置读取权限,如下所示:

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
    <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"
        tools:ignore="ProtectedPermissions"/>
    <uses-permission android:name="android.permission.INTERNET"/>

        设置完之后可能还获取不了权限,我当时写的时候总是读取不了数据,然后查了资料,才终于弄出来,应该是新的AS软件不仅仅要添加权限,还有单独设置建立一个权限类,然后在读取数据时调用它就可以了。具体如下所示

PermissionUtils.java类

public class PermissionUtils {
    // Storage Permissions
    private static final int REQUEST_EXTERNAL_STORAGE = 1;
    private static String[] PERMISSIONS_STORAGE = {
            Manifest.permission.READ_EXTERNAL_STORAGE,
            Manifest.permission.WRITE_EXTERNAL_STORAGE};
    public static void verifyStoragePermissions(Activity activity) {
        // Check if we have write permission
        int permission = ActivityCompat.checkSelfPermission(activity,
                Manifest.permission.WRITE_EXTERNAL_STORAGE);

        if (permission != PackageManager.PERMISSION_GRANTED) {
            // We don't have permission so prompt the user
            ActivityCompat.requestPermissions(activity, PERMISSIONS_STORAGE,
                    REQUEST_EXTERNAL_STORAGE);
        }
    }
}

        此时,要设置的基本就完成了,接下来就对MovieActivity.java操控了,此界面就是显示列表界面的数据啦,具体如下:

MovieActivity.java

public class MovieActivity extends AppCompatActivity {
    RecyclerView recyclerView;
    List<Movie> movieList;
    MovieAdapter movieAdapter;
    private static final String TAG="MovieActivity";
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_movie);
        recyclerView=(RecyclerView) findViewById(R.id.recyclerview);
        initData();
    }
    public void initData(){
        //建立动态数组存放数据
        movieList=new ArrayList<>();
        //获取网络视频
        Movie firstmovie=new Movie("明星大侦探","http://vfx.mtime.cn/Video/2019/03/21/mp4/190321153853126488.mp4");
        movieList.add(firstmovie);
        Movie secondmovie=new Movie("哈哈哈哈哈","https://www.dglydz.com/mov-hahahahahadierji.html");
        movieList.add(secondmovie);
        //获取本工程中的视频
        Movie thirdmovie=new Movie("等到苦尽甘来时,待我给你讲来时的路","android.resource://"+getPackageName()+"/"+R.raw.read);
        movieList.add(thirdmovie);
        Movie forthmovie=new Movie("阳光开朗孔乙己","android.resource://"+getPackageName()+"/"+R.raw.why);
        movieList.add(forthmovie);
        //获取模拟器中的视频
        Movie fifthmovie=new Movie("我会等","file:///storage/emulated/0/Pictures/waitting.mp4");
        movieList.add(fifthmovie);
        Movie sixthmovie=new Movie("稻香","file:///storage/emulated/0/Pictures/jay.mp4");
        movieList.add(sixthmovie);
        //将视频显示在控件上
        movieAdapter=new MovieAdapter(movieList);
        StaggeredGridLayoutManager layoutManager=new StaggeredGridLayoutManager(1,StaggeredGridLayoutManager.VERTICAL);
        recyclerView.setLayoutManager(layoutManager);
        recyclerView.setAdapter(movieAdapter);
    }
}

        (3)播放界面

        新建Activity此界面就是获取从列表传过来的视频名和视频地址,然后进行播放,具体代码如下:

activity_play.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".PlayActivity"
    android:orientation="vertical"
    android:background="@drawable/back">
    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/tvmovename"
        android:text="name"
        android:layout_marginTop="30dp"
        android:textSize="40sp"
        android:gravity="center"
        android:textStyle="bold"/>
    <VideoView
        android:layout_width="match_parent"
        android:layout_height="400dp"
        android:id="@+id/vvmovie"
        android:layout_marginTop="10dp"/>
</LinearLayout>

PlayActivity.java

public class PlayActivity extends AppCompatActivity {
     private TextView tvvedioname;
     private VideoView videoView;
     //媒体控制器
    private MediaController mediaController;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_play);
        tvvedioname= findViewById(R.id.tvmovename);
        videoView=findViewById(R.id.vvmovie);
        mediaController=new MediaController(this);
        initData();
        verifyStoragePermissions(this);
    }
    public void initData(){
        //获取从音乐列表传过来的视频名称和地址
        String videoname=getIntent().getStringExtra("my");
        String videouri=getIntent().getStringExtra("movieurl");
        //String videourl= Environment.getExternalStorageDirectory().getAbsolutePath()+"/jay.mp4";
        //Log.i("PlayActivity","videourl="+videourl);
        //将视频名称显示在文本框中,将视频地址关联到播放器中
        tvvedioname.setText(videoname);
        videoView.setVideoPath(videouri);
        //videoView.setVideoPath(videourl);
        //将视频播放器和媒体控制柄关联起来
        videoView.setMediaController(mediaController);
        //媒体控制柄和视频播放器关联起来
        mediaController.setMediaPlayer(videoView);
        //启动视频播放器播放视频
        videoView.start();
    }
}

        三个不同路径(网络/文件夹内/模拟器里的视频)的视频的加载如下所示,具体的知识点就不描述了,基本代码上都有备注。 

android studio 音乐播放 androidstudio音乐播放器完整教程_音视频_06

android studio 音乐播放 androidstudio音乐播放器完整教程_android studio 音乐播放_07

android studio 音乐播放 androidstudio音乐播放器完整教程_xml_08