热门标签 | HotTags
当前位置:  开发笔记 > Android > 正文

浅析Android代码质量管理

本篇文章给大家分享了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 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  Fragment createFragment(Class 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  Fragment getFragment(String className) { 
 Fragment fragment = mFragmentMap.get(className); 
 return fragment; 
 } 
 
 private  void setFragment(Fragment fragment) throws InstantiationException, IllegalAccessException { 
 String className = fragment.getClass().getName(); 
 mFragmentMap.put(className, fragment); 
 } 
 
 private void hideFragment(FragmentTransaction fragmentTransaction) { 
 Set keySet = mFragmentMap.keySet(); 
 for (String key : keySet) { 
 Fragment fragment = mFragmentMap.get(key); 
 fragmentTransaction.hide(fragment); 
 } 
 
 } 
 
 public  T showFragment(Class 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 extends BaseAdapter { 
 //需要显示的数据,List中的类型为泛型,因为不知道用户的封装Bean 
 private List mDatas; 
 
 private Context mContext; 
 //布局文件Id 
 private int mLayoutId; 
 public CommonAdapter(Context context,List 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 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 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 { 
 public MyAdapter(Context context, List 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 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) { 
 HuaWei.savaBackLight(value); 
 } 
 
 @Override 
 public void setPictureMode(int mode) { 
 HuaWei.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分层架构

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

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

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


推荐阅读
  • 本文探讨了在Android应用中实现动态滚动文本显示控件的优化方法。通过详细分析焦点管理机制,特别是通过设置返回值为`true`来确保焦点不会被其他控件抢占,从而提升滚动文本的流畅性和用户体验。具体实现中,对`MarqueeText.java`进行了代码层面的优化,增强了控件的稳定性和兼容性。 ... [详细]
  • 本文详细解析了JSONP(JSON with Padding)的跨域机制及其工作原理。JSONP是一种通过动态创建``标签来实现跨域请求的技术,其核心在于利用了浏览器对``标签的宽松同源策略。文章不仅介绍了JSONP的产生背景,还深入探讨了其具体实现过程,包括如何构造请求、服务器端如何响应以及客户端如何处理返回的数据。此外,还分析了JSONP的优势和局限性,帮助读者全面理解这一技术在现代Web开发中的应用。 ... [详细]
  • 通过整合JavaFX与Swing,我们成功地将现有的Swing应用程序组件进行了现代化改造。此次升级不仅提升了用户界面的美观性和交互性,还确保了与原有Swing应用程序的无缝集成,为开发高质量的Java桌面应用提供了坚实的基础。 ... [详细]
  • 本文介绍了Android动画的基本概念及其主要类型。Android动画主要包括三种形式:视图动画(也称为补间动画或Tween动画),主要通过改变视图的属性来实现动态效果;帧动画,通过顺序播放一系列预定义的图像来模拟动画效果;以及属性动画,通过对对象的属性进行平滑过渡来创建更加复杂的动画效果。每种类型的动画都有其独特的应用场景和实现方式,开发者可以根据具体需求选择合适的动画类型。 ... [详细]
  • 通过优化模板消息机制,本研究提出了一种高效的信息化推送方案。该方案利用获取的访问令牌(access token)和指定的模板ID,实现了精准且快速的信息推送,显著提升了用户体验和信息传递效率。具体实现中,通过调用相关API接口,确保了消息的准确性和及时性,为用户提供更加便捷的服务。 ... [详细]
  • 通过自定义 `TextView`,实现了在用户点击或焦点变化时动态调整字体颜色的效果。该方法利用了 `ColorStateList` 和 `Selector` 资源文件,确保了界面交互的流畅性和视觉效果的提升。具体实现中,通过重写 `onTouchEvent` 和 `onFocusChanged` 方法,精确控制了颜色变化的时机和状态。此外,还对性能进行了优化,确保在高频率操作下依然保持高效响应。 ... [详细]
  • 如何在Oracle ASM_Diskgroup中重命名现有磁盘
    如何在Oracle ASM_Diskgroup中重命名现有磁盘 ... [详细]
  • 本文深入探讨了 iOS 开发中 `int`、`NSInteger`、`NSUInteger` 和 `NSNumber` 的应用与区别。首先,我们将详细介绍 `NSNumber` 类型,该类用于封装基本数据类型,如整数、浮点数等,使其能够在 Objective-C 的集合类中使用。通过分析这些类型的特性和应用场景,帮助开发者更好地理解和选择合适的数据类型,提高代码的健壮性和可维护性。苹果官方文档提供了更多详细信息,可供进一步参考。 ... [详细]
  • 解决基于XML配置的MyBatis在Spring整合中出现“无效绑定语句(未找到):com.music.dao.MusicDao.findAll”问题的方法
    在将Spring与MyBatis进行整合时,作者遇到了“无效绑定语句(未找到):com.music.dao.MusicDao.findAll”的问题。该问题主要出现在使用XML文件配置DAO层的情况下,而注解方式配置则未出现类似问题。作者详细分析了两个配置文件之间的差异,并最终找到了解决方案。本文将详细介绍问题的原因及解决方法,帮助读者避免类似问题的发生。 ... [详细]
  • 从零起步:使用IntelliJ IDEA搭建Spring Boot应用的详细指南
    从零起步:使用IntelliJ IDEA搭建Spring Boot应用的详细指南 ... [详细]
  • 本文深入探讨了原型模式在软件设计中的应用与实现。原型模式通过使用已有的实例作为原型来创建新对象,而不是直接通过类实例化。这种方式不仅简化了对象的创建过程,还提高了系统的灵活性和效率。具体来说,原型模式涉及一个支持克隆功能的接口或基类,子类通过实现该接口来提供具体的克隆方法,从而实现对象的快速复制。此外,文章还详细分析了原型模式的优缺点及其在实际项目中的应用场景,为开发者提供了实用的指导和建议。 ... [详细]
  • Android 图像色彩处理技术详解
    本文详细探讨了 Android 平台上的图像色彩处理技术,重点介绍了如何通过模仿美图秀秀的交互方式,利用 SeekBar 实现对图片颜色的精细调整。文章展示了具体的布局设计和代码实现,帮助开发者更好地理解和应用图像处理技术。 ... [详细]
  • xStream 1.4.14 升级至 1.4.16 后无法解析包含井号 (#) 的 Map 键值问题分析与解决 ... [详细]
  • Spring框架入门指南:专为新手打造的详细学习笔记
    Spring框架是Java Web开发中广泛应用的轻量级应用框架,以其卓越的功能和出色的性能赢得了广大开发者的青睐。本文为初学者提供了详尽的学习指南,涵盖基础概念、核心组件及实际应用案例,帮助新手快速掌握Spring框架的核心技术与实践技巧。 ... [详细]
  • 当前,众多初创企业对全栈工程师的需求日益增长,但市场中却存在大量所谓的“伪全栈工程师”,尤其是那些仅掌握了Node.js技能的前端开发人员。本文旨在深入探讨全栈工程师在现代技术生态中的真实角色与价值,澄清对这一角色的误解,并强调真正的全栈工程师应具备全面的技术栈和综合解决问题的能力。 ... [详细]
author-avatar
sdr700724
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有