Android重构(一)

重新规划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;
        }
    }
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值