1 Retrofit(HTTP客户端)
1.1 简介
我们项目当中的每个
app
都需要用到网络和服务器进行交互,在
Android
项目开发中使用
HTTP
协议完成通信的话,基本上都要用到OkHttp
或者
Retrofit
。
OkHttp
和
Retrofit
是目前应用最为广泛的网络组件。
1.2 Retrofit是什么?
准确来说,
Retrofit
是一个
RESTful
的
HTTP
网络请求框架的封装。
网络请求的工作本质上是
OkHttp
完成,而
Retrofit
仅负责网络请求接口的封装。
App
应用程序通过Retrofit请求网络,实际上是使用
Retrofit
接口层封装请求参数、
Header
、
Url
等信息,之后由
OkHttp完成后续的请求操作。在服务端返回数据之后,OkHttp
将原始的结果交给
Retrofit
,
Retrofit
根据用户的需求对结果进行解析。
1.3 Retrofit的使用 (异步GET)
第一步: 创建项目
第二步:导入依赖
implementation "com.github.bumptech.glide:glide:4.12.0"
implementation("com.squareup.okhttp3:okhttp:4.10.0")
implementation 'com.squareup.retrofit2:retrofit:2.4.0'
implementation 'com.squareup.retrofit2:converter-gson:2.0.2'
第三步:添加网络权限
<uses-permission android:name="android.permission.INTERNET"/>
第四步:在
activity_main.xml
添加
Recycle
,并给其设置
id
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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"
tools:context=".MainActivity">
<androidx.viewpager2.widget.ViewPager2
android:id="@+id/vp_head_img"
android:layout_width="match_parent"
android:layout_height="200dp"/>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rv_news"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="10dp"
android:layout_below="@+id/vp_head_img"/>
</RelativeLayout>
第五步:创建子布局
<?xml version="1.0" encoding="utf-8"?>
<androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="150dp"
android:layout_margin="5dp">
<ImageView
android:id="@+id/iv_news"
android:layout_width="160dp"
android:layout_height="match_parent"
android:scaleType="fitXY" />
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="20dp"
android:layout_toEndOf="@+id/iv_news"
android:orientation="vertical">
<TextView
android:id="@+id/tv_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_marginTop="30dp"
android:text="text"/>
<TextView
android:id="@+id/tv_desc"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_marginTop="30dp"
android:text="text"/>
</LinearLayout>
</RelativeLayout>
</androidx.cardview.widget.CardView>
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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">
<ImageView
android:id="@+id/iv_head"
android:layout_width="match_parent"
android:layout_height="200dp"
android:scaleType="fitXY"
tools:srcCompat="@tools:sample/avatars" />
</RelativeLayout>
第六步:创建实体类
public class News {
private boolean success;
private String title;
private String subtitle;
private String update_time;
private List<Data> data;
public class Data {
private int index;
private String title;
private String pic;
private String desc;
private String url;
private String mobilUrl;
public void setIndex(int index) {
this.index = index;
}
public int getIndex() {
return index;
}
public void setTitle(String title) {
this.title = title;
}
public String getTitle() {
return title;
}
public void setPic(String pic) {
this.pic = pic;
}
public String getPic() {
return pic;
}
public void setDesc(String desc) {
this.desc = desc;
}
public String getDesc() {
return desc;
}
public void setUrl(String url) {
this.url = url;
}
public String getUrl() {
return url;
}
public void setMobilUrl(String mobilUrl) {
this.mobilUrl = mobilUrl;
}
public String getMobilUrl() {
return mobilUrl;
}
}
public News(List<Data> data) {
this.data = data;
}
public List<Data> getData() {
return data;
}
@Override
public String toString() {
return "News{" +
"success=" + success +
", title='" + title + '\'' +
", subtitle='" + subtitle + '\'' +
", update_time='" + update_time + '\'' +
", data=" + data.toString() +
'}';
}
}
public class HeadImg {
private boolean success;
private String title;
private String subtitle;
private String update_time;
private List<Data> data;
public class Data {
private int index;
private String title;
private String pic;
private String desc;
private String url;
private String mobilUrl;
public void setIndex(int index) {
this.index = index;
}
public int getIndex() {
return index;
}
public void setTitle(String title) {
this.title = title;
}
public String getTitle() {
return title;
}
public void setPic(String pic) {
this.pic = pic;
}
public String getPic() {
return pic;
}
public void setDesc(String desc) {
this.desc = desc;
}
public String getDesc() {
return desc;
}
public void setUrl(String url) {
this.url = url;
}
public String getUrl() {
return url;
}
public void setMobilUrl(String mobilUrl) {
this.mobilUrl = mobilUrl;
}
public String getMobilUrl() {
return mobilUrl;
}
@Override
public String toString() {
return "Data{" +
"index=" + index +
", title='" + title + '\'' +
", pic='" + pic + '\'' +
", desc='" + desc + '\'' +
", url='" + url + '\'' +
", mobilUrl='" + mobilUrl + '\'' +
'}';
}
}
public HeadImg(List<Data> data) {
this.data = data;
}
public List<Data> getData() {
return data;
}
@Override
public String toString() {
return "HeadImg{" +
"data=" + data +
'}';
}
}
第七步:创建适配器
public class NewsAdapter extends RecyclerView.Adapter<NewsAdapter.ViewHold> {
private List<News.Data> list;
public void setList(List<News.Data> list){
this.list=list;
notifyDataSetChanged();
}
@NonNull
@Override
public ViewHold onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.news_item, parent,false);
ViewHold viewHold=new ViewHold(view);
return viewHold;
}
@Override
public void onBindViewHolder(@NonNull ViewHold holder, int position) {
News.Data data=list.get(position);
holder.tv_tital.setText(data.getTitle());
holder.tv_desc.setText(data.getDesc());
Glide.with(holder.view).load(data.getPic()).into(holder.iv_news);
}
@Override
public int getItemCount() {
return list == null ? 0 : list.size();
}
public class ViewHold extends RecyclerView.ViewHolder{
TextView tv_tital;
TextView tv_desc;
ImageView iv_news;
View view;
public ViewHold(@NonNull View itemView) {
super(itemView);
this.view=itemView;
tv_tital=itemView.findViewById(R.id.tv_title);
tv_desc=itemView.findViewById(R.id.tv_desc);
iv_news=itemView.findViewById(R.id.iv_news);
}
}
}
public class HeadImgAdapter extends RecyclerView.Adapter<HeadImgAdapter.ViewHold> {
private List<HeadImg.Data> list;
public void setList(List<HeadImg.Data> list) {
this.list = list;
notifyDataSetChanged();
}
@NonNull
@Override
public ViewHold onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.head_img_item, parent, false);
ViewHold viewHold=new ViewHold(view);
return viewHold;
}
@Override
public void onBindViewHolder(@NonNull ViewHold holder, int position) {
HeadImg.Data data = list.get(position);
Glide.with(holder.view).load(data.getPic()).into(holder.iv_head);
}
@Override
public int getItemCount() {
return list == null ? 0 : list.size();
}
public class ViewHold extends RecyclerView.ViewHolder{
ImageView iv_head;
View view;
public ViewHold(@NonNull View itemView) {
super(itemView);
this.view=itemView;
iv_head=itemView.findViewById(R.id.iv_head);
}
}
}
第九步:创建请求接口
public interface GetRequest_Interface {
//https://api.vvhan.com/api/hotlist?type=baiduRD
@GET("api/hotlist?type=baiduRD")
Call<News> getNews();
//https://api.vvhan.com/api/hotlist?type=wxHot
@GET("api/hotlist?type=wxHot")
Call<HeadImg> getHeadImg();
}
第十步:进行网络请求
public class MainActivity extends AppCompatActivity {
private ViewPager2 vp_head_img;
private RecyclerView rv_news;
private LinearLayoutManager layoutManager;
private NewsAdapter newsAdapter;
private HeadImgAdapter headImgadapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
vp_head_img=findViewById(R.id.vp_head_img);
rv_news=findViewById(R.id.rv_news);
layoutManager=new LinearLayoutManager(MainActivity.this);
newsAdapter=new NewsAdapter();
rv_news.setLayoutManager(layoutManager);
rv_news.setAdapter(newsAdapter);
headImgadapter=new HeadImgAdapter();
vp_head_img.setAdapter(headImgadapter);
loadNews();
loadHeadImg();
}
private void loadNews() {
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://api.vvhan.com/")
.addConverterFactory(GsonConverterFactory.create())
.build();
GetRequest_Interface request = retrofit.create(GetRequest_Interface.class);
Call<News> call = request.getNews();
call.enqueue(new Callback<News>() {
@Override
public void onResponse(Call<News> call, Response<News> response) {
newsAdapter.setList(response.body().getData());
}
@Override
public void onFailure(Call<News> call, Throwable t) {
Log.i("onFailure","连接失败");
}
});
}
private void loadHeadImg() {
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://api.vvhan.com/")
.addConverterFactory(GsonConverterFactory.create())
.build();
GetRequest_Interface request = retrofit.create(GetRequest_Interface.class);
Call<HeadImg> call = request.getHeadImg();
call.enqueue(new Callback<HeadImg>() {
@Override
public void onResponse(Call<HeadImg> call, Response<HeadImg> response) {
headImgadapter.setList(response.body().getData());
Log.i("onResponse","连接成功");
}
@Override
public void onFailure(Call<HeadImg> call, Throwable t) {
Log.i("onFailure","连接失败");
}
});
}
}
2 RxJAVA(响应式编程)
2.1 简介
2.1.1 响应式编程
响应式编程的一个关键概念是事件。事件可以被等待,可以触发过程,也可以触发其它事件。事件是唯一的以合适的方式将我们的现实世界映射到我们的软件中:如果屋里太热了我们就打开一扇窗户。同样的,当我们的天气app
从服务端获取到新的天气数据后,我们需要更新
app
上展示天气信息的
UI
;汽车上的车道偏移系统探测到车辆偏移了正常路线就会提醒驾驶者纠正,就是是响应事件。
2.1.2 什么是RxJava
RxJava
是一种响应式编程,来创建基于事件的异步操作库。基于事件流的链式调用、逻辑清晰简
洁。
RxJava
我的理解是将事件从起点(上游)流向终点(下游),中间有很多卡片对数据进操作并传
递,每个卡片获取上一个卡片传递下来的结果然后对事件进行处理然后将结果传递给下一个卡片,
这样事件就从起点通过卡片一次次传递直到流向终点。
2.1.3 什么是观察者模式?
举个栗子,
Android
中
View
的点击监听器的实现,
View
是被观察者,
OnClickListener
对象是观察者,Activity要如何知道
View
被点击了?那就是派一个
OnClickListener
对象,入驻
View
,与
View
达成一个订阅关系,一旦View
被点击了,就通过
OnClickListener
对象的
OnClick
方法传达给
Activity
。采用观察者模式可以避免去轮询检查,节约有限的cpu
资源。
2.2 Retrofit+RxJava的使用
2.2.1 为什么要结合使用
代码简洁
借助
retorfit
加
rxjava
,我们就不需要再做其他多余的封装或修改。网络请求写起来就会简单许多,而且结构也清晰。被观察者就是请求的发起,观察者就是请求的回调。
操作符的作用
rxjava
的优势就在于其操作符的使用,我理解的「操作符」就是
rxjava
为我们提供了一系列方法,可以运用在观察者模式中的「被观察者」「观察者」或「订阅过程」之间来控制。实际项目中我遇到过以下几种常见情况,可以用操作符来处理。
1.
请求结果需要做数据处理之后,再给页面展示。 「
map
」操作符,这个操作符就是在请求回来之后直接对数据做处理之后再返回给观察者。
2.
请求结果是做为下一个请求的请求入参。「
flatMap
」操作符,这个操作符是在遇到串联请求时使用的,当第一个请求返回结果之后,再拿着结果去请求下一个接口。
2.2.2 实现步骤
第一步: 创建项目
第二步:导入依赖
implementation "com.github.bumptech.glide:glide:4.12.0"
//for rxjava
implementation 'io.reactivex.rxjava2:rxjava:2.2.0'
//for rxandroid
implementation 'io.reactivex.rxjava2:rxandroid:2.1.0'
//rxjava adapter for retrofit
implementation 'com.squareup.retrofit2:adapter-rxjava2:2.5.0'
implementation 'com.squareup.retrofit2:converter-gson:2.0.2'
第三步:添加网络权限
<uses-permission android:name="android.permission.INTERNET"/>
第四步:在
activity_main.xml
添加
Recycle
,并给其设置
id
<?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"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity" >
<androidx.viewpager2.widget.ViewPager2
android:id="@+id/vp_head_img"
android:layout_width="match_parent"
android:layout_height="200dp"/>
</LinearLayout>
第五步:创建子布局
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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">
<ImageView
android:id="@+id/iv_head"
android:layout_width="match_parent"
android:layout_height="200dp"
android:scaleType="fitXY"
tools:srcCompat="@tools:sample/avatars" />
</RelativeLayout>
第六步:创建实体类
public class HeadImg {
private boolean success;
private String title;
private String subtitle;
private String update_time;
private List<Data> data;
public class Data {
private int index;
private String title;
private String pic;
private String desc;
private String url;
private String mobilUrl;
public void setIndex(int index) {
this.index = index;
}
public int getIndex() {
return index;
}
public void setTitle(String title) {
this.title = title;
}
public String getTitle() {
return title;
}
public void setPic(String pic) {
this.pic = pic;
}
public String getPic() {
return pic;
}
public void setDesc(String desc) {
this.desc = desc;
}
public String getDesc() {
return desc;
}
public void setUrl(String url) {
this.url = url;
}
public String getUrl() {
return url;
}
public void setMobilUrl(String mobilUrl) {
this.mobilUrl = mobilUrl;
}
public String getMobilUrl() {
return mobilUrl;
}
@Override
public String toString() {
return "Data{" +
"index=" + index +
", title='" + title + '\'' +
", pic='" + pic + '\'' +
", desc='" + desc + '\'' +
", url='" + url + '\'' +
", mobilUrl='" + mobilUrl + '\'' +
'}';
}
}
public HeadImg(List<Data> data) {
this.data = data;
}
public List<Data> getData() {
return data;
}
@Override
public String toString() {
return "HeadImg{" +
"data=" + data +
'}';
}
}
第七步:创建适配器
public class HeadImgAdapter extends RecyclerView.Adapter<HeadImgAdapter.ViewHold> {
private List<HeadImg.Data> list;
public void setobservable(List<HeadImg.Data> list) {
this.list = list;
notifyDataSetChanged();
}
@NonNull
@Override
public ViewHold onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.head_img_item, parent, false);
ViewHold viewHold=new ViewHold(view);
return viewHold;
}
@Override
public void onBindViewHolder(@NonNull ViewHold holder, int position) {
HeadImg.Data data = list.get(position);
Glide.with(holder.view).load(data.getPic()).into(holder.iv_head);
}
@Override
public int getItemCount() {
return list == null ? 0 : list.size();
}
public class ViewHold extends RecyclerView.ViewHolder{
ImageView iv_head;
View view;
public ViewHold(@NonNull View itemView) {
super(itemView);
this.view=itemView;
iv_head=itemView.findViewById(R.id.iv_head);
}
}
}
第九步:
创建请求接口
public interface GetRequest_Interface {
//https://api.vvhan.com/api/hotlist?type=wxHot
@GET("api/hotlist?type=wxHot")
Observable<HeadImg> getHeadImg();
}
第十步:进行网络请求
public class MainActivity extends AppCompatActivity {
private ViewPager2 vp_head_img;
private HeadImgAdapter headImgadapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
vp_head_img=findViewById(R.id.vp_head_img);
headImgadapter=new HeadImgAdapter();
vp_head_img.setAdapter(headImgadapter);
loadHeadImg();
}
private void loadHeadImg() {
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://api.vvhan.com/")
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.build();
GetRequest_Interface request = retrofit.create(GetRequest_Interface.class);
Observable<HeadImg> observable = request.getHeadImg();
observable.subscribeOn(Schedulers.io())//在io线程进行网络请求操作
.observeOn(AndroidSchedulers.mainThread())//回到主线程 处理请求结果
.subscribe(new Observer<HeadImg>() {
@Override
public void onSubscribe(Disposable d) {
}
@Override
public void onNext(HeadImg headImg) {
headImgadapter.setobservable(headImg.getData());
}
@Override
public void onError(Throwable e) {
Log.i("onError","连接失败");
}
@Override
public void onComplete() {
Log.i("onComplete","连接完成");
}
});
}
}