测试豆瓣api,这里调用了豆瓣TOP250,还有正在热映 的api接口。并且结合了Rxjava 还有Rxtrofit具体用法如下
这是封装的一个网络调用的基础类。
1.首先编写一个apiService接口工厂。
public interface MovieApiService { //region @description API 定义相关 String BASEURL = "http://api.douban.com/"; //被观察者 @GET("v2/movie/in_theaters") Observable<TheatersMoive> getTheatersMovie(@Query("city") String city); //http://api.douban.com/v2/movie/subject/1764796 @GET("v2/movie/subject/{id}") Observable<MovieDetailBean> getMovieDetail(@Path("id") int id); //解析到的json字符串 //http://api.douban.com/v2/movie/top250 @GET("v2/movie/top250") Observable<mTop250Bean> getTop250Movie(@Query("start") int start, @Query("count") int count); }
2.写接口
public interface Repository { /** * 获取正在上映 * * @param city * @return */ Observable<List<TheatersMoive.SubjectsEntity>> gettheatersMovie(String city); /** * 获取即将上映的电影 * * @param start * @param count * @return */ // Observable<CommonBean> getCommingSoonMovie(int start, int count); /** * 获取电影详情 * * @param id id * @return */ Observable<MovieDetailBean> getMovieDetail(int id); /** * top 250 电影 * * @param start * @param count * @return */ Observable<mTop250Bean> getTop250Movie(int start, int count); }3.写实现
public class RetrofitRepository implements Repository { private static RetrofitRepository mRetrofitRepository; private Context mContext; private MovieApiService mMovieApiService; private RetrofitRepository(Context mContext) { this.mContext = mContext; mMovieApiService = MovieApiService.Factory.createService(mContext); } public synchronized static RetrofitRepository getInstance(Context context) { if (mRetrofitRepository == null) { mRetrofitRepository = new RetrofitRepository(context); } return mRetrofitRepository; } //观察者模式 @Override //传递一个参数进去了 public Observable<List<TheatersMoive.SubjectsEntity>> gettheatersMovie(String city) { return mMovieApiService.getTheatersMovie(city) .map(new Func1<TheatersMoive, List<TheatersMoive.SubjectsEntity>>() { @Override public List<TheatersMoive.SubjectsEntity> call(TheatersMoive theatersMoive) { return theatersMoive.getSubjects(); } }); } //获取电影详情这里关于rxjava,rxtrofit可以好好学习一下,在这里也码一下。public Observable<MovieDetailBean> getMovieDetail(int id) { return mMovieApiService.getMovieDetail(id);/*map(new Func1<MovieDetailBean, MovieDetailBean>() { @Override public MovieDetailBean call(MovieDetailBean movieDetailBean) { return movieDetailBean; } //获取豆瓣top250public Observable<mTop250Bean> getTop250Movie(int start, int count) { return mMovieApiService.getTop250Movie(start, count); } }
在电影详情页里获取到的最新院线信息的fragment
/** * Observable被观察者 发射源 * Observer 观察者 接收数据 * * Subscriber:“订阅者”,也是接收源Subscriber实现了Observer接口,比Observer多了一个最重要的方法unsubscribe( ),用来取消订阅 *Subscription :Observable调用subscribe( )方法返回的对象,同样有unsubscribe( )方法,可以用来取消订阅事件; RxJava中的一个接口,它只有一个无参call()方法,且无返回值 */ //监听者 private void requestDefaultData() { mRepository.gettheatersMovie("杭州")//根据城市获取资源 .subscribeOn(Schedulers.io())//观察它 .observeOn(AndroidSchedulers.mainThread()) .subscribe(new Subscriber<List<TheatersMoive.SubjectsEntity>>() { //接收数据完成时调用 调用这个数据 @Override public void onCompleted() { if (mSwipeRefreshLayout != null && mSwipeRefreshLayout.isRefreshing()) { mSwipeRefreshLayout.setRefreshing(false); } } //数据接收错误时调用 @Override public void onError(Throwable e) { if (mSwipeRefreshLayout != null && mSwipeRefreshLayout.isRefreshing()) { mSwipeRefreshLayout.setRefreshing(false); } } //正常接收数据调用 @Override public void onNext(List<TheatersMoive.SubjectsEntity> subjectsEntities) { //1.取到传回来的数据 用 javaBean对象装着 mSubjectsEntities = subjectsEntities; if (mTheaterAdapter == null) { //2;出入Adapter mTheaterAdapter = new InTheatersAdapter(mSubjectsEntities,getActivity()); mRecyclerView.setAdapter(mTheaterAdapter); } else { mTheaterAdapter.update(mSubjectsEntities); } } }); }
正在热映的adapter比较简单,它的处理逻辑主要就是把图片和文字填充在itemView里,并且做一些最基本的RecycleView的配置工作。
public class InTheatersAdapter extends com.udaye.library.pullloadlibrary.RecyclerViewCommonAdapter<TheatersMoive.SubjectsEntity> { public InTheatersAdapter(List<TheatersMoive.SubjectsEntity> list, Context context) { super(context, list, R.layout.view_list_home); } public void update(List<TheatersMoive.SubjectsEntity> list) { mList = list; notifyDataSetChanged(); } @Override public int getItemCount() { return mList.size(); } @Override public void onListBindViewHolder(CommonViewHolder holder, int position) { final TheatersMoive.SubjectsEntity entity = mList.get(position); Glide.with(mContext) .load(mList.get(position).getImages().getLarge()) .placeholder(android.R.color.white) .into((ImageView) holder.getView(R.id.photo)); holder.setText(R.id.tv_movie_name, entity.getTitle()); holder.itemView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { mContext.startActivity(MovieDetailActivity.getCalling(mContext, entity.getId())); } }); }这里是一个需要注意的地方,在它的item 点击事件里,传入当前点击的id,传入到电影详情页里,根据获得的id显示电影的详细信息。因为电影太多,而豆瓣的API格式封装的比较好,所以用了一个MovieDetail就够了。
public static Intent getCalling(Context context, String id) { Log.i(TAG, "getCalling: " + id); Intent intent = new Intent(context, MovieDetailActivity.class); intent.putExtra(INERNT_KEY_MOVIE_ID, id);//根据刚刚得到的id传入 去开启详情页 return intent;//返回这个intent 被其他activity调用内部类 }
getMovieDetail(getIntent()); //传递一个intent进入这里就是这个方法,得到api数据 用bean去盛装,然后通过子线程去显示在view界面上。当然如果想做的更好一些,还可以把电影人的照片做一个ListView ,或者把其他一些比较好封装而且有利于提升用户体验的数据做一些封装,这里就根据自己的需要了,去做一些随意性的东西。
/** * 获取电影资讯详情 */ private void getMovieDetail(Intent intent) { //1.得到ID这里面是演员的详情 String movieId = intent.getStringExtra(INERNT_KEY_MOVIE_ID); //处理正则字符串的 如果movieId不为空 if (!TextUtils.isEmpty(movieId)) { mRepository.getMovieDetail(Integer.parseInt(movieId)) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(new Subscriber<MovieDetailBean>() { @Override public void onCompleted() { } @Override public void onError(Throwable e) { } //处理逻辑 @Override public void onNext(MovieDetailBean movieDetailBean) { //1.判空 if (movieDetailBean != null) { //2.缓加载 loadBackdrop(movieDetailBean.getImages().getLarge()); //强制转换在 后面加一个(float) 转换为float型,本来是double //影片信息 // Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); Log.i(TAG, "MovieDetailActivity: onNext " + movieDetailBean.getTitle() + movieDetailBean.getYear() + movieDetailBean.getCasts()); float averageLevel = (float) movieDetailBean.getRating().getAverage(); //设置标题 //评分人数 平分 电影名 tvRating.setText(String.format("%s 分", String.valueOf(averageLevel))); tvFilmName.setText(movieDetailBean.getTitle()); tvRatingNum.setText(String.format("%s 人", String.valueOf(movieDetailBean.getRatings_count()))); tvDateAndFilmTime.setText(movieDetailBean.getYear()); if (movieDetailBean.getCountries() != null && movieDetailBean.getCountries().size() > 0) { tvFilmCountry.setText(movieDetailBean.getCountries().get(0)); } StringBuilder stringBuilder = new StringBuilder(); for (String s : movieDetailBean.getGenres()) { stringBuilder.append(s + "/"); } tvFilmType.setText(stringBuilder.toString().substring(0, stringBuilder.toString().length() - 1)); tvFilmName.setText(movieDetailBean.getOriginal_title() + " [原名]"); //国家 年代 名字 toolbar.setTitle(movieDetailBean.getTitle()); tv_description.setText(movieDetailBean.getSummary()); //alt的处理 alt = movieDetailBean.getAlt(); // loadBaseInfo(movieDetailBean); //处理这个RecycleView里 的照片了 // CelebrityActivity.start(mContext, castsBean.getId()); MovieDetailAdapter artAdapter = new MovieDetailAdapter(MovieDetailActivity.this, movieDetailBean.getCasts()); recyclerview.setAdapter(artAdapter); } } }); } }
贴一下代码,个人觉得重要的那块是网络请求,其他的布局控制,api接口,实体bean的书写(GsonFormat就可以了),都可以用工具。
github源码地址