重新规划Android项目结构
我的切身感受是,无论是什么App开发人员都喜欢把所有的代码、类放在一个项目下,甚至将Acitvity和adapter放在一个Package下,或者将Adapter内置在Activity中。相当于一个房间里既有餐桌又有马桶,床上还放着酱油瓶。
我们需要重新归法目录结构,分两部走:
将与业务逻辑无关的逻辑放到AndroidLib
activity包中存放的主要是与业务无关的Acitivity基类。是App中AppBaseAcitivity的父类;
net包中存放的是网络底层封装,比如AsyncTask
cache包中存放的是缓存数据和图片的相关处理
ui中存放的是自定义控件
utils中存放的是业务无关的公用类,例如SharedPreferences的封装
业务相关的放到业务(这里是Heart,一般是app的名字)的包下
activity:我们按模块继续拆分,将不同模块的activity划分到不同的包下
adapter:将所有的适配器都放到一起
entity:将所有实体(只有属性,没有业务逻辑方法的类)放到一起
db:sqlite相关的逻辑
engine:业务相关的类
ui:自定义控件
utils:所有的公共方法
interfaces:真正意义上的接口,I开头
listener:基于Listener接口,On开头
作用
1.每个文件爱你只有一个单独的类,没有嵌套类,比如在acitivity中嵌套adapter entity
2.将acitivity按照模块拆分归类后,可以迅速的定位到一个具体的页面.
3.开发人员按照模块划分后,每个开发人员都只负责自己的那个包,开发边界线很清晰
为Acitivity定义新的生命周期
public abstract class BaseAcitivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
initVariables();
initViews(savedInstanceState);
loadData();
}
//初始化变量,包括Intent带过来的数据和acitivity的中数据
protected abstract void initVariables();
//加载布局,初始化控件,为控件设置监听器
protected abstract void initViews(Bundle savedInstanceState);
//调用API获取数据
protected abstract void loadData();
}
统一事件编程模型
一般来说,一个点击事件我们会
button.setOnClickListener(this);
@Override
public void onClick(View v) {
switch (v.getId()){
//todo
}
}
但这样需要使用switch case语句对值进行怕暖,也会扰乱面向对象的编程风格
所以更推荐
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
go2lastActivity();
}
});
//使用私有方法,来避免onClick方法过于臃肿
private void go2lastActivity() {
//todo
}
实体化编程
原生解析
仍然有许多android开发人员,他们的项目是不使用实体化编程的,他们在获取mobileAPI网络请求返回JSON数据时,使用JSONObject/JSONArray来承载数据,然后把返回的数据当作一个字典,根据键来取出相应的值.
//原生JSON解析
try {
JSONObject jsonObject = new JSONObject("json数据");
JSONObject weatherinfo = jsonObject.getJSONObject("weatherinfo");
String string = weatherinfo.getString("key1");
int anInt = weatherinfo.getInt("key2");
} catch (JSONException e) {
e.printStackTrace();
}
这样的写法有两个问题:
1.根据key来取值value,我们可以认为这是一个字典,同样的功能实现,字典比实体更会泽难懂,容易产生bug
2.每次都要手动从jsonObjecy中取值,繁琐
fastJson
Gradle:
compile 'com.alibaba:fastjson:1.2.36'
//2.创建对应的实体类javabean
T instance = JSON.parseObject("", T.class);
谨慎有个坑:
1.加了annatation的实体属性,使用一崩溃
2.当有泛型的使用,一使用就崩溃
在调试的时候没事,可是每次打签名混淆包就会出席那上述问题
最后发现是混淆文件缺了以下两行代码导致的
-keepattributes Signature //避免混淆泛型
-keepattributes *Annotation*//避免混淆注解
GSON
gradle
compile 'com.google.code.gson:gson:2.6.2'
//创建实体javabean
Gson gson = new Gson();
T t = gson.fromJson("", T.class);
自动创建实体类的第三方插件
Gsonformat
将json字符串传入即可
在页面跳转中使用实体
public class GlobalVariables{
public static T t;
}
//在Acitivity中
GlobalVariables.T=xxx;
但这样使用有很大风险,app一旦被切换到后台,有可能回收,当app再次回到前台时候可能出现异常
所以即使要使用全局变量进行数据的传递,就一定要把他们序列化到本地
进阶版:
使用Intent传递,妥妥的
Adapter模版
public abstract class MyBaseAdapter<T> extends BaseAdapter {
//在构造器中初始化两个属性,数据和context
ArrayList<T> mList;
BaseAcitivity context;
public MyBaseAdapter(ArrayList<T> list, BaseAcitivity context) {
mList = list;
this.context = context;
}
@Override
public int getCount() {
return mList!=null?mList.size():0;
}
@Override
public T getItem(int position) {
return mList.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public abstract View getView(int position, View convertView, ViewGroup parent);
}
但实际上,每个adapter最好有一个自己的viewholder,可以大大提高复用性,
接下来对viewholder进行抽取
public abstract class MyBaseAdapter<T,VH extends MyBaseAdapter.ViewHolder> extends BaseAdapter {
//在构造器中初始化两个属性,数据和context
public ArrayList<T> mList;
public Context context;
public VH mHolder;
public MyBaseAdapter(ArrayList<T> list, Context context) {
mList = list;
this.context = context;
mHolder=initViewHolder();
}
//必须实现的代码,用来设置viewholder的类型
public abstract VH initViewHolder();
@Override
public int getCount() {
return mList!=null?mList.size():0;
}
@Override
public T getItem(int position) {
return mList.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public abstract View getView(int position, View convertView, ViewGroup parent);
//容器来
public abstract class ViewHolder{}
}
那么其子类就不需要实现那么多方法了,同时也自定义了viewholder
public class lvAdapter extends MyBaseAdapter<String,lvAdapter.MyViewHolder>{
public lvAdapter(ArrayList list, MainActivity context) {
super(list, context);
}
@Override
public MyViewHolder initViewHolder() {
return new MyViewHolder();
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView==null){
convertView = LayoutInflater.from(parent.getContext()).inflate(android.R.layout.simple_list_item_1, parent, false);
mHolder.tv= (TextView) convertView.findViewById(android.R.id.text1);
convertView.setTag(mHolder);
}else{
mHolder= (MyViewHolder) convertView.getTag();
}
mHolder.tv.setText(mList.get(position));
return convertView;
}
//自定义的viewholder
public class MyViewHolder extends MyBaseAdapter.ViewHolder{
TextView tv;
}
}