关于Retrofit的理解之Hello Retrofit
前言
Retrofit是一个RESTful的网络请求框架的一种封装,Retrofit只需要对网络请求信息进行封装,然后通过内置的OkHttp进行网络请求,当从服务器返回数据之后,OkHttp将结果交给Retrofit,Retrofit根据用户的需求对结果进行解析,这篇文章我用一个简单的栗子去认识并使用Retrofit。栗子是请求网络获取快递信息,旨在初识并使用,并未深入。
前期准备
要使用Retrofit首先要在build.gradle添加依赖
compile 'com.squareup.retrofit2:retrofit:2.1.0'
Retrofit 2.0之后也不再依赖于Gson ,所以我们要想解析json只能自己添加Gson Converter依赖
compile 'com.squareup.retrofit2:converter-gson:2.1.0'
然后联网别忘了在清单文件添加权限
<uses-permission android:name="android.permission.INTERNET" />
请求的接口为:
http://www.kuaidi100.com/query?type=快递公司代号&postid=快递单号
快递公司代号为:申通=”shentong” EMS=”ems” 顺丰=”shunfeng” 圆通=”yuantong” 中通=”zhongtong” 韵达=”yunda” 天天=”tiantian” 汇通=”huitongkuaidi” 全峰=”quanfengkuaidi” 德邦=”debangwuliu” 宅急送=”zhaijisong”
前期编码
下面一步步完成这个例子,我是打算用listview去显示这些数据,所以界面就直接是listview跟一个出错时显示的文字
界面布局为:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="com.sjr.helloretrofit.MainActivity">
<ListView
android:id="@+id/lv"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<TextView
android:id="@+id/tv_erro"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:textSize="16sp"
android:visibility="gone" />
</RelativeLayout>
listviewitem布局:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="70dp"
android:orientation="vertical"
android:padding="10dp">
<TextView
android:id="@+id/tv_address"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:lines="2"
android:singleLine="true"
android:text="address"
android:textColor="#A7A3A7"
android:textSize="16sp" />
<TextView
android:id="@+id/tv_time"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:layout_marginTop="5dp"
android:text="time"
android:textColor="#A7A3A7"
android:textSize="16sp" />
</LinearLayout>
然后编写实体bean,实体bean可以直接用GsonFormat生成,这里就不在累赘叙述
由于listview用得实在是太频繁了,所以我老早就封装好他的适配器了,下面是适配器代码,可以直接拷贝当做工具类来用..
/**
*
* ListView适配器基类
*/
public abstract class MyListViewBaseAdapter<T> extends BaseAdapter {
private Context context;
private List<T> datas;
private int resId;
public MyListViewBaseAdapter(Context context, int resId) {
this.context = context;
this.resId = resId;
datas = new ArrayList<>();
}
/**
* @param datas 设置数据源数据
*/
public void setDatas(List<T> datas) {
this.datas = datas;
notifyDataSetChanged();
}
/**
* 增加数据
* @param datas
*/
public void addDatas(List<T> datas) {
this.datas.addAll(datas);
notifyDataSetChanged();
}
@Override
public int getCount() {
return datas == null ? 0 : datas.size();
}
@Override
public Object getItem(int position) {
return datas == null ? 0 :datas.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder = null;
if (convertView == null) {
convertView = View.inflate(context, resId, null);
holder = new ViewHolder(convertView);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
bindDatas(holder, datas.get(position));
return convertView;
}
public abstract void bindDatas(ViewHolder holder, T datas);
public class ViewHolder {
public Map<Integer, View> mapCache = new HashMap<>();
public View layoutView;//布局对象
public ViewHolder(View layoutView) {
this.layoutView = layoutView;
}
public View getView(int viewId) {
if (mapCache.get(viewId) != null) {
return mapCache.get(viewId);
} else {
View v = layoutView.findViewById(viewId);
mapCache.put(viewId, v);
return v;
}
}
}
}
然后只要后面的listview适配器继承即可,下面是这个栗子的listview适配器:
public class ListViewAdapter extends MyListViewBaseAdapter<ExpressBean.DataBean> {
public ListViewAdapter(Context context, int resId) {
super(context, resId);
}
@Override
public void bindDatas(ViewHolder holder, ExpressBean.DataBean datas) {
TextView tvAddress = (TextView) holder.getView(R.id.tv_address);
tvAddress.setText(datas.getContext());
TextView tvTime = (TextView) holder.getView(R.id.tv_time);
tvTime.setText(datas.getTime());
}
}
Hello Retrofit
写完上面那些前期准备的代码就可以着手编写Retrofit的逻辑代码了首先根据快递接口编写Service
/**
* Created by 宋家任 on 2016/9/9.
* 快递业务接口
*/
public interface ExpressApiService {
@GET("query")
Call<ExpressBean> getExpressInfo(@Query("type") String name,
@Query("postid") long id);
}
其实@GET注解表示get请求,@Query表示请求参数,根据接口我们知道是根据type和postid两个参数请求。
然后就可以开始请求数据了,逻辑代码为:
public class MainActivity extends AppCompatActivity {
private static final String BASEURL = "http://www.kuaidi100.com/";
@BindView(R.id.lv)
ListView lv;
@BindView(R.id.tv_erro)
TextView tvErro;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ButterKnife.bind(this);
downDatas();
}
private void downDatas() {
//创建Retrofit实例
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(BASEURL)//固定的地址
.addConverterFactory(GsonConverterFactory.create())//添加转换器工厂
.build();
ExpressApiService service = retrofit.create(ExpressApiService.class);
Call<ExpressBean> call = service.getExpressInfo("tiantian", 666798482392L);
//异步请求网络,同步为execute
call.enqueue(new Callback<ExpressBean>() {
@Override
public void onResponse(Call<ExpressBean> call, Response<ExpressBean> response) {
if ("200".equals(response.body().getStatus())) {
List<ExpressBean.DataBean> beans = response.body().getData();
ListViewAdapter adapter = new ListViewAdapter(MainActivity.this, R.layout.item_lv);
lv.setAdapter(adapter);
adapter.setDatas(beans);
} else {
tvErro.setVisibility(View.VISIBLE);
tvErro.setText("no message");
}
}
@Override
public void onFailure(Call<ExpressBean> call, Throwable t) {
tvErro.setVisibility(View.VISIBLE);
tvErro.setText(t.getMessage());
}
});
}
}
其中
Call<ExpressBean> call = service.getExpressInfo("tiantian", 666798482392L);
Call是Retrofit用来进行网络请求并处理返回结果的类,请求很简单,只要把要请求的参数传递给Call即可.
最后效果如下:
这里写图片描述
总结
Retrofit这个库很优秀,关于它还有各种细节值得剖析,但是这篇文章的目的只是让没接触过Retrofit的同学进行了解使用,后续我应该会接着写自己对它的深入理解。
Demo下载地址:http://download.csdn.net/detail/lxzmmd/9628114