之前的文章有说过 Android MVP框架搭建 以及Dagger, ARouter的基本用法,
下面继续补充说说一些其他框架插件,如:
ButterKnife,Retrofit,EventBus, RxJava
1. ButterKnife
黄油刀,这框架名字听起来挺形象的,用来做什么的呢?它是一个用于Android系统View注入的框架,可以自动生成视图资源索引文件从而绑定视图,替换掉以前总是要写很多繁琐的findViewById来找到View对象。其简单的使用步骤:
1.1 AS开发工具安装插件 Android ButterKnife Zelezny (android studio 4.0后已绑定该插件)
将用户配置文件中的夹包拷到android studio plugin 下
C:\Users\Bruce\AppData\Roaming\Google\AndroidStudio4.1\plugins\Android-ButterKnife-Injections.jar
将以上位置的夹包拷到以下位置:D:\AndroidStudio\plugins, 然后重启android studio
任意找一个layout引用的地方,右键,generate->自动生成代码
1.2 引入依赖
build.gradle
dependencies { api 'com.jakewharton:butterknife:8.5.1' annotationProcessor 'com.jakewharton:butterknife-compiler:8.5.1' }
1.3 引用插件
build.gradle
apply plugin: 'com.jakewharton.butterknife'
1.4 Activity中绑定视图
1.4.1 activity onCreate方法中:
// 绑定视图 ButterKnife.bind(this); 或 // 加载并绑定视图 View contentView = View.inflate(this, R.layout.activity_main, null); ButterKnife.bind(this, contentView);
1.4.2 绑定视图中的组件元素
主模块:
@BindView(R.id.tv_version)
public TextView tv_version;
子模块:
@BindView(R2.id.tv_title)
public TextView tv_title;
注意:多模块构建时,app project中绑定用R, 其他library module中绑定用R2,即子模块用R2。
这是因为多模块构建时,由于命名可能会重复,导致编译时资源引用有冲突。主模块的R文件中定义的变量都是final修饰的,不会被覆盖,在资源查找时会直接引用。但子模块的R文件中声明的变量都不是final修饰的,即为可覆盖的,直接引用可能会导致资源错乱。为了避免该问题ButterKnife会自动将子模块的R文件中定义的变量拷贝到R2文件中然后加上final修饰,同主模块的R文件一同编译,这时就能保证资源id的唯一性。
1.4.3 视图事件监听
主模块:
@OnClick({R.id.button_login})
public void onViewClicked(View view) {
int i = view.getId();
if (i == R.id.button_login) {
//
}
}
子模块(注意绑定注解参数用R2, 监听事件内部处理需用R):
@OnClick({R2.id.tv_cancel, R2.id.tv_confirm, R2.id.tv_button})
public void onViewClicked(View view) {
int i = view.getId();
if (i == R.id.tv_cancel) {
if (onDialogCancelCallback != null) {
onDialogCancelCallback.onCancel();
}
dismiss();
} else if (i == R.id.tv_confirm || i == R.id.tv_button) {
if (onDialogConfirmCallback != null) {
onDialogConfirmCallback.onConfirm();
}
dismiss();
}
}
2. Retrofit
Retrofit其实是基于 okhttp3 封装了一个易用的发起Http请求的框架
2.1 引入依赖
dependencies {
api 'com.squareup.retrofit2:retrofit:2.4.0'
}
2.2 定义拦截器,调节网络请求延迟
public class RetrofitInterceptor implements Interceptor { @Override public Response intercept(Chain chain) throws IOException { Request request = chain.request(); SystemClock.sleep(100); // 网络延迟时间 return chain.proceed(request); } }
2.3 构建请求客户端
public class RetrofitClient {
private static Retrofit.Builder retrofit;
public static RetrofitService getService(String baseUrl) {
if (retrofit == null) {
OkHttpClient client = new OkHttpClient.Builder()
.connectTimeout(ARetrofit.timeout, TimeUnit.SECONDS)
.readTimeout(ARetrofit.timeout, TimeUnit.SECONDS)
.writeTimeout(ARetrofit.timeout, TimeUnit.SECONDS)
.retryOnConnectionFailure(true)
.addNetworkInterceptor(new RetrofitInterceptor())
.build();
retrofit = new Retrofit.Builder().client(client);
}
if (TextUtils.isEmpty(baseUrl)) {
return retrofit.build().create(RetrofitService.class);
}
return retrofit.baseUrl(baseUrl).build().create(RetrofitService.class);
}
}
2.4 定义请求响应回调处理
public abstract class BaseCallback<T> implements Callback<ResponseBody> {
@Override
public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
RetrofitResult<T> result = new RetrofitResult<>();
if (response.code() == 200) {
try {
this.onSuccess(response);
} catch (Exception e) {
result.status = RetrofitResult.Status.ERROR_CLIENT;
if (BuildConfig.DEBUG) {
result.msg = RetrofitResult.Status.ERROR_CLIENT.getMsg();
}
this.onComplete(result);
}
} else {
result.status = RetrofitResult.Status.ERROR_SERVER;
result.msg = RetrofitResult.Status.ERROR_SERVER.getMsg();
this.onComplete(result);
}
}
@Override
public void onFailure(Call<ResponseBody> call, Throwable t) {
RetrofitResult<T> result = new RetrofitResult<>();
if (ConnectUtil.isNetworkConnected()) {
if (t instanceof SocketTimeoutException) {
result.status = RetrofitResult.Status.ERROR_TIMEOUT;
result.msg = RetrofitResult.Status.ERROR_TIMEOUT.getMsg();
} else {
result.status = RetrofitResult.Status.ERROR_REQUEST;
result.msg = RetrofitResult.Status.ERROR_REQUEST.getMsg();
}
} else {
result.status = RetrofitResult.Status.ERROR_NETWORK;
result.msg = RetrofitResult.Status.ERROR_NETWORK.getMsg();
}
this.onComplete(result);
}
/**
* 完成请求
*/
public abstract void onComplete(RetrofitResult<T> result);
/**
* 请求成功
*/
public abstract void onSuccess(Response<ResponseBody> response) throws Exception;
}
public abstract class RetrofitCallback<T> extends BaseCallback<T> {
private Type type; // 泛型的类型
public RetrofitCallback() {
try {
type = ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
} catch (Exception e) {
LogUtil.e(e.getMessage());
}
}
private ParameterizedType type(final Class raw, final Type... args) {
return new ParameterizedType() {
public Type getRawType() {
return raw;
}
public Type[] getActualTypeArguments() {
return args;
}
public Type getOwnerType() {
return null;
}
};
}
@Override
public void onSuccess(Response<ResponseBody> response) throws Exception {
String json = response.body().string();
RetrofitResult result;
if (type != null) {
result = new Gson().fromJson(json, type(RetrofitResult.class, type));
} else {
result = new Gson().fromJson(json, RetrofitResult.class);
}
if (result.code == RetrofitResult.RetrofitCode.SUCCESS) {
result.status = RetrofitResult.Status.SUCCESS;
} else {
result.status = RetrofitResult.Status.ERROR_UNKNOWN;
}
onComplete(result);
}
}
2.5 定义请求方法
public interface RetrofitService {
@GET
Call<ResponseBody> download(@Url String url);
@GET
Call<ResponseBody> get(@Url String url, @QueryMap Map<String, Object> map);
@GET
Call<ResponseBody> get(@Url String url, @Query("userId") int userId);
@POST
Call<ResponseBody> post(@Url String url, @Body RequestBody jsonBody);
@Multipart
@POST
Call<ResponseBody> upload(@Url String url, @Part List<MultipartBody.Part> parts);
@Multipart
@POST
Call<ResponseBody> uploadFile(@Url String url,
@Part List<MultipartBody.Part> parts,
@PartMap Map<String, RequestBody> params);
}
2.6 封装扩展请求方法
以post方法为例:
public class RetrofitRequest {
public static Call post(RetrofitService service, String url,
Object params, Callback callback) {
Map<String, Object> paramMap = new HashMap<>();
if(params != null){
paramMap.put("param", params);
}
Call call = service.post(url, RequestBody.create(MediaType.parse("application/json"), GsonUtil.objectToJson(paramMap)));
call.enqueue(callback);
return call;
}
}
2.7 使用示例
RetrofitService userService = RetrofitClient.getService("http://192.168.2.6:8100/");
Map<String, Object> map = new HashMap<>();
map.put("username", "admin");
map.put("pwd", "admin123");
RetrofitRequest.post(userService, "api/login", map, new RetrofitCallback() {
@Override
public void onComplete(RetrofitResult result) {
if (result.status == RetrofitResult.Status.SUCCESS) {
EventManager.post(new LoginEvent());
} else {
ToastManager.toast(result.msg);
}
}
});
3. EventBus
EventBus是一个基于消息事件的异步处理框架。
3.1 引入依赖
dependencies {
api 'org.greenrobot:eventbus:3.1.1'
}
3.2 定义消息监听管理器
public class EventManager {
/**
* 注册
*/
public static void register(Object view) {
if (!isRegister(view)){
EventBus.getDefault().register(view);
}
}
/**
* 反注册
*/
public static void unregister(Object view) {
if (isRegister(view)){
EventBus.getDefault().unregister(view);
}
}
/**
* 发送事件
*/
public static void post(Object data) {
EventBus.getDefault().post(data);
}
/**
* 是否已注册
*/
private static boolean isRegister(Object view) {
return EventBus.getDefault().isRegistered(view);
}
}
3.3 注册监听
Activity onCreate方法中:
EventManager.register(this);
3.4 发送消息
比如上面Retrofit请求示例中,登录成功回调方法中:
EventManager.post(new LoginEvent());
3.5 监听消息
在需要监听接收消息的Activity中订阅消息:
@Subscribe
public void onEvent(LoginEvent event) {
// 调用对应的presenter处理业务逻辑或执行页面路由跳转等
}
4. RxJava
RxJava是一个异步事件处理操作库,相比于AsyncTask,Handler等的异步操作处理更简洁。
RxJava无需层层嵌套,可以直接链式调用,示例(实现一个简单的倒计时):
private Subscription mSubscription;
private final int TIME = 60; // 开始倒计时时间
private int currentTime = TIME; // 剩余时间
/**
* 开始倒计时
*/
public void countdown() {
getView().tv_code.setEnabled(false);
mSubscription = Observable.interval(0, 1, TimeUnit.SECONDS)
.observeOn(AndroidSchedulers.mainThread()).subscribe(aLong -> {
if (isNotEmptyView()) {
if (currentTime > 0) {
getView().tv_code.setText(currentTime + "s");
getView().tv_code.setTextColor(Color.parseColor("#cccccc"));
} else {
cancelTask();
getView().tv_code.setEnabled(true);
getView().tv_code.setText("验证码");
getView().tv_code.setTextColor(Color.parseColor("#222222"));
currentTime = TIME;
}
currentTime--;
}
});
}
/**
* 取消倒计时
*/
private void cancelTask() {
if (mSubscription != null) {
if (!mSubscription.isUnsubscribed()) {
mSubscription.unsubscribe();
}
mSubscription = null;
}
}
5. 写在最后
以上是Android MVP 中常用的一些框架技术,再加上之前说的Dagger, ARouter等,基本上能解决Android端开发的常规业务功能操作流程问题。后续会再抽空整理下安卓支付对接处理,微信授权分享等以及一些常用的具体组件的用法心得。关注我,持续更新中~