前言:
正在做一个资讯类app,打算一边做一边整理,供自己学习与巩固。用到的知识复杂度不高,仅适于新手。经验不多,如果写出来的代码有不好的地方欢迎讨论。
以往的内容
第四章 电影模块
本章内容最终效果:

知识点:
RxJava,RecyclerView,WebView
学习目标:
1、使用RecyclerView显示电影列表数据。
2、使用Glide加载图片。
3、WebView显示网页。
电影模块电影列表内容包括正在热映、豆瓣Top250。除了电影模块的展示,本章内容还将第二章的网络请求进行优化,运用RxJava来体会事件流的链式调用。
项目实战:
注意
本章用到的drawable资源、values资源皆存放在百度网盘
(请将values文件夹中的style.xml或color.xml更新一致后再运行,如有后续更新自行修改)
1.1 项目结构

注意:电影模块获取数据与新闻模块相同,MVP的部分复制修改新闻模块的就行,本章将不在重复展示MVP部分的内容。完成了第二章的任务内容,这部分应该就没有问题。
需导入的库:
导入了retrofit的Rxjava扩展和RxAndroid。
compile 'com.squareup.retrofit2:adapter-rxjava:2.1.0'
compile 'io.reactivex:rxandroid:1.2.0'

用到的Api:
https://api.douban.com/v2/movie/in_theaters
1.1 加入RxJava
在第二章的内容里,我们用retrofit2的方法获取网络数据,今天我们来结合另一个网上非常火热的库 RxJava。(参考 RxJava+retrofit2的初尝试)
首先打开RetrofitHelper.java,在Retrofit的声明里加上CallAdapterFactory

然后将get方法的返回对象改为Observable,

注意:import的是rx的Observable,不要弄成database的了

因为此时的返回对象不再为Call对象,所以我们到RetrofitService里把Call改为Observable:

然后到Model层修改Observable订阅Subscriber的代码:
NewsModel.java

