浅析Android代码质量管理

模板方法-基类封装

Activity和Fragment应该是Android最常用的组件,对他进行简单的封装对提高代码的简洁性也有很大的帮助。

BaseActivity :

public abstract class BaseActivity extends FragmentActivity {

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		init();
		findViews();
		initData();
		setListener();
		setting();
	}

	/**
	 * 获得上下文
	 * @return Context
	 */
	public Context getContext(){
		return this;
	}

	/**
	 * 始化参数
	 */
	public abstract void init();
	/**
	 * 查找所有的控件
	 */
	public abstract void findViews();
	/**
	 * 初始化页面数据
	 */
	public abstract void initData();
	/**
	 * 设置控件的监听事件
	 */
	public abstract void setListener();

	/**
	 * 后续参数设置
	 */
	public abstract void setting();

}

BaseFragment :

public abstract class BaseFragment extends Fragment {

	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
	}

	@Override
	public void onStart() {
		super.onStart();
		init();
		findViews();
		initData();
		setListener();
		setting();
	}

	public Context getContext() {
		return getActivity();
	}

	public abstract void init();

	public abstract void findViews();

	public abstract void initData();

	public abstract void setListener();

	public abstract void setting();

}

代码比较简单,用到了模板设计模式,一个方法只做一样事情,初始化的就只做初始化操作,设置监听的就只设置监听。不管多少个Activity\Fragment都能很好的统一化编码风格,看起来更清晰不乱。

Fragment简单管理

下面先看看标准的创建和管理Fragment

private void showFragment(){
 FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
 hideFragment(fragmentTransaction);
 if (mFragment1== null) {
 mFragment1 = new MyFragment1(context);
 fragmentTransaction.add(R.id.content, mFragment1);
 fragmentTransaction.commit();
 } else {
 fragmentTransaction.show(mFragment1);
 fragmentTransaction.commit();
 }
} 

每次创建一个Fragment都要复制一边这个方法,代码冗余、不利于维护和更新。

下面封装一下

public class FragmentFactory { 

 private FragmentActivity mContext;
 private static FragmentFactory factory = new FragmentFactory();
 //用于存储已创建的Fragment对象
 private Map<String, Fragment> mFragmentMap=new HashMap<>();
 private int mLayoutId; 

 private FragmentFactory() {
 } 

 public static FragmentFactory getInstance() {
 return factory;
 } 

 //layoutId 传入布局文件的id
 public FragmentFactory init(FragmentActivity context,int layoutId) {
 this.mContext = context;
 this.mLayoutId=layoutId;
 return factory;
 } 

 public Activity getParentActivity() {
 return mContext;
 } 

 private <T extends Fragment> Fragment createFragment(Class<T> clazz) {
 Fragment fragment = null;
 try {
 fragment = getFragment(clazz.getName());
 FragmentTransaction fragmentTransaction = mContext.getSupportFragmentManager().beginTransaction();
 hideFragment(fragmentTransaction);
 if (fragment == null) { 

 fragment = (Fragment) clazz.newInstance();
 setFragment(fragment);
 fragmentTransaction.add(mLayoutId, fragment);
 fragmentTransaction.commit();
 } else {
 fragmentTransaction.show(fragment);
 fragmentTransaction.commit();
 }
 } catch (InstantiationException e) {
 e.printStackTrace();
 } catch (IllegalAccessException e) {
 e.printStackTrace();
 }
 return fragment;
 } 

 private <T extends Fragment> Fragment getFragment(String className) {
 Fragment fragment = mFragmentMap.get(className);
 return fragment;
 } 

 private <T extends Fragment> void setFragment(Fragment fragment) throws InstantiationException, IllegalAccessException {
 String className = fragment.getClass().getName();
 mFragmentMap.put(className, fragment);
 } 

 private void hideFragment(FragmentTransaction fragmentTransaction) {
 Set<String> keySet = mFragmentMap.keySet();
 for (String key : keySet) {
 Fragment fragment = mFragmentMap.get(key);
 fragmentTransaction.hide(fragment);
 } 

 } 

 public <T extends Fragment> T showFragment(Class<T> clazz) {
 return (T) createFragment(clazz);
 }
} 

调用代码:

FragmentFactory mFragmentFactory = FragmentFactory.getInstance().init(this, R.id.fl_content);
mFragmentFactory.showFragment(MyFragment1.class);
mFragmentFactory.showFragment(MyFragment2.class); 

