美文网首页
关于Retrofit的理解之Hello Retrofit

关于Retrofit的理解之Hello Retrofit

作者: 老实任 | 来源:发表于2017-07-29 20:56 被阅读0次

    前言

    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

    相关文章

      网友评论

          本文标题:关于Retrofit的理解之Hello Retrofit

          本文链接:https://www.haomeiwen.com/subject/tmiclxtx.html