Android RxJava+Retrofit+RecyclerView 学习

下面记录学习的内容

一.添加依赖项 (本人添加的依赖项如下)

    implementation 'com.android.support:cardview-v7:27.1.1'
    implementation 'com.android.support:design:27.1.1'
    implementation 'com.squareup.retrofit2:retrofit:2.3.0'
    implementation 'com.google.code.gson:gson:2.6.2'
    implementation 'io.reactivex:rxjava:1.1.0'
    implementation 'io.reactivex:rxandroid:1.1.0'
    implementation 'com.squareup.retrofit2:converter-gson:2.1.0'
    implementation 'com.squareup.retrofit2:adapter-rxjava:2.1.0'

    implementation 'com.nostra13.universalimageloader:universal-image-loader:1.9.3'

二.定义数据bean

定义 Movie 类

public class Movie {

    public String title;
    public String original_title;
    public String year;
    public MovieImage images;

    public static class MovieImage{
        public String small;
        public String large;
        public String medium;
    }
}

定义 Movie list 类

public class MovieSubject {
   public int start;
   public List<Movie>  subjects;
   public String title;
}

三.Retrofit + Rxjava

定义一个 Retrofit 相关的类
个人认为可以分为下面几个步骤:
1. 创建 OKHttpClient
2. 创建Retrofit
3. 添加 函数 接口 ApiService
4. 实现调用的函数
5. 定义接口类
6. 调用函数getTop250获取数据

public class RetrofitServiceManager {

    private static final int DEFAULT_TIME_OUT = 5;//超时时间 5s
    private static final int DEFAULT_READ_TIME_OUT = 10;
    private Retrofit mRetrofit;
    private OkHttpClient.Builder builder;
    private ApiService apiService = null;

    private RetrofitServiceManager(){
        //1. 创建 OKHttpClient
        builder = new OkHttpClient.Builder()
                .connectTimeout(DEFAULT_TIME_OUT, TimeUnit.SECONDS)
                .writeTimeout(DEFAULT_READ_TIME_OUT,TimeUnit.SECONDS)
                .readTimeout(DEFAULT_READ_TIME_OUT,TimeUnit.SECONDS);

        //2. 创建Retrofit
        mRetrofit = new Retrofit.Builder()
                .client(builder.build())
                .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
                .addConverterFactory(GsonConverterFactory.create())
                .baseUrl("https://api.douban.com/v2/movie/")
                .build();
        //3.添加 函数 接口 ApiService
        apiService = mRetrofit.create(ApiService.class);
    }

    private static class SingletonHolder{
        private static final RetrofitServiceManager INSTANCE = new RetrofitServiceManager();
    }

    public static RetrofitServiceManager getInstance(){
        return SingletonHolder.INSTANCE;
    }
   //4.实现调用的函数
    public void getTop250(int start, int count, Subscriber<MovieSubject> subscriber){
        apiService.getTop250(start,count)
                .subscribeOn(Schedulers.io())
                .unsubscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(subscriber);
    }
}

Apiservice 接口定义如下
//5.定义接口类

public interface ApiService {
    //获取豆瓣Top250 榜单
    @GET("top250")
    Observable<MovieSubject> getTop250(@Query("start") int start, @Query("count")int count);
}

注意 MovieSubject 相关的几个地方要一致,MovieSubject 就是要返回的数据类型,要从网络端得到的数据类型

private void getMovieList(){
//6.调用函数getTop250获取数据
        RetrofitServiceManager.getInstance().getTop250(0, 10, new Subscriber<MovieSubject>() {
            @Override
            public void onCompleted() {
            //数据传输完成
                Log.e(TAG,"MainActivity onCompleted");
            }

            @Override
            public void onError(Throwable e) {
            //e.getMessage()可以打印出网络报错的原因,如手机网络权限内打开
                Log.e(TAG,"MainActivity onError: "+ e.getMessage());
            }

            @Override
            public void onNext(MovieSubject movieSubject) {
            //传输数据
                Log.e(TAG,"MainActivity onNext");
                myRecyclerViewAdapter.setmMovies(movieSubject.subjects);
                //通知RecyclerViewAdapter适配器更新数据
                myRecyclerViewAdapter.notifyDataSetChanged();
            }
        });
    }

