美文网首页Android架构程序员
从零开始搭建一个项目(rxJava+Retrofit+Dagge

从零开始搭建一个项目(rxJava+Retrofit+Dagge

作者: niknowzcd | 来源:发表于2016-12-14 17:07 被阅读2128次

    鸡汤:积跬步,至千里

    本篇文章是从零开始搭建框架的第二章,将要讲述的是flux架构。

    架构简述

    关于架构,比较传统的该属MVC模式(Model-View-Controllor),这个模式设计之初的有个作用就是解耦,将代码的各个模块分离出来。

    Android一开始的架构模式也是MVC,

    View:对应布局文件

    Model:业务逻辑和实体模型

    Controller:对应Activity

    看起来好像没什么问题,实际上Activity作为一个Controller做的事情太多了,数据绑定,事件处理等代码都是写在Activity中的。等到项目一大,代码一多,程序就会看起来很臃肿。

    因为这些原因,才会有后来的MVP架构(Model-View-Presenter),以及MVVM等架构。

    MVP:

    View:对应Activity,负责View的绘制和事件处理

    Model:业务逻辑和实体模型

    Presenter:负责view和model间的交互。

    MVP的设计理念MVC是一样的,解耦,应该说所有的架构的设计理念都是解耦。

    MVC的数据流向


    MVP的数据流向


    从上述两张图可以看出MVC的data和view是打通的,而且是没有制约的,很容易引起数据的混乱,反观MVP在data和view中间多了一层Presenter,Presenter负责解析数据,并通知view,而view需要什么数据,也是向Presenter请求的。这样就不容易引起数据混乱。

    好!说了这么多,接下来我们来了解下flux架构吧!
    什么,前面讲了这么多MVC和MVP的东西,你说接下来要讲flux了,你是再搞我们吗?

    我的心情这样的:

    Flux架构

    Flux是由facebook推出的架构理念,相比起MVC,更加简洁和清晰。

    Flux将应用分成4部分

    View:视图层
    Action:view发出的事件,比如点击事件等
    Dispatcher:用来接收Actions,执行对应的回调函数
    Store:用来存放应用的状态,一旦应用发生变动(数据变化),就提醒View更新

    Flux最大的特点就是数据的单向流动,这样就不会出现数据混乱的问题
    如图所示

    整体流程
    1.用户访问View
    2.view发出用户指定的Action,如点击事件
    3.Dispatcher收到Action,要求store进行相应的更新
    4.store更新完之后,发出"change"事件
    5.View收到"change"事件后,更新页面。

    不过上图中缺少了一部分,数据的来源,再补上一张图


    流程变为
    1.用户访问View
    2.view从ActionCreator中请求数据
    3.ActionCreator加载网络数据,并发出Action
    4.Dispatcher收到Action,要求store进行相应的更新
    5.store更新完之后,发出"change"事件
    6.View收到"change"事件后,更新页面。

    根据上述所讲的Flux架构。事情的起点用户访问view,
    对应的ActionCreator请求数据网络数据,并发送对应的Action

    编写ActionCreator和对应的Action

    tip:接下来的内容涉及RxJava,Retrofit2,请还不知道这些是什么的同学,先去入个门

    新建网络请求类HttpService 和数据反序列化类 DateDeserializer,注释写的比较详细,所以不多加解释了!

    public interface HttpService {
    
        String BASE_URL = "http://gank.io/api/";
    
        String DATE_HISTORY = "day/history";
    
        //获取gank的历史数据
        @GET(DATE_HISTORY)
        Observable<DateData> getDateHistory();
    
        //获取某一天的数据
        @GET("day/{year}/{month}/{day}")
        Observable<DayData> getDayGank(@Path("year") int year, @Path("month") int month, @Path("day") int day);
    
        
        class Factory {
            private static OkHttpClient mOkHttpClient;
    
            private static final int CACHE_MAX_TIME = 12 * 60 * 60;
            private static final String DATE_PATTERN1 = "yyyy-MM-dd'T'HH:mm:ss.SSSSSS";
            private static final String DATE_PATTERN2 = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'";
    
            static {
                //设置缓存策略
                Interceptor interceptor = new Interceptor() {
                    @Override
                    public Response intercept(Chain chain) throws IOException {
                        Request request = chain.request();
                        Response response = chain.proceed(request);
                        if (request.url().toString().startsWith(BASE_URL)) {
                            int maxTime = CACHE_MAX_TIME;
                            Date receiveDate = response.headers().getDate("Date");
                            if (null != receiveDate) {
                                //设置缓存的到期时候
                                Calendar calendar = Calendar.getInstance();
                                calendar.setTime(receiveDate);
                                int hour = calendar.get(Calendar.HOUR_OF_DAY);
                                int min = calendar.get(Calendar.MINUTE);
    
                                maxTime = 24 * 3600 - hour * 3600 - min * 60;
                            }
                            return response.newBuilder()
                                    .header("Cache-Control", "max-age=" + maxTime)
                                    .build();
                        }
                        return response;
                    }
                };
    
                File cacheDir = new File(AppUtil.getCacheDir(), "http_reponse");
                mOkHttpClient = new OkHttpClient.Builder()
                        .retryOnConnectionFailure(true) //连接失败是否重连
                        .connectTimeout(15, TimeUnit.SECONDS) //超时时间15s
                        .addNetworkInterceptor(interceptor) //把定义好的拦截器加入到okhttp
                        .cache(new Cache(cacheDir, 10 * 1024 * 1024))
                        .build();
            }
    
            private static final Gson dateGson = new GsonBuilder()
                    .registerTypeAdapter(Date.class, new DateDeserializer(DATE_PATTERN1, DATE_PATTERN2))  //定义json的解析样本
                    .serializeNulls()
                    .create();
    
            private static final HttpService mGankService = new Retrofit.Builder()
                    .client(mOkHttpClient)
                    .baseUrl(BASE_URL)
                    .addConverterFactory(GsonConverterFactory.create(dateGson))
                    .addCallAdapterFactory(RxJavaCallAdapterFactory.create())    //允许以 Observable 形式返回
                    .build()
                    .create(HttpService.class);
    
            public static HttpService getGankService() {
                return Factory.mGankService;
            }
    
        }
    }
    

    数据反序列化类 DateDeserializer

    public class DateDeserializer implements JsonDeserializer {
    
        private List<SimpleDateFormat> mDateFormatList;
    
        public DateDeserializer(String... patterns) {
            mDateFormatList = new ArrayList<>(patterns.length);
            for(String pattern : patterns) {
                mDateFormatList.add(new SimpleDateFormat(pattern, Locale.US));
            }
        }
    
        @Override
        public Object deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
            throws JsonParseException {
            for (SimpleDateFormat dateFormat : mDateFormatList) {
                try {
                    return dateFormat.parse(json.getAsString());
                }catch (ParseException e) {
                    e.printStackTrace();
                }
            }
            return null;
        }
    }
    

    新建一个TodayGankFragment类,用来和用户交互。
    public class TodayGankFragment extends Fragment {

        public static final String TAG = TodayGankFragment.class.getSimpleName();
    
        public static TodayGankFragment newInstance() {
            return new TodayGankFragment();
        }
    
    
        @Nullable
        @Override
        public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
            View rootView = inflater.inflate(R.layout.frag_today, container, false);
            return rootView;
        }
    
        @Override
        public void onViewCreated(View view, Bundle savedInstanceState) {
            super.onViewCreated(view, savedInstanceState);
            TodayGankActionCreator creator = new TodayGankActionCreator();
            //view从对应的Creator请求数据
            creator.getTodayGank();
        }
    }
    

    TodayGankFragment类很简单,加载一个简单的布局,然后从对应的Creator请求数据。

    那么这个TodayGankActionCreator类是怎么样的呢!

    新建TodayGankActionCreator类,过滤和初步解析http请求的数据。

    public class TodayGankActionCreator {
    
        //定义数据转化模板
        private static SimpleDateFormat sDataFormat = new SimpleDateFormat("yyyy-MM-dd", Locale.CHINA);
    
        public void getTodayGank() {
    
            //RxJava处理数据
            HttpService.Factory.getGankService()
                    .getDateHistory()
                    .subscribeOn(Schedulers.io())
                    .filter(new Func1<DateData, Boolean>() {
                        @Override
                        public Boolean call(DateData dateData) {
                            return (null != dateData && null != dateData.results && dateData.results.size() > 0);//接口请求成功,这边返回true
                        }
                    })
                    .map(new Func1<DateData, Calendar>() {
                        @Override
                        public Calendar call(DateData dateData) {
                            Calendar calendar = Calendar.getInstance(Locale.CHINA);
                            try {
                                calendar.setTime(sDataFormat.parse(dateData.results.get(0)));  //设置时间为最新一天,一般是今天
                            } catch (ParseException e) {
                                e.printStackTrace();
                                calendar = null;
                            }
                            return calendar;
                        }
                    })
                    .flatMap(new Func1<Calendar, Observable<DayData>>() {
                        @Override
                        public Observable<DayData> call(Calendar calendar) {
                            return HttpService.Factory.getGankService()        //再次请求数据,获取当天的数据
                                    .getDayGank(calendar.get(Calendar.YEAR), calendar.get(Calendar.MONTH) + 1, calendar.get(Calendar.DAY_OF_MONTH));
                        }
                    })
                    .map(new Func1<DayData, List<GankItem>>() {
                        @Override
                        public List<GankItem> call(DayData dayData) {
                            //获取当天的数据,然后在getGankList方法中执行具体的解析工作
                            return getGankList(dayData);
                        }
                    })
                    .observeOn(AndroidSchedulers.mainThread())
                    .subscribe(new Action1<List<GankItem>>() {
                        @Override
                        public void call(List<GankItem> gankItems) {
                            //数据正常处理之后调用此方法
                        }
                    }, new Action1<Throwable>() {
                        @Override
                        public void call(Throwable throwable) {
                            //数据处理过程中报错时调用
                        }
                    });
    
        }
        
        
        private List<GankItem> getGankList(DayData dayData) {
            if (dayData == null || dayData.results == null) {
                return null;
            }
            //对数据进行处理,解析成你所需要的model
    
            return null;
        }
    
    }
    

    附上两张图


    api的回调.png 程序返回的数据.png

    从两张图可以看出,程序已经可以正常返回数据,并以对象的形式,接下来看具体需要如何形式的model,进一步解析即可。

    本章就先到这里。

    从零开始系列第0章
    从零开始系列第1章
    从零开始系列第2章
    从零开始系列完结章

    本人也只是Android开发路上一只稍大一点的菜鸟,如果各位读者中发现文章中有误之处,请帮忙指出,你的批评和鼓励都是我前进的动力。

    写在文末:如果读者朋友有什么问题或者意见可以在评论里指出.
    代码地址为https://github.com/niknowzcd/FluxDemo1

    相关文章

      网友评论

      本文标题:从零开始搭建一个项目(rxJava+Retrofit+Dagge

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