其他Model层也照上图修改就行。
至此,RxJava的植入就完成了,可以运行下程序试试是否能获取到数据。
2.1 items_movie_on及适配器
电影正在上映的显示需要用RecyclerView,所以先完成每个电影item的代码。
新建一个布局文件,命名为items_movie_on。
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/rl_movie_on"
android:layout_margin="5dp">
<ImageView
android:layout_width="100dp"
android:layout_height="145dp"
android:layout_marginRight="12dp"
android:layout_alignParentLeft="true"
android:id="@+id/iv_movie_on"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_toRightOf="@+id/iv_movie_on"
android:id="@+id/ll_movie"
android:layout_gravity="left">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/tv_movie_on_title"
android:layout_marginBottom="5dp"
android:textSize="18dp"
android:textColor="@color/text_common"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/tv_movie_on_directors"
android:textSize="15dp"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/tv_movie_on_casts"
android:textSize="15dp"
android:maxLines="2"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/tv_movie_on_genres"
android:textSize="15dp"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/tv_movie_on_rating"
android:textSize="15dp"/>
</LinearLayout>
<View
android:layout_width="match_parent"
android:layout_height="2dp"
android:layout_marginTop="10dp"
android:layout_alignBottom="@id/iv_movie_on"
android:layout_toRightOf="@id/iv_movie_on"
android:background="@color/colorLineDeep"/>
</RelativeLayout>
然后为我们的item_movie_on写上适配器代码。
新建一个java文件,命名为ItemMovieOnAdapter。
public class ItemMovieOnAdapter extends RecyclerView.Adapter<ItemMovieOnAdapter.ViewHolder> {
private List<MoviesBean.SubjectsBean> objects = new ArrayList<MoviesBean.SubjectsBean>();
private Context context;
public ItemMovieOnAdapter(Context context) {
this.context = context;
}
public void setData(List<MoviesBean.SubjectsBean> objects){
this.objects = objects;
}
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.items_movie_on, parent, false);
return new ViewHolder(view);
}
@Override
public void onBindViewHolder(ViewHolder holder, int position) {
final MoviesBean.SubjectsBean bean=objects.get(position);
if (bean==null){
return;
}
Glide.with(context)
.load(bean.getImages().getSmall())
.into(holder.ivMovieOn);
holder.tvMovieOnTitle.setText(bean.getTitle());
String directors="";
for(int i=0;i<bean.getDirectors().size();i++){
if (i==bean.getDirectors().size()-1){
directors+=bean.getDirectors().get(i).getName();
}else{
directors+=bean.getDirectors().get(i).getName()+"/";
}
}
holder.tvMovieOnDirectors.setText("导演:"+directors);
String casts="";
if (bean.getCasts().size()!=0){
for(int i=0;i<bean.getCasts().size();i++){
if (i==bean.getCasts().size()-1){
casts+=bean.getCasts().get(i).getName();
}else{
casts+=bean.getCasts().get(i).getName()+"/";
}
}
holder.tvMovieOnCasts.setText(casts);
}else {
holder.tvMovieOnCasts.setText("主演:佚名");
}
String gen="";
for(int i=0;i<bean.getGenres().size();i++){
if (i==bean.getGenres().size()-1){
gen+=bean.getGenres().get(i);
}else{
gen+=bean.getGenres().get(i)+"/";
}
}
holder.tvMovieOnGenres.setText("类型:"+gen);
holder.tvMovieOnRating.setText("评分:"+bean.getRating().getAverage());
holder.rvMovieOn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(context, ADetailActivity.class);
intent.putExtra("url",bean.getAlt());
intent.putExtra("title", bean.getTitle());
context.startActivity(intent);
}
});
}
@Override
public int getItemCount() {
return objects.size();
}
@Override
public long getItemId(int position) {
return position;
}
protected class ViewHolder extends RecyclerView.ViewHolder {
private ImageView ivMovieOn;
private TextView tvMovieOnTitle;
private TextView tvMovieOnDirectors;
private TextView tvMovieOnCasts;
private TextView tvMovieOnGenres;
private TextView tvMovieOnRating;
private RelativeLayout rvMovieOn;
public ViewHolder(View view) {
super(view);
ivMovieOn = (ImageView) view.findViewById(R.id.iv_movie_on);
tvMovieOnTitle = (TextView) view.findViewById(R.id.tv_movie_on_title);
tvMovieOnDirectors = (TextView) view.findViewById(R.id.tv_movie_on_directors);
tvMovieOnCasts = (TextView) view.findViewById(R.id.tv_movie_on_casts);
tvMovieOnGenres = (TextView) view.findViewById(R.id.tv_movie_on_genres);
tvMovieOnRating = (TextView) view.findViewById(R.id.tv_movie_on_rating);
rvMovieOn = (RelativeLayout) view.findViewById(R.id.rl_movie_on);
}
}
}
2.2 RecycleView
接下来我们让刚才做的item在fragment里显示出来。
首先修改fg_movie的布局代码,加入RecycleView:
fg_movie.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="5dp"
android:orientation="horizontal">
<View
android:layout_width="5dp"
android:layout_height="match_parent"
android:background="@color/colorTheme" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginHorizontal="10dp"
android:text="热映榜"
android:textSize="20sp" />
</LinearLayout>
<android.support.v4.widget.SwipeRefreshLayout
android:id="@+id/srl_movie"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v7.widget.RecyclerView
android:id="@+id/rv_movie_on"
android:layout_width="match_parent"
android:layout_height="wrap_content"></android.support.v7.widget.RecyclerView>
</android.support.v4.widget.SwipeRefreshLayout>
</LinearLayout>
</LinearLayout>
然后修改FgMovieFragment的代码:
FgMovieFragment.java
public class FgMovieFragment extends Fragment implements IMoviesView {
private MoviesPresenter moviesPresenter;
private RecyclerView rv_movie_on;
private SwipeRefreshLayout srl_movie;
private ItemMovieOnAdapter movieOnAdapter;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
return inflater.inflate(R.layout.fg_movie, null);
}
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
moviesPresenter = new MoviesPresenter(this);
srl_movie = view.findViewById(R.id.srl_movie);
rv_movie_on = view.findViewById(R.id.rv_movie_on);
movieOnAdapter = new ItemMovieOnAdapter(getActivity());
srl_movie.setColorSchemeColors(Color.parseColor("#ffce3d3a"));
moviesPresenter.loadNews("in_theaters");
srl_movie.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
@Override
public void onRefresh() {
moviesPresenter.loadNews("in_theaters");
}
});
}
@Override
public void showNews(MoviesBean moviesBean) {
movieOnAdapter.setData(moviesBean.getSubjects());
rv_movie_on.setLayoutManager(new LinearLayoutManager(getActivity()));
rv_movie_on.setAdapter(movieOnAdapter);
}
@Override
public void hideDialog() {
srl_movie.setRefreshing(false);
}
@Override
public void showDialog() {
srl_movie.setRefreshing(true);
}
@Override
public void showErrorMsg(Throwable throwable) {
Toast.makeText(getContext(), "加载出错:"+throwable.getMessage(), Toast.LENGTH_SHORT).show();
}
}
只要解决了网络请求的问题,数据的展示并没有什么新的东西,甚至跟上一章的内容很相似(电影详情也用的是上一章的WebView)。
效果:

任务
在电影模块顶端加上豆瓣Top250,要求横向滑动,并且在上滑时会有折叠隐藏的效果。
Api:
https://api.douban.com/v2/movie/top250
任务效果:

项目源码:https://github.com/Huigesi/IdleReaderDemo
上一章:
第三章 新闻模块
下一章:
第五章 视频模块
网友评论