四.RecyclerView使用

这个个人认为可以参照 listview的使用,会更容易理解;适配器的定义如下:

public class MyRecyclerViewAdapter extends RecyclerView.Adapter<MyRecyclerViewAdapter.MovieHolder> {

    private List<Movie> mMovies;
    private String TAG = "MyRecyclerViewAdapter";
    private Context context = null;

    public MyRecyclerViewAdapter(Context context){
        this.context = context;
    }

    @NonNull
    @Override
    public MovieHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
//创建RecyclerView的list中每个item的布局,放在 moive_item中
        View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.moive_item,parent,false);
        MovieHolder holder = new MovieHolder(view);
       return holder;
    }

    public void setmMovies(List<Movie> mMovies) {
        this.mMovies = mMovies;
    }


    @Override
    public void onBindViewHolder(@NonNull MovieHolder holder, int position) {
        //Log.e(TAG,"xtk onBindViewHolder");

        Movie movie = mMovies.get(position);

        Log.e(TAG,"xtk onBindViewHolder:" + movie.title);
        ImageLoader.getInstance().displayImage(movie.images.small,holder.mImageView);
        holder.time.setText("上映时间:"+movie.year + "年");
        holder.title.setText(movie.title);
        holder.subTitle.setText(movie.original_title);
    }

    @Override
    public int getItemCount() {
        //return 0;
        int count = mMovies == null ? 0:mMovies.size();
        Log.e(TAG,"xtk getItemCount:" + String.valueOf(count));
        return count;
    }
   //RecyclerView的每个item的要显示内容
    public static class MovieHolder extends RecyclerView.ViewHolder{
        public ImageView mImageView;
        public TextView title;
        public TextView subTitle;
        public TextView time;
        public MovieHolder(View itemView) {
            super(itemView);
            mImageView = (ImageView) itemView.findViewById(R.id.movie_image);
            title = (TextView) itemView.findViewById(R.id.movie_title);
            subTitle = (TextView) itemView.findViewById(R.id.movie_sub_title);
            time = (TextView) itemView.findViewById(R.id.movie_time);
        }
    }
}

通知数据更新 myRecyclerViewAdapter.notifyDataSetChanged()

其中收到更新数据后,函数调用如下
1.getItemCount() :得到要显示的 list数目
2.onCreateViewHolder:创建需要的item个数即布局情况
3.onBindViewHolder:数据加载到每个 item上面

item的布局如下(moive_item.xml):

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:orientation="vertical"
              android:layout_width="match_parent"
              android:layout_height="120dp"
    android:background="@drawable/item_shape"
    >
  <RelativeLayout
      android:layout_width="match_parent"
      android:layout_height="wrap_content"
      >

      <ImageView
          android:id="@+id/movie_image"
          android:layout_width="80dp"
          android:layout_height="100dp"
          android:layout_marginTop="10dp"
          android:layout_marginBottom="10dp"
          android:layout_marginLeft="15dp"
          />
      <LinearLayout
          android:layout_width="match_parent"
          android:layout_height="wrap_content"
          android:orientation="vertical"
          android:layout_marginLeft="10dp"
          android:layout_toRightOf="@+id/movie_image"
          >
          <TextView
              android:id="@+id/movie_title"
              android:layout_width="match_parent"
              android:layout_height="wrap_content"
              android:textSize="18sp"
              android:textColor="@android:color/black"
              android:text="hello"
              />
          <TextView
              android:id="@+id/movie_sub_title"
              android:layout_width="match_parent"
              android:layout_height="wrap_content"
              android:textSize="18sp"
              android:layout_marginTop="8dp"
              android:textColor="@android:color/black"
              android:text="hello"
              />
          <TextView
              android:id="@+id/movie_time"
              android:layout_width="match_parent"
              android:layout_height="wrap_content"
              android:layout_marginTop="8dp"
              android:textSize="18sp"
              android:textColor="@android:color/black"
              />
      </LinearLayout>

  </RelativeLayout>
