Android应用开发:主界面、视频列表与播放界面设计与实现详解
1、界面分析

三个界面:主界面,视频列表界面,视频播放界面,如下图所示:
2、实现思路
(1)主界面设计
很简单,有一个背景以及一个控件。接着为这个控件设置点击事件,之后就会跳转到视频列表界面。
activity_main.xml界面
MainActivity.java类
公共类 MainActivity 是 AppCompatActivity 的子类。
private TextView textView;
@Override
在创建活动时会调用该方法,在这个方法中可以进行一些初始化操作,比如获取布局资源、设置视图等,这些操作对于构建一个完整的活动界面是很重要的。
super 调用了 onCreate 方法并传入了 savedInstanceState 参数。
设置内容视图为 R.layout.activity_main ; 让内容视图呈现为 R.layout.activity_main ; 将内容视图设定为 R.layout.activity_main 。
通过 findViewById(R.id.btlogin) 找到了一个 TextView 并赋值给 textView 。
这个监听器会在 textView 被点击时触发相应的操作。
@Override
公共类中的方法 onClick 接收一个 View 类型的参数 view 并进行相关操作。 该方法用于处理点击事件。 它会根据点击的具体情况执行相应的逻辑。 例如,可能会触发不同的界面切换、数据更新或其他操作。 这个方法在用户与界面进行交互时起到关键作用。 它是实现界面响应点击功能的重要部分。
Intent 被创建出来,其目的是从 MainActivity.this 这个上下文跳转到 MovieActivity.class 这个类所对应的活动;创建 Intent 的动作是通过 new Intent 来实现的。
startActivity(intent);
}
});
}
}
(2)视频列表界面
每次跳转都需构建一个新的 Activity。首先构建一个 MovieActivity,接着在对应的 xml 文件中设置列表。因为此界面所使用的控件是 RecycleView,且此控件属于新增的控件,所以需要手动添加依赖项。
在 app/build.gradle 文件里添加依赖项,在闭包 dependencies 中添加如下这些语句。
实现 'com.android.support:recyclerview-v7:33.0.0'
需注意添加的版本需与文件中上面代码所显示的版本保持一致,否则会报红,并且项目也无法运行。
activity_movie.xml文件
列表框架呈现的样子如下,因此通过看图便能知晓我们还需针对此界面列表里的每一行展开具体的设计。
创建一个名为 movie_item_layout.ml 的 xml 文件,具体内容如下:
我在写的时候犯了个小错,在这个界面又添加了背景图。这导致列表里的照片无论怎样设计,每一行的数据都显示在这张背景图上,而另一个数据则显示在另一张图上,就如同分页一样,非常不美观。所以,如果在 activity_movie.xml 文件中设置了背景图,就无需在这个 xml 文件下再次设置了,此界面是上一个界面的子布局。
界面设置完成后,我们来分析一下。视频列表界面具有哪些属性呢?有视频名,还有视频地址。由于此次设计使用的照片是统一的,所以就无需将其写在属性里。
所以在这里建立实体类Movie.java
public class Movie {
private String moviename;
private String movieuri;
公共的 Movie(字符串 moviename,字符串 movieuri){
this.moviename=moviename;
this.movieuri=movieuri;
}
public String getMoviename(){
return moviename;
}
public String getMovieuri(){
return movieuri;
}
}
接着需要针对 RecyclerView 去自定义一个适配器,因此要创建一个适配器类,其代码如下:
MovieAdapter.java
公共类 MovieAdapter 继承自 RecyclerView.Adapter {
List mymovieList;
公共类 ViewHolder 继承自 RecyclerView.ViewHolder ;
View movieview;
TextView moviename;
公共的 ViewHolder(@NonNull View 视图){
super(view);
获取名为 moviename 的元素,是通过 itemView.findViewById(R.id.moviename) 来实现的。
movieview=view;
}
}
//利用适配器的构造函数传入要展示的数据
public MovieAdapter(List mymovieList){
this.mymovieList=mymovieList;
}
创建实例,加载每一行的布局,创建一个 ViewHolder 实例,把布局传入构造函数,最后返回实例
在 public 方法 onCreateViewHolder 中,它接收两个参数,一个是 @NonNull 的 ViewGroup 类型的 parent,另一个是 int 类型的 viewType,该方法用于创建 MovieAdapter 的 ViewHolder。
LayoutInflater 从 parent 的上下文获取。然后通过该 LayoutInflater 实例化一个视图 view,其布局文件为 R.layout.movie_item_layout,并且将该视图添加到 parent 中时设置为 false。即 View view 等于通过上述方式获取并初始化的视图。
创建了一个名为 holder 的 ViewHolder 实例,这个实例是通过传入一个名为 view 的参数来初始化的。
//单击任意视频跳转到播放界面
holder 的 movieview 设置了点击事件监听器,新创建了一个 View.OnClickListener 的实例并将其作为参数传递给 movieview 的 setOnClickListener 方法。
@Override
public void onClick(View view) {
//获取位置
获取到的适配器位置被存储在一个名为 position 的整型变量中,这个变量是通过 holder.getAdapterPosition() 方法获取到的。
获取指定位置的电影,将其赋值给变量 Movie,即 Movie 等于 mymovieList 中该位置的元素。
获取电影的名称并将其赋值给字符串 mymoviename,即 mymoviename 等于 movie.getMoviename()。
获取电影的视频地址,将其赋值给字符串 mymovievideo,即 mymovievideo 等于 movie.getMovieuri()。
//获取位置后跳转
创建了一个 Intent 对象,这个 Intent 对象的上下文是 view 所对应的上下文,目标活动类是 PlayActivity 类。
//然后根据位置传递信息
intent 把 "my" 这个键值对与 mymoviename 进行关联并添加到其中。
intent 把 "movieurl" 这个键值对进行了设置,设置的值为 mymovievideo 。
获取上下文对象并启动活动。获取上下文对象可以通过 view.getContext()来实现,然后使用该上下文对象调用 startActivity(intent)方法来启动指定的意图。
}
});
return holder;
}
通过位置获取 recyclerview 中的当前实例,接着对该实例进行赋值,最后将电影名和视频显示在控件上。
公共的 void 方法 onBindViewHolder,传入一个非空的 MovieAdapter.ViewHolder 类型的 holder 和一个整数类型的 position 参数。
从 mymovieList 中获取到位置为 position 的电影,将其赋值给 Movie 类型的变量 movie。
holder 的 moviename 被设定为 movie 的 moviename 。
}
public int getItemCount(){
return mymovieList.size();
}
}
MovieAdapter继承了 RecyclerView.Adapter 类,并且把泛型指定为 MovieAdapter.ViewHolder。因为它继承了 RecyclerView.Adapter 类,所以需要对 onCreateViewHolder()方法、onBindViewHolder 方法以及 getItemCount()方法进行重写。
要读取 SD 卡以及访问网络上的视频资源,所以需要在 androidmanifest.xml 文件中设置读取权限,具体如下:
设置完之后可能无法获取权限。我在编写时,经常读取不到数据,后来查阅资料,才得以解决。新的 AS 软件不仅要添加权限,还需单独设置并建立一个权限类,在读取数据时调用该权限类即可。具体如下:
PermissionUtils.java类
公共类 PermissionUtils 。
// Storage Permissions
静态私有常量 REQUEST_EXTERNAL_STORAGE 的值为 1 。
包含 "android.permission.WRITE_EXTERNAL_STORAGE"。
Manifest 的权限 READ_EXTERNAL_STORAGE 。
Manifest 的权限 WRITE_EXTERNAL_STORAGE 。
公共静态 void 验证存储权限(Activity 活动)。
检查我们是否拥有写入权限。
通过 ActivityCompat 来检查当前活动的权限,将其赋值给变量 permission ,即 permission = ActivityCompat.checkSelfPermission(activity,
Manifest 的 permission 为 WRITE_EXTERNAL_STORAGE 。
如果 permission 不等于 PackageManager.PERMISSION_GRANTED ,那么
我们没有获得许可,所以需要提示用户。
ActivityCompat发起权限请求,其请求的对象是 activity,请求的权限是 PERMISSIONS_STORAGE。
REQUEST_EXTERNAL_STORAGE);
}
}
}
此时,基本设置已完成。接下来对 MovieActivity.java 进行操控。此界面用于显示列表界面的数据,具体情况如下:
MovieActivity.java
MovieActivity 是一个继承自 AppCompatActivity 的类。
RecyclerView recyclerView;
List movieList;
MovieAdapter movieAdapter;
静态私有常量字符串 TAG 的值为 "MovieActivity"。
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
将布局设置为 R.layout.activity_movie 。
它是从 findViewById 方法中获取到的对应 id 为 recyclerview 的视图组件。
initData();
}
public void initData(){
//建立动态数组存放数据
movieList=new ArrayList<>();
//获取网络视频
Movie 是一个类,这里创建了一个名为 firstmovie 的实例,该实例的构造函数传入了两个参数,一个是字符串"明星大侦探",另一个是字符串"http://vfx.mtime.cn/Video/2019/03/21/mp4/190321153853126488.mp4"。
movieList.add(firstmovie);
Movie 名为“哈哈哈哈哈”的新 Movie,其链接为“https://www.dglydz.com/mov-hahahahahadierji.html”。
movieList.add(secondmovie);
//获取本工程中的视频
Movie thirdmovie 被创建,创建时传入的参数为 "等到苦尽甘来时,待我给你讲来时的路" 以及 "android.resource://" 与获取的包名加上 "/" 再加上 R.raw.read 。
movieList.add(thirdmovie);
Movie forthmovie 被创建,其名称为“阳光开朗孔乙己”,创建时所使用的资源路径为“android.resource://”加上当前应用的包名再加上“/”以及 R.raw.why 所对应的资源。
movieList.add(forthmovie);
//获取模拟器中的视频
Movie 名为“我会等”,其路径为“file:///storage/emulated/0/Pictures/waitting.mp4”,创建了一个新的 Movie 对象,名为 fifthmovie。
movieList.add(fifthmovie);
Movie sixthmovie 被创建,其名称为“稻香”,视频文件路径为“file:///storage/emulated/0/Pictures/jay.mp4”。
movieList.add(sixthmovie);
//将视频显示在控件上
movieAdapter 被创建出来,它所关联的是 movieList 这个电影列表。
创建一个 StaggeredGridLayoutManager 布局管理器,将其初始化为 1 列且垂直排列。即先创建一个 StaggeredGridLayoutManager 对象,然后设置列数为 1,排列方向为垂直方向。
layoutManager 被应用于 recyclerView 作为其布局管理器 。
recyclerView 被设置为使用 movieAdapter 作为适配器。
}
}
(3)播放界面
新建一个 Activity,这个界面的作用是获取从列表传递过来的视频名以及视频地址,接着进行播放,具体的代码呈现如下:
activity_play.xml
PlayActivity.java
公共类 PlayActivity 是 AppCompatActivity 的子类。
private TextView tvvedioname;
private VideoView videoView;
//媒体控制器
创建了一个名为 mediaController 的私有 MediaController 对象。
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
设置内容视图为 R.layout.activity_play 。
通过 findViewById 方法找到 id 为 R.id.tvmovename 的视图,并将其赋值给 tvvedioname 变量。
通过 findViewById 方法找到了 id 为 R.id.vvmovie 的视图并赋值给 videoView 。
创建了一个名为 mediaController 的 MediaController 对象,并且这个对象关联到了当前的上下文 this 。
initData();
验证存储权限(this)。
}
public void initData(){
//获取从音乐列表传过来的视频名称和地址
获取到的额外数据 "my" 通过 getIntent() 方法转换为字符串赋值给了 videoname 这个变量。
获取 Intent 中的字符串额外数据,该数据名为 "movieurl",并将其赋值给字符串 videouri 。
视频路径 += "/jay.mp4";
Log.i("PlayActivity", "视频的 URL 为" + videourl);
//将视频名称显示在文本框中,将视频地址关联到播放器中
tvvedioname 让 videoname 成为其显示的文本 。
videoView 把视频路径设置为 videouri 。
videoView 把视频路径设置为 videourl 。
//将视频播放器和媒体控制柄关联起来
videoView 被设置了媒体控制器为 mediaController 。
//媒体控制柄和视频播放器关联起来
媒体控制器设置了视频视图的媒体播放器。
//启动视频播放器播放视频
videoView.start();
}
}
网络路径的视频加载如下所示,文件夹内路径的视频加载如下所示,模拟器里路径的视频加载如下所示,具体的知识点不做描述,基本代码上都有备注。