1. 程式人生 > >模仿[一個] 製作的Android app

模仿[一個] 製作的Android app

 測試豆瓣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();
                    }
                });
    }
//獲取電影詳情
public Observable<MovieDetailBean> getMovieDetail(int id) {
    return mMovieApiService.getMovieDetail(id);/*map(new Func1<MovieDetailBean, MovieDetailBean>() {
        @Override
        public MovieDetailBean call(MovieDetailBean movieDetailBean) {
            return movieDetailBean;

}
//獲取豆瓣top250
public Observable<mTop250Bean> getTop250Movie(int start, int count) {
    return mMovieApiService.getTop250Movie(start, count);
}
}

這裡關於rxjava,rxtrofit可以好好學習一下,在這裡也碼一下。

在電影詳情頁裡獲取到的最新院線資訊的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原始碼地址