</LinearLayout>

五.MainActivity代码如下

public class MainActivity extends AppCompatActivity {

    private RecyclerView recyclerView = null;
    private MyRecyclerViewAdapter myRecyclerViewAdapter = null;
    private String TAG = "MainActivity";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        Log.e(TAG,"MainActivity onCreate");

        Toolbar toolbar = (Toolbar) findViewById(R.id.main_toolbar);
        toolbar.setNavigationOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                finish();
            }
        });
       toolbar.setTitle("hell");

        recyclerView = (RecyclerView) findViewById(R.id.recycler_view);
        recyclerView.addItemDecoration(new MovieDecoration());
        //定义recyclerView 的layout,否则可能会出现不显示数据
        LinearLayoutManager manager = new LinearLayoutManager(this);
        manager.setOrientation(LinearLayoutManager.VERTICAL);
        recyclerView.setLayoutManager(manager);

        myRecyclerViewAdapter = new MyRecyclerViewAdapter(this);
        recyclerView.setAdapter(myRecyclerViewAdapter);
        getMovieList();

    }

    private void getMovieList(){
        RetrofitServiceManager.getInstance().getTop250(0, 10, new Subscriber<MovieSubject>() {
            @Override
            public void onCompleted() {
                Log.e(TAG,"MainActivity onCompleted");
            }

            @Override
            public void onError(Throwable e) {
                Log.e(TAG,"MainActivity onError: "+ e.getMessage());
            }

            @Override
            public void onNext(MovieSubject movieSubject) {
                Log.e(TAG,"MainActivity onNext");
                myRecyclerViewAdapter.setmMovies(movieSubject.subjects);
                myRecyclerViewAdapter.notifyDataSetChanged();
            }
        });
    }

//RecyclerView item间距布置
    public static class MovieDecoration extends RecyclerView.ItemDecoration{
        @Override
        public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
            outRect.set(0,0,0,20);
        }
    }
}

六.ImageLoader 初始化配置

public class MovieApplication extends Application {

    private static final int MEMORY_SIZE = 5 * 1024 * 1024;
    private static final int DISK_SIZE = 20 * 1024 * 1024;

    @Override
    public void onCreate() {
        super.onCreate();

        // 初始化 Image-Loader
        DisplayImageOptions options = new DisplayImageOptions.Builder()
                .cacheInMemory(true)
                .cacheOnDisk(true)
                .build();

        ImageLoaderConfiguration configuration = new ImageLoaderConfiguration.Builder(this)
                .memoryCache(new LruMemoryCache(MEMORY_SIZE))
                .diskCache(new UnlimitedDiscCache(new File(getCacheDir(),"caches")))
                .diskCacheSize(DISK_SIZE)
                .defaultDisplayImageOptions(options)
                .build();

        ImageLoader.getInstance().init(configuration);
    }
}

七.AndroidMainfest中添加下面内容

android:name=".MovieApplication"

八、activity_main 文件

<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"
    android:orientation="vertical"
    android:background="@android:color/darker_gray"
    tools:context=".MainActivity">

    <android.support.v7.widget.Toolbar
        android:id="@+id/main_toolbar"
        android:layout_width="match_parent"
        android:layout_height="50dp"
        android:background="@color/colorPrimary"
        />

    <android.support.v7.widget.RecyclerView
        android:id="@+id/recycler_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:padding="10dp"
        />

</LinearLayout>

调试中遇到的问题:
1.没有打开网络权限
2.LinearLayout布局没有设置方向导致数据一直显示不出来
3.ImageLoader 加载网络图片要先初始化配置
4.出现错误 call to OpenGL ES API with no current context,该问题不影响功能
本人还在Android学习的初级阶段,因此写的内容都非常简单且大部分为代码的堆叠

本代码参考内容(有的部分是直接拿来)
1.https://www.jianshu.com/p/811ba49d0748

可能有人更喜欢直接看代码(上传时积分处没有选 0 的项,就选择了1):
https://download.csdn.net/download/shiluohuashengmi/10475752

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值