上面的封装用到了泛型、工厂、单例等知识。只需要在Activity初始化一次对象就可以一行代码管理Fragment了,想显示哪个页面就传入对应的Fragment的class。

简单通用的适配器

ListView是Android最常用的一个组件,优化Litsview那就是必不可少的工作了。

用Listview最痛苦的就是写BaseAdapter的getView()方法,一遍又一遍的写,大部分代码都是重复冗余,但又不得不写。下面来抽取冗余的代码封装起来。

public abstract class CommonAdapter<T> extends BaseAdapter {
 //需要显示的数据,List中的类型为泛型,因为不知道用户的封装Bean
 private List<T> mDatas; 

 private Context mContext;
 //布局文件Id
 private int mLayoutId;
 public CommonAdapter(Context context,List<T> data,int layoutId) {
 mDatas = data;
 mContext = context;
 mLayoutId = layoutId;
 }
 @Override
 public int getCount() {
 return mDatas.size();
 } 

 @Override
 public Object getItem(int position) {
 return mDatas.get(position);
 } 

 @Override
 public long getItemId(int position) {
 return position;
 } 

 @Override
 public View getView(int position, View convertView, ViewGroup parent) {
 ViewHolder holder = ViewHolder.getHolder(mContext,convertView, parent, mLayoutId);
 setDatas(holder,getItem(position));
 return holder.getConvertView();
 } 

 /**
 * 为各个item中的控件设置数据
 * @param holder ViewHolder
 * @param object 从集合中所取的一个对象
 */
 public abstract void setDatas(ViewHolder holder, Object object);
} 
public class ViewHolder {
 private View mConvertView;
 //用来存布局中的各个组件,以键值对形式
 private HashMap<Integer,View> mViews = new HashMap<>();
 //ViewHolder构造函数,只有当convertView为空的时候才创建
 public ViewHolder(Context context,View convertView, ViewGroup parent, int layouId) {
 convertView = LayoutInflater.from(context).inflate(layouId,parent,false);
 convertView.setTag(this); //将其setTag()
 mConvertView = convertView;
 }
 //返回一个ViewHolder对象
 public static ViewHolder getHolder(Context context, View convertView, ViewGroup parent, int layoutId) {
 if (convertView == null) {
 return new ViewHolder(context,convertView,parent,layoutId);
 }else {
 return (ViewHolder) convertView.getTag();
 }
 }
 //返回一个View的子类对象,因为不确定用户布局有什么组件,相当于findViewById
 //这里返回一个泛型,也可以返回一个View或Object
 public <T extends View>T getView(int resId) {
 View view = mViews.get(resId); //从集合中取出这个组件
 if (view == null) { //如果为空,说明为第一屏
 view = mConvertView.findViewById(resId); //从convertView中找
 mViews.put(resId,view);
 }
 return (T) view;
 } 

 public View getConvertView() {
 return mConvertView;
 }
} 

调用代码:

public class MyAdapter extends CommonAdapter<Bean> {
 public MyAdapter(Context context, List<Bean> data, int layoutId) {
 super(context, data, layoutId);
 }
 @Override
 public void setDatas(ViewHolder holder, Object object) {
 Bean bean = (Bean) object;
 ((TextView)holder.getView(R.id.title_Tv)).setText(bean.getTitle());
 ((TextView)holder.getView(R.id.desc_Tv)).setText(bean.getDesc());
 ((TextView)holder.getView(R.id.time_Tv)).setText(bean.getTime());
 ((TextView)holder.getView(R.id.phone_Tv)).setText(bean.getPhone());
 }
} 
 List<Bean> data=new ArrayList<>();
 Bean bean=new Bean("标题1", "内容1", "时间1", "18300000000");
 Bean bean2=new Bean("标题2", "内容2", "时间2", "18300000000");
 data.add(bean);
 data.add(bean2);
 listView.setAdapter(new MyAdapter(context, data, R.layout.listview_item)); 

注释写的很清楚了,就不多说了。

自定义组合控,布局模块化

正常的项目开发中肯定有很多布局冗余例如下面图红框中的设置和导航。

很多人会把这些布局文件一遍又一遍的复制,只修改其中的ID、字符串等,其他部分几乎一模一样,造成布局文件代码特别多。

