java dagger2_从零开始搭建一个项目(rxJava+Retrofit+Dagger2) ---上

工程结构

Androd studio 替代eclipse给我带来最大的感觉,就是不用每次需要用到什么类库,就得去网上下载一个jar包。只要在项目app/build.gradle中加入代码,就能远程使用support-v4包了。

compile 'com.android.support:support-v4:23.2.0'

一般的小项目,这么使用是完全没什么问题的,但是等到项目大起来,模块之间的依赖越来越复杂的时候,上述的写法就会出现问题。

比如出现这么一个场景,你的项目有多个模块,其中A,B,C三个模块都依赖support-v4包。然后在某次升级中,需要对support-v4进行升级,这个时候你需要改的就是A,B,C三个模块的v4包的版本,改三个地方是小意思,问题是有的时候不止三个模块呢,说不定v7包也要升级呢。

为了解决这个问题,我们将统一配置所有的依赖。

首先在工程的根目录下创建一个config.gradle的文件

如图所示:

AAffA0nNPuCLAAAAAElFTkSuQmCC

接下来我们把所有项目所需要的依赖写在这个创建的文件中,这么写即可

AAffA0nNPuCLAAAAAElFTkSuQmCC

依赖已经配置好,那么如何使用呢?首先要在项目下的build.gradle中加入apply from: 'config.gradle'

表示该项目能使用config.gradle这个文件。

接着在app/build.gradle中配置

编译工具的版本,SDK的版本等

AAffA0nNPuCLAAAAAElFTkSuQmCC

依赖的配置

AAffA0nNPuCLAAAAAElFTkSuQmCC

讲到这里,依赖的配置应该清楚了,以后如果需要修改配置,统一修改config.gradle文件即可

项目主体,DrawerLayout+NavigationView的结构

主要的布局文件如下,外层一个DrawerLayout

内层一个Fragment,用来切换内容显示,再加一个NavigationView侧边栏用来控制选项

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:id="@+id/drawer_layout"

android:layout_width="match_parent"

android:layout_height="match_parent"

tools:openDrawer="start">

layout="@layout/app_bar_main"

android:layout_width="match_parent"

android:layout_height="match_parent"/>

android:id="@+id/nav_view"

android:layout_width="wrap_content"

android:layout_height="match_parent"

android:layout_gravity="start"

android:fitsSystemWindows="true"

app:headerLayout="@layout/nav_header_main"

app:menu="@menu/activity_main_drawer"/>

效果如下,这部分内容简单,而且比较常用,相信大部分都可以轻松看懂,就不多做解释了,如果有少部分人看不懂也没事,最后我还把相关代码传到github上,

AAffA0nNPuCLAAAAAElFTkSuQmCC

gif1.gif

架构简述

关于架构,比较传统的该属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的数据流向

AAffA0nNPuCLAAAAAElFTkSuQmCC

MVP的数据流向

AAffA0nNPuCLAAAAAElFTkSuQmCC

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

好!说了这么多,接下来我们来了解下flux架构吧!

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

我的心情这样的:

AAffA0nNPuCLAAAAAElFTkSuQmCC

Flux架构

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

Flux将应用分成4部分View:视图层

Action:view发出的事件,比如点击事件等

Dispatcher:用来接收Actions,执行对应的回调函数

Store:用来存放应用的状态,一旦应用发生变动(数据变化),就提醒View更新

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

如图所示

AAffA0nNPuCLAAAAAElFTkSuQmCC

整体流程

1.用户访问View

2.view发出用户指定的Action,如点击事件

3.Dispatcher收到Action,要求store进行相应的更新

4.store更新完之后,发出"change"事件

5.View收到"change"事件后,更新页面。

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

AAffA0nNPuCLAAAAAElFTkSuQmCC

流程变为

1.用户访问View

2.view从ActionCreator中请求数据

3.ActionCreator加载网络数据,并发出Action

4.Dispatcher收到Action,要求store进行相应的更新

5.store更新完之后,发出"change"事件

6.View收到"change"事件后,更新页面。

根据上述所讲的Flux架构。事情的起点用户访问view,

对应的ActionCreator请求数据网络数据,并发送对应的Action

编写ActionCreator和对应的Actiontip:接下来的内容涉及RxJava,Retrofit2,请还不知道这些是什么的同学,先去入个门

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

String BASE_URL = "http://gank.io/api/";

String DATE_HISTORY = "day/history";

//获取gank的历史数据

@GET(DATE_HISTORY)

Observable getDateHistory();

//获取某一天的数据

@GET("day/{year}/{month}/{day}")

Observable 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;

}

}

}

数据反序列化类 DateDeserializerpublic class DateDeserializer implements JsonDeserializer {

private List 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() {

@Override

public Boolean call(DateData dateData) {

return (null != dateData && null != dateData.results && dateData.results.size() > 0);//接口请求成功,这边返回true

}

})

.map(new Func1() {

@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>() {

@Override

public Observable 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>() {

@Override

public List call(DayData dayData) {

//获取当天的数据,然后在getGankList方法中执行具体的解析工作

return getGankList(dayData);

}

})

.observeOn(AndroidSchedulers.mainThread())

.subscribe(new Action1>() {

@Override

public void call(List gankItems) {

//数据正常处理之后调用此方法

}

}, new Action1() {

@Override

public void call(Throwable throwable) {

//数据处理过程中报错时调用

}

});

}

private List getGankList(DayData dayData) {

if (dayData == null || dayData.results == null) {

return null;

}

//对数据进行处理,解析成你所需要的model

return null;

}

}

附上两张图

AAffA0nNPuCLAAAAAElFTkSuQmCC

api的回调.png

AAffA0nNPuCLAAAAAElFTkSuQmCC

程序返回的数据.png

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值