前言
Retrofit是一個(gè)RESTful的網(wǎng)絡(luò)請(qǐng)求框架的一種封裝,Retrofit只需要對(duì)網(wǎng)絡(luò)請(qǐng)求信息進(jìn)行封裝,然后通過(guò)內(nèi)置的OkHttp進(jìn)行網(wǎng)絡(luò)請(qǐng)求,當(dāng)從服務(wù)器返回?cái)?shù)據(jù)之后,OkHttp將結(jié)果交給Retrofit,Retrofit根據(jù)用戶的需求對(duì)結(jié)果進(jìn)行解析,這篇文章我用一個(gè)簡(jiǎn)單的栗子去認(rèn)識(shí)并使用Retrofit。栗子是請(qǐng)求網(wǎng)絡(luò)獲取快遞信息,旨在初識(shí)并使用,并未深入。
前期準(zhǔn)備
要使用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'
然后聯(lián)網(wǎng)別忘了在清單文件添加權(quán)限
<uses-permission android:name="android.permission.INTERNET" />
請(qǐng)求的接口為:
http://www.kuaidi100.com/query?type=快遞公司代號(hào)&postid=快遞單號(hào)
快遞公司代號(hào)為:申通=”shentong” EMS=”ems” 順豐=”shunfeng” 圓通=”yuantong” 中通=”zhongtong” 韻達(dá)=”yunda” 天天=”tiantian” 匯通=”huitongkuaidi” 全峰=”quanfengkuaidi” 德邦=”debangwuliu” 宅急送=”zhaijisong”
前期編碼
下面一步步完成這個(gè)例子,我是打算用listview去顯示這些數(shù)據(jù),所以界面就直接是listview跟一個(gè)出錯(cuò)時(shí)顯示的文字
界面布局為:
<?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>
然后編寫(xiě)實(shí)體bean,實(shí)體bean可以直接用GsonFormat生成,這里就不在累贅敘述
由于listview用得實(shí)在是太頻繁了,所以我老早就封裝好他的適配器了,下面是適配器代碼,可以直接拷貝當(dāng)做工具類來(lái)用..
/**
*
* 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 設(shè)置數(shù)據(jù)源數(shù)據(jù)
*/
public void setDatas(List<T> datas) {
this.datas = datas;
notifyDataSetChanged();
}
/**
* 增加數(shù)據(jù)
* @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;//布局對(duì)象
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適配器繼承即可,下面是這個(gè)栗子的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
寫(xiě)完上面那些前期準(zhǔn)備的代碼就可以著手編寫(xiě)Retrofit的邏輯代碼了首先根據(jù)快遞接口編寫(xiě)Service
/**
* Created by 宋家任 on 2016/9/9.
* 快遞業(yè)務(wù)接口
*/
public interface ExpressApiService {
@GET("query")
Call<ExpressBean> getExpressInfo(@Query("type") String name,
@Query("postid") long id);
}
其實(shí)@GET注解表示get請(qǐng)求,@Query表示請(qǐng)求參數(shù),根據(jù)接口我們知道是根據(jù)type和postid兩個(gè)參數(shù)請(qǐng)求。
然后就可以開(kāi)始請(qǐng)求數(shù)據(jù)了,邏輯代碼為:
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() {
//創(chuàng)建Retrofit實(shí)例
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(BASEURL)//固定的地址
.addConverterFactory(GsonConverterFactory.create())//添加轉(zhuǎn)換器工廠
.build();
ExpressApiService service = retrofit.create(ExpressApiService.class);
Call<ExpressBean> call = service.getExpressInfo("tiantian", 666798482392L);
//異步請(qǐng)求網(wǎng)絡(luò),同步為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用來(lái)進(jìn)行網(wǎng)絡(luò)請(qǐng)求并處理返回結(jié)果的類,請(qǐng)求很簡(jiǎn)單,只要把要請(qǐng)求的參數(shù)傳遞給Call即可.
最后效果如下:
總結(jié)
Retrofit這個(gè)庫(kù)很優(yōu)秀,關(guān)于它還有各種細(xì)節(jié)值得剖析,但是這篇文章的目的只是讓沒(méi)接觸過(guò)Retrofit的同學(xué)進(jìn)行了解使用,后續(xù)我應(yīng)該會(huì)接著寫(xiě)自己對(duì)它的深入理解。
Demo下載地址:http://download.csdn.net/detail/lxzmmd/9628114