最要命的不是这个,而且把所有的逻辑写在Activity\Fragment里,造成Activity\Fragment特别的庞大,真正实现一坨X代码。

我觉得应该把公用的布局单独抽取出来到一个xml里,再用一个GroupView去处理这些逻辑和业务,减少activity\Fragment的负担。

代码就不贴了,自己去源码demo里查看ParamSwitchView,这个View是图1的一个Item,封装了布局和所需要的遥控按键左右切换数据的逻辑。

面向接口编程

面向接口编程的意思是指在面向对象的系统中所有的类或者模块之间的交互是由接口完成的。

父类的引用指向子类对象,指向不同的子类对象,产生不同的行为:

父 a =new 子A;

有很多童靴在项目开发中经常更变业务,例如:定制化系统应用,底层的接口在不同型号的TV\手机上都有可能不一样。
这时候把这些底层接口单独封装在一个类进行管理,在平台发生改变的时候只需要改变实现。

定义接口类统一化管理方法

public interface IManager { 

 void setBackLight(int value);
 void setPictureMode(int mode); 

} 

实现类 1

public class HuaWeiManager implements IManager { 

 @Override
 public void setBackLight(int value) {
 <strong>HuaWei</strong>.savaBackLight(value);
 } 

 @Override
 public void setPictureMode(int mode) {
 <strong>HuaWei</strong>.setPictureMode(mode);
 } 

} 

假如现在业务需求是华为的定制系统,只需要调用华为的子类

IManager iManager=new HuaWeiManager();
iManager.setBackLight(100); 

如果业务需求转变成小米,那么只需要创建一个类进行实现

实现类 2

public class XiaoMiManager implements IManager { 

 @Override
 public void setBackLight(int value) {
 XiaoMi.savaBackLight(value);
 } 

 @Override
 public void setPictureMode(int mode) {
 XiaoMi.setPictureMode(mode);
 } 

} 

调用代码里只需要把HuaWeiManager改成XiaoMiManager就能适配其他机型了。

//IManager iManager=new HuaWeiManager();
IManager iManager=new XiaoMiManager();
iManager.setBackLight(100); 

在这里只是灌输一个编码思维,实际开发中突发情况比较多,并不一定全部适用。

在编码之前一定要花一点点时间简单构思和组织一下代码,不要想到什么写什么。

注重工具类的封装

我们正常的开发中经常用到很多不需要在逻辑层编写的方法,我们就可以单独的把他抽取出来放在单独的类里面去单独管理。

例如:Toast 、SharePreference、获取时间、系统版本、网络、MD5等等。。。。

这些东西都可以单独的封装和管理,减少逻辑层的代码,并且也可以让其他逻辑层调用。

坏习惯

有些人喜欢把定义个Tools这样的工具类,里面存放着所有的工具方法。

1. 网络、Toast、状态、时间等等全部都用一个类去管理,这样造成的后果就是后期不方便维护和不利于更新,代码看起来杂乱无章。

2. 把一些公共的方法直接在逻辑层构建,其他地方需要就直接复制一份过去。

或者有其他相同的比较类似的方法没有进行封装,在其他地方直接复制过去只修改其他一行的代码。

好习惯

1. 把这些tools单独创建各种各样的tools去存放这些方法,Toast只存Toast相关的,网络只存网络相关的,避免交杂在一起。也符合设计原则之一的:单一原则。

2. 类似的方法独立抽取出来,用传参flag标记去区分应用场景。

源码里收藏了一些常用的工具类分享给大家。

MVP分层架构

去年写了一篇关于它的文章,大家可以看看。能够让代码变得异常的清晰。

//www.jb51.net/article/98422.htm

改善代码的方式很多很多,一下子想不完,后面想到了什么再继续更新分享。

(0)

