代码强迫症晚期患者,碰到新鲜的,觉得确实比自己写的好的,就会把自己的代码全改了,虽然碰到各种各样的坑,但是过程是很爽很爽的,极大的满足感。同时公开了很多公共依赖库,新开发的项目只需要添加一行依赖就ok了,可以快速开发应用
一。代码框架mvvm+fragmentation:
1.mvvm的数据绑定各种天马行空的错误,开始的时候真的很头疼,但还是咬牙坚持下来了,mvvm可以通过一行代码控制recylerview填充,刷新
adapter可以这样写,
@BindingAdapter({"app:functionsf", "app:functionsItem"})
public static void scanAdapter(final RecyclerView recyclerView, final FunctionsFVH scanVH, final ArrayList<FunctionBean> arrayList) {
RecyclerView.Adapter adapter = recyclerView.getAdapter();
if (adapter != null) {
adapter.notifyDataSetChanged();
return;
}
if (scanVH != null && arrayList != null) {
recyclerView.setLayoutManager(new GridLayoutManager(recyclerView.getContext(), 3));
recyclerView.setAdapter(new BaseRecyclerAdapterF<FunctionBean>(arrayList) {
@Override
protected RecyclerView.ViewHolder createNewViewHolder(ViewGroup parent, int viewType) {
ViewDataBinding binding = getBinding(parent, R.layout.f_functions_item);
RecyclerView.ViewHolder viewHolder = new FunctionsFItemVH(binding, scanVH.mCtx);
binding.setVariable(cn.com.reformer.brake.BR.FunctionsFItemVH, viewHolder);
return viewHolder;
}
});
}
}
xml文件
<android.support.v7.widget.RecyclerView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/title_aasdfasf"
android:layout_centerInParent="true"
android:layout_gravity="center"
android:divider="@null"
android:dividerHeight="8dp"
app:functionsItem="@{FunctionsFVH.itmesVHs}"
app:functionsf="@{FunctionsFVH}" />
viewhodler中的成员变量
public final ObservableArrayList<FunctionBean> itmesVHs = new ObservableArrayList<>();
通过改变这个成员变量就可以实现adapter的填充,刷新,真tmd英明神武啊
2.framentation是youkey大神的开源框架,通过这个框架完全可以实现单Activity+多Fragment模式,app整体性能很轻,各种跳转很优美,所有也进行了各种各样的踩坑,再完成门禁大师app的时候,实现了一个Activity+多个fragment的框架,其中很多坑比如
1>activity主题切换:启动主题要更换普通主题的
<!--启动模式-->
<style name="theme_launch" parent="Theme.AppCompat.Light.NoActionBar">
<item name="android:windowFullscreen">true</item>
<item name="android:windowBackground">@drawable/launch_bg</item>
<item name="android:navigationBarColor">@color/colorPrimaryTitle</item>
</style>
<!--主题模式-->
<style name="theme_wangfei" parent="Theme.AppCompat.Light.NoActionBar">
<item name="android:windowBackground">@color/colorPrimary</item>
<item name="android:navigationBarColor">@color/colorPrimaryTitle</item>
</style>
注意单个activity的实现主题的切换是很麻烦的,尤其加上fragmentation框架
package com.reformer.util.global;
import android.os.Build;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.annotation.RequiresApi;
import android.view.WindowManager;
import com.baidu.mobstat.StatService;
import com.reformer.util.R;
import me.yokeyword.fragmentation.SupportActivity;
import wangfei.util.global.SpUtil;
public abstract class BaseA extends SupportActivity {
public static BaseA mCtx;//上下文
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
initTheme(savedInstanceState);
}
@Override
protected void onResume() {
super.onResume();
StatService.onResume(mCtx);
mCtx = this;
}
@Override
protected void onPause() {
super.onPause();
StatService.onPause(mCtx);
mCtx = null;
SpUtil.putString("welcomeTime", String.valueOf(System.currentTimeMillis()));
}
@Override
protected void onSaveInstanceState(Bundle savedInstanceState) {
super.onSaveInstanceState(savedInstanceState);
savedInstanceState.putInt("theme", mCurTheme);
}
public int mCurTheme = 0;
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
private void initTheme(Bundle savedInstanceState) {
if (savedInstanceState != null) {
initBarState();
int[] themeIds = {R.style.theme_launch, R.style.theme_wangfei, R.style.theme_full_screen};
getWindow().setBackgroundDrawable(null);
mCurTheme = themeIds[savedInstanceState.getInt("theme")];
setTheme(mCurTheme);
reCreateView();
} else {
firstCreate();
switchTheme(1);
}
}
protected abstract void firstCreate();
protected abstract void reCreateView();
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
protected void initBarState() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {//透明状态栏
getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
}
}
/**
* @param themeID 0启动模式,1.主题模式 ,2.全屏模式
*/
public void switchTheme(final int themeID) {
mCurTheme = themeID;
recreate();
}
}
实现这个activity要重写两个方法,
public class AllA extends BaseA {
private AllVH allvh;
@Override
protected void firstCreate() {
}
@Override
protected void reCreateView() {
AAllBinding viewDataBinding = DataBindingUtil.setContentView(this, R.layout.a_all);
allvh = new AllVH(this);
viewDataBinding.setAllvh(allvh);
FunctionsF fragment = findFragment(FunctionsF.class);
if (fragment == null)
loadRootFragment(viewDataBinding.flContainer.getId(), FunctionsF.newInstance());
在第一个firstCreate()的时候调用app的初始化方法,第二个reCreateView()就可以加载界面了,因为直接加载首界面所以还需要
判断用户身份,这个时候如果身份不合法需要跳转登陆界面,这个跳转太快了,需要延时500ms(个人建议),否则背景容易重影;
fragment创建启动的时候,不能有太多的Obsevable变量刷新界面,否则界面的跳转可能会有抖动的现象
二。联网框架用的retrofit+rxjava,优点很明显代码逻辑清晰,可异步,快速
public class RetrofitUtils {
// public static final String baseUrl = "http://192111.168111.1111.1111:11111/firmware/";
private static Retrofit retrofit = null;
private static IRetrofitServer iServer;
private static Retrofit retrofit2 = null;
private static IRetrofitServer iServer2;
public static IRetrofitServer getInstance() {
if (retrofit == null) {
synchronized (RetrofitUtils.class) {
if (retrofit == null) {
// OkHttpClient mOkHttpClient=new OkHttpClient.Builder()
// .connectTimeout(HttpConfig.HTTP_TIME, TimeUnit.SECONDS)
// .readTimeout(HttpConfig.HTTP_TIME, TimeUnit.SECONDS)
// .writeTimeout(HttpConfig.HTTP_TIME, TimeUnit.SECONDS)
// .addInterceptor(InterceptorUtil.HeaderInterceptor())
// .addInterceptor(InterceptorUtil.LogInterceptor())//添加日志拦截器
// .build();
retrofit = new Retrofit.Builder()
.baseUrl("http://sd:dad/aasdfas/")
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())//添加rxjava转换器
.build();
iServer = retrofit.create(IRetrofitServer.class);
}
}
}
return iServer;
}
public static IRetrofitServer getInstance2(final ProgressListener progressListener) {
if (retrofit2 == null) {
synchronized (RetrofitUtils.class) {
if (retrofit2 == null) {
// OkHttpClient mOkHttpClient=new OkHttpClient.Builder()
// .connectTimeout(HttpConfig.HTTP_TIME, TimeUnit.SECONDS)
// .readTimeout(HttpConfig.HTTP_TIME, TimeUnit.SECONDS)
// .writeTimeout(HttpConfig.HTTP_TIME, TimeUnit.SECONDS)
// .addInterceptor(InterceptorUtil.HeaderInterceptor())
// .addInterceptor(InterceptorUtil.LogInterceptor())//添加日志拦截器
// .build();
OkHttpClient client = new OkHttpClient.Builder().addNetworkInterceptor(new Interceptor() {
@Override
public Response intercept(Chain chain) throws IOException {
Response response = chain.proceed(chain.request());
return response.newBuilder().body(new ProgressResponseBody(response.body(), progressListener)).build();
}
}).build();
retrofit2 = new Retrofit.Builder()
.client(client)
.baseUrl("http://114.215.171.48:8995/firmware/")
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())//添加rxjava转换器
.build();
iServer2 = retrofit2.create(IRetrofitServer.class);
}
}
}
return iServer2;
}
public interface IRetrofitServer {
//### 1. 获取token
@FormUrlEncoded
@POST("api/emply/Login")
Call<BaseResponse<Token>> getToken(@Field("param") String userPhone);
//### 2. 获取固件设备列表
@FormUrlEncoded
@POST("api/version/date")
Call<BaseResponse<ArrayList<Vertion>>> getDevices(@Field("token") String token, @Field("param") String code);
//### 3.下载固件
@GET
Call<ResponseBody> downFirmware(@Url String fileUrl);
// 如果你下载的文件很大,则使用
@Streaming
@GET
Call<ResponseBody> downloadFileWithDynamicUrlAsync(@Url String fileUrl);
}
其实一个实例就行了,有两个是因为有一个是测试下载大文件的,所以分开了
三。整体架构是app module指向多个子module,过个子module共同只想工具类module
除了app module是
apply plugin: 'com.android.application'
其他的都是
apply plugin: 'com.android.library'
module之间是单向继承关系,可以保证各个功能子module互不影响,同时公用一个util module可以同时公用所有公共资源类