相关推荐

  • Android 采用AOP方式封装6.0权限管理的方法

    [一]背景 6.0运行时申请权限已经是一个老生常谈的内容了,最近项目TargetSDKVersion升到23以上,所以我们也需要做权限管理,我想到的需求是这样的: 1.支持单个权限.多个权限申请 2.运行时申请 3.无侵入式申请,无需关注权限申请的逻辑 4.除了Activity.Fragment之外,还需要支持Service中申请 5.对国产手机做兼容处理 第一.二点,Google都有对应的API: 第三点可以通过自定义注解+AOP切面方式来解决.为什么采用AOP方式呢?首先看AOP定义: 面向

  • 浅谈Android中线程池的管理

    说到线程就要说说线程机制 Handler,Looper,MessageQueue 可以说是三座大山了 Handler Handler 其实就是一个处理者,或者说一个发送者,它会把消息发送给消息队列,也就是Looper,然后在一个无限循环队列中进行取出消息的操作 mMyHandler.sendMessage(mMessage); 这句话就是我耗时操作处理完了,我发送过去了! 然后在接受的地方处理!简单理解是不是很简单. 一般我们在项目中异步操作都是怎么做的呢? // 这里开启一个子线程进行耗时操作

  • Android源代码仓库及其管理工具Repo分析详解

    软件工程由于需要不断迭代开发,因此要对源代码进行版本管理.Android源代码工程(AOSP)也不例外,它采用Git来进行版本管理.AOSP作为一个大型开放源代码工程,由许许多多子项目组成,因此不能简单地用Git进行管理,它在Git的基础上建立了一套自己的代码仓库,并且使用工具Repo进行管理.工欲善其事,必先利其器.本文就对AOSP代码仓库及其管理工具repo进行分析,以便提高我们日常开发效率. <Android系统源代码情景分析>--点击下载 现代的代码版本管理工具,SVN和Git是最流行

  • Android实现电池管理系统

    一.Android 电池服务 Android电池服务,用来监听内核上报的电池事件,并将最新的电池数据上报给系统,系统收到新数据后会去更新电池显示状态.剩余电量等信息.如果收到过温报警和低电报警,系统会自动触发关机流程,保护电池和机器不受到危害. Android电池服务的启动和运行流程: Android 电池服务的源码结构 Framework\base\services\java\com\android\server         ├── SystemServer.java           

  • 直接可用的Android studio学生信息管理系统

    百度上流传最广的版本有所欠缺,并不能直接使用,同时有很多不必要的功能,这是我进行删减.修改.核查后的版本,根据下面的步骤一步步来直接能够运行程序. 本程序实现的功能是增删改查以及全选 首先是程序提纲 主要部分是java文件和xml文件. activity放在java文件里面,xml文件就是布局文件,用来规定界面的显示格式. 类定义的Java文件 StudentDao StudnetDBHelper Student TableContanst 其他文件 string .xml color.xml

  • Android版学生管理系统

    用户可以输入姓名.性别.年龄三个字段,通过点击添加学生按钮,将学生信息展示到开始为空的ScrollView控件中,ScrollView控件只能包裹一个控件,我这里包裹的是LinearLayout.点击保存数据按钮将数据通过XmlSerializer对象将数据保存到sd卡中,当点击恢复数据按钮时将sd卡文件中的数据读取出来回显到ScrollView中.大概功能就是这样的,下面我们来看看具体的代码吧. 因为要读写文件,所以要在清单文件中添加两个权限: <uses-permission android

  • 详解Android使用Gradle统一配置依赖管理

    在介绍使用 Gradle 统一配置依赖管理前我们先来简单介绍一下 Gradle, Gradle 是一个基于 JVM 的构建工具,也是一款非常灵活强大的构建工具,支持  jcenter.maven.Ivy 仓库,支持传递性依赖管理(即 A 依赖 B,B 依赖 C,那么 A 也就可以依赖 C,不用再单独去依赖),而不需要远程仓库或者是 pom.xml 和 ivy.xml 配置文件,抛弃了各种繁琐,基于 Groovy,build 脚本使用 Groovy 编写 而在我们的 Android studio

  • 浅析Android代码质量管理

    模板方法-基类封装 Activity和Fragment应该是Android最常用的组件,对他进行简单的封装对提高代码的简洁性也有很大的帮助. BaseActivity : public abstract class BaseActivity extends FragmentActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); ini

  • 浅析Android手机卫士关闭自动更新

    推荐阅读: 浅析Android手机卫士自定义控件的属性 保存数据的四种方式,网络,广播提供者,SharedPreferences,数据库 获取SharedPreferences对象,通过getSharedPreferences()方法,参数:名称,模式 例如config,MODE_PRIVATE 调用SharedPreferences对象的edit()方法,得到Editor对象 调用Editor对象的putBoolean()方法,放入布尔数据,参数:键值对,"update" false

  • 深入浅析Android Fragment(下篇)

    在上篇文章给大家介绍深入浅析Android Fragment(上篇),包括一些基本的用法和各种API,如果还想深入学习请继续关注本篇文章. 本篇将介绍上篇提到的:如何管理Fragment回退栈,Fragment如何与Activity交互,Fragment与Activity交互的最佳实践,没有视图的Fragment的用处,使用Fragment创建对话框,如何与ActionBar,MenuItem集成等~~ 1.管理Fragment回退栈 类似与Android系统为Activity维护一个任务栈,我

  • 深入浅析 Android Fragment(上篇)

    自从Fragment出现,曾经有段时间,感觉大家谈什么都能跟Fragment谈上关系,做什么都要问下Fragment能实现不~~~哈哈,是不是有点过~~~ 为了让界面可以在平板上更好地展示,Android在3.0版本引入了Fragment(碎片)功能,它非常类似于Activity,可以像Activity一样包含布局.Fragment通常是嵌套在Activity中使用的,现在想象这种场景:有两个Fragment,Fragment 1包含了一个ListView,每行显示一本书的标题.Fragment

  • 浅析Android中常见三种弹框在项目中的应用

    一丶概述 弹框在Android项目中经常出现,常见的实现方法有三种:Dialog 弹框,Window弹框,Activity伪弹框.本文就说一说三种弹框的实现及在项目中的运用. 二丶演示图         图一为常见的三种弹框(文末上链接),图二为项目中用到的Activity伪弹框 三丶正文 1.Dialog弹框 先看一篇一篇文章: android 8种对话框(Dialog)使用方法汇总 Dialog是系统自带的弹框,然而常常因为UI不好看而遭嫌弃,常需要自定义 public class MyDi

  • 浅析Android手机卫士之手机实现短信指令获取位置

    推荐阅读: 浅析Android手机卫士sim卡绑定 深入浅析Android手机卫士保存密码时进行md5加密 详解Android 手机卫士设置向导页面 浅析Android手机卫士关闭自动更新 浅析Android手机卫士自定义控件的属性 浅析Android手机卫士读取联系人 浅析Android手机卫士接收短信指令执行相应操作 浅析Android手机卫士手机定位的原理 获取位置 新建一个service的包 新建一个GPSService类继承系统的Service类 清单文件中注册一下 重写onCreat

  • 浅析Android手机卫士手机定位的原理

    推荐阅读: 浅析Android手机卫士sim卡绑定 深入浅析Android手机卫士保存密码时进行md5加密 详解Android 手机卫士设置向导页面 浅析Android手机卫士关闭自动更新 浅析Android手机卫士自定义控件的属性 浅析Android手机卫士读取联系人 浅析Android手机卫士接收短信指令执行相应操作 手机定位的三种方式:网络定位,基站定位,GPS定位 网络定位,手机连上wifi 2g 3g的时候,手机会有一个ip,误差很大 基站定位,精确度与基站的多少有关,几十米到几公里的

  • 浅析Android中getWidth()和getMeasuredWidth()的区别

    结论:getMeasuredWidth()获取的是view原始的大小,也就是这个view在XML文件中配置或者是代码中设置的大小.getWidth()获取的是这个view最终显示的大小,这个大小有可能等于原始的大小也有可能不等于原始大小. 1.getMeasuredWidth 从源码上来看,getMeasuredWidth()获取的是mMeasuredWidth的这个值.这个值是一个8位的十六进制的数字,高两位表示的是这个measure阶段的Mode的值,具体可以查看MeasureSpec的原理

  • 浅析Android Service中实现弹出对话框的坑

    一.手机版本问题,大多数文章没有涉及这个点,导致他们的代码并无法正常使用 M版本以上需要使用的Type--> TYPE_APPLICATION_OVERLAY AlertDialog.Builder builder=new AlertDialog.Builder(getApplicationContext()); builder.setTitle("提示"); builder.setMessage("service弹框"); builder.setNegati

  • 浅析Android文件存储

    一.内部存储 内部存储,位于data/data/包名/路径下 是否需要用户权限:否 是否能被其他应用访问:否 卸载应用数据是否被删除:是 内部存储控件不需要用户权限,这意味着我们不需要用户去授权下面的权限: android.permission.WRITE_EXTERNAL_STORAGE android.permission.READ_EXTERNAL_STORAGE 对于设备中每一个安装的 App,系统都会在 data/data 目录下以应用程序包名自动创建与之对应的文件夹,可以直接读写该目

随机推荐