Android 代码质量管理(代码篇)

简介: Android 代码质量管理(代码篇) 模板方法-基类封装 Activity和Fragment应该是Android最常用的组件,对他进行简单的封装对提高代码的简洁性也有很大的帮助。 BaseActivity : [java] view plain copy public abstr.

Android 代码质量管理(代码篇)

模板方法-基类封装

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

  • BaseActivity :

[java] view plain copy

  1. public abstract class BaseActivity extends FragmentActivity {
  2.     @Override
  3.     protected void onCreate(Bundle savedInstanceState) {
  4.         super.onCreate(savedInstanceState);
  5.         init();
  6.         findViews();
  7.         initData();
  8.         setListener();
  9.         setting();
  10.     }
  11.     /**
  12.      * 获得上下文
  13.      * @return Context
  14.      */
  15.     public Context getContext(){
  16.         return this;
  17.     }
  18.     /**
  19.      * 始化参数
  20.      */
  21.     public abstract void init();
  22.     /**
  23.      * 查找所有的控件
  24.      */
  25.     public abstract void findViews();
  26.     /**
  27.      * 初始化页面数据
  28.      */
  29.     public abstract void initData();
  30.     /**
  31.      * 设置控件的监听事件
  32.      */
  33.     public abstract void setListener();
  34.     /**
  35.      * 后续参数设置
  36.      */
  37.     public abstract void setting();
  38. }
  • BaseFragment :

[java] view plain copy

  1. public abstract class BaseFragment extends Fragment {
  2.     @Override
  3.     public void onCreate(Bundle savedInstanceState) {
  4.         super.onCreate(savedInstanceState);
  5.     }
  6.     @Override
  7.     public void onStart() {
  8.         super.onStart();
  9.         init();
  10.         findViews();
  11.         initData();
  12.         setListener();
  13.         setting();
  14.     }
  15.     public Context getContext() {
  16.         return getActivity();
  17.     }
  18.     public abstract void init();
  19.     public abstract void findViews();
  20.     public abstract void initData();
  21.     public abstract void setListener();
  22.     public abstract void setting();
  23. }

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

Fragment简单管理

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

[java] view plain copy

  1. private void showFragment(){
  2.     FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
  3.     hideFragment(fragmentTransaction);
  4.     if (mFragment1== null) {
  5.         mFragment1 = new MyFragment1(context);
  6.         fragmentTransaction.add(R.id.content, mFragment1);
  7.         fragmentTransaction.commit();
  8.     } else {
  9.         fragmentTransaction.show(mFragment1);
  10.         fragmentTransaction.commit();
  11.     }
  12. }

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

下面封装一下

[java] view plain copy

  1. public class FragmentFactory {
  2.     private FragmentActivity mContext;
  3.     private static FragmentFactory factory = new FragmentFactory();
  4.     //用于存储已创建的Fragment对象
  5.     private Map<String, Fragment> mFragmentMap=new HashMap<>();
  6.     private int mLayoutId;
  7.     private FragmentFactory() {
  8.     }
  9.     public static FragmentFactory getInstance() {
  10.         return factory;
  11.     }
  12.     //layoutId 传入布局文件的id
  13.     public FragmentFactory init(FragmentActivity context,int layoutId) {
  14.         this.mContext = context;
  15.         this.mLayoutId=layoutId;
  16.         return factory;
  17.     }
  18.     public Activity getParentActivity() {
  19.         return mContext;
  20.     }
  21.     private <T extends Fragment> Fragment createFragment(Class<T> clazz) {
  22.         Fragment fragment = null;
  23.         try {
  24.             fragment = getFragment(clazz.getName());
  25.             FragmentTransaction fragmentTransaction = mContext.getSupportFragmentManager().beginTransaction();
  26.             hideFragment(fragmentTransaction);
  27.             if (fragment == null) {
  28.                 fragment = (Fragment) clazz.newInstance();
  29.                 setFragment(fragment);
  30.                 fragmentTransaction.add(mLayoutId, fragment);
  31.                 fragmentTransaction.commit();
  32.             } else {
  33.                 fragmentTransaction.show(fragment);
  34.                 fragmentTransaction.commit();
  35.             }
  36.         } catch (InstantiationException e) {
  37.             e.printStackTrace();
  38.         } catch (IllegalAccessException e) {
  39.             e.printStackTrace();
  40.         }
  41.         return fragment;
  42.     }
  43.     private <T extends Fragment> Fragment getFragment(String className) {
  44.         Fragment fragment = mFragmentMap.get(className);
  45.         return fragment;
  46.     }
  47.     private <T extends Fragment> void setFragment(Fragment fragment) throws InstantiationException, IllegalAccessException {
  48.         String className = fragment.getClass().getName();
  49.         mFragmentMap.put(className, fragment);
  50.     }
  51.     private void hideFragment(FragmentTransaction fragmentTransaction) {
  52.         Set<String> keySet = mFragmentMap.keySet();
  53.         for (String key : keySet) {
  54.             Fragment fragment = mFragmentMap.get(key);
  55.             fragmentTransaction.hide(fragment);
  56.         }
  57.     }
  58.     public <T extends Fragment> T showFragment(Class<T> clazz) {
  59.         return (T) createFragment(clazz);
  60.     }
  61. }

 

调用代码:

[java] view plain copy

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

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

简单通用的适配器

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

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

[html] view plain copy

  1. public abstract class CommonAdapter<T> extends BaseAdapter {
  2.     //需要显示的数据,List中的类型为泛型,因为不知道用户的封装Bean
  3.     private List<T> mDatas;
  4.     private Context mContext;
  5.     //布局文件Id
  6.     private int mLayoutId;
  7.     public CommonAdapter(Context context,List<T> data,int layoutId) {
  8.         mDatas = data;
  9.         mContext = context;
  10.         mLayoutId = layoutId;
  11.     }
  12.     @Override
  13.     public int getCount() {
  14.         return mDatas.size();
  15.     }
  16.     @Override
  17.     public Object getItem(int position) {
  18.         return mDatas.get(position);
  19.     }
  20.     @Override
  21.     public long getItemId(int position) {
  22.         return position;
  23.     }
  24.     @Override
  25.     public View getView(int position, View convertView, ViewGroup parent) {
  26.         ViewHolder holder = ViewHolder.getHolder(mContext,convertView, parent, mLayoutId);
  27.         setDatas(holder,getItem(position));
  28.         return holder.getConvertView();
  29.     }
  30.     /**
  31.      * 为各个item中的控件设置数据
  32.      * @param holder   ViewHolder
  33.      * @param object  从集合中所取的一个对象
  34.      */
  35.     public abstract void setDatas(ViewHolder holder, Object object);
  36. }

[html] view plain copy

  1. public class ViewHolder {
  2.     private View mConvertView;
  3.     //用来存布局中的各个组件,以键值对形式
  4.     private HashMap<Integer,View> mViews = new HashMap<>();
  5.     //ViewHolder构造函数,只有当convertView为空的时候才创建
  6.     public ViewHolder(Context context,View convertView, ViewGroup parent, int layouId) {
  7.         convertView = LayoutInflater.from(context).inflate(layouId,parent,false);
  8.         convertView.setTag(this);       //将其setTag()
  9.         mConvertView = convertView;
  10.     }
  11.     //返回一个ViewHolder对象
  12.     public static ViewHolder getHolder(Context context, View convertView, ViewGroup parent, int layoutId) {
  13.         if (convertView == null) {
  14.             return new ViewHolder(context,convertView,parent,layoutId);
  15.         }else {
  16.             return (ViewHolder) convertView.getTag();
  17.         }
  18.     }
  19.     //返回一个View的子类对象,因为不确定用户布局有什么组件,相当于findViewById
  20.     //这里返回一个泛型,也可以返回一个View或Object
  21.     public <T extends View>T getView(int resId) {
  22.         View view = mViews.get(resId);  //从集合中取出这个组件
  23.         if (view == null) {         //如果为空,说明为第一屏
  24.             view = mConvertView.findViewById(resId);    //从convertView中找
  25.             mViews.put(resId,view);
  26.         }
  27.         return (T) view;
  28.     }
  29.     public View getConvertView() {
  30.         return mConvertView;
  31.     }
  32. }

调用代码:

[java] view plain copy

  1. public class MyAdapter extends CommonAdapter<Bean> {
  2.     public MyAdapter(Context context, List<Bean> data, int layoutId) {
  3.         super(context, data, layoutId);
  4.     }
  5.     @Override
  6.     public void setDatas(ViewHolder holder, Object object) {
  7.         Bean bean = (Bean) object;
  8.         ((TextView)holder.getView(R.id.title_Tv)).setText(bean.getTitle());
  9.         ((TextView)holder.getView(R.id.desc_Tv)).setText(bean.getDesc());
  10.         ((TextView)holder.getView(R.id.time_Tv)).setText(bean.getTime());
  11.         ((TextView)holder.getView(R.id.phone_Tv)).setText(bean.getPhone());
  12.     }
  13. }

[java] view plain copy

  1.     List<Bean> data=new ArrayList<>();
  2.     Bean bean=new Bean("标题1""内容1""时间1""18300000000");
  3.     Bean bean2=new Bean("标题2""内容2""时间2""18300000000");
  4.     data.add(bean);
  5.     data.add(bean2);
  6.     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\手机上都有可能不一样。

这时候把这些底层接口单独封装在一个类进行管理,在平台发生改变的时候只需要改变实现。

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

[java] view plain copy

  1. public interface IManager {
  2.     void setBackLight(int value);
  3.     void setPictureMode(int mode);
  4. }

实现类 1

[java] view plain copy

  1. public class HuaWeiManager implements IManager {
  2.     @Override
  3.     public void setBackLight(int value) {
  4.         <strong>HuaWei</strong>.savaBackLight(value);
  5.     }
  6.     @Override
  7.     public void setPictureMode(int mode) {
  8.         <strong>HuaWei</strong>.setPictureMode(mode);
  9.     }
  10. }

[java] view plain copy

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

[java] view plain copy

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

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

实现类 2

[java] view plain copy

  1. public class XiaoMiManager implements IManager {
  2.     @Override
  3.     public void setBackLight(int value) {
  4.         XiaoMi.savaBackLight(value);
  5.     }
  6.     @Override
  7.     public void setPictureMode(int mode) {
  8.         XiaoMi.setPictureMode(mode);
  9.     }
  10. }

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

[java] view plain copy

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

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

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

注重工具类的封装

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

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

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

坏习惯

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

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

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

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

好习惯

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

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

原文地址http://www.bieryun.com/3622.html

相关文章
|
20天前
|
安全 Java 网络安全
Android远程连接和登录FTPS服务代码(commons.net库)
Android远程连接和登录FTPS服务代码(commons.net库)
17 1
|
1月前
|
Android开发 Swift iOS开发
探索安卓与iOS开发的差异:从代码到用户体验
【10月更文挑战第5天】在移动应用开发的广阔天地中,安卓和iOS两大平台各占半壁江山。它们在技术架构、开发环境及用户体验上有着根本的不同。本文通过比较这两种平台的开发过程,揭示背后的设计理念和技术选择如何影响最终产品。我们将深入探讨各自平台的代码示例,理解开发者面临的挑战,以及这些差异如何塑造用户的日常体验。
|
2月前
|
存储 Java Android开发
🔥Android开发大神揭秘:从菜鸟到高手,你的代码为何总是慢人一步?💻
在Android开发中,每位开发者都渴望应用响应迅速、体验流畅。然而,代码执行缓慢却是常见问题。本文将跟随一位大神的脚步,剖析三大典型案例:主线程阻塞导致卡顿、内存泄漏引发性能下降及不合理布局引起的渲染问题,并提供优化方案。通过学习这些技巧,你将能够显著提升应用性能,从新手蜕变为高手。
27 2
|
3月前
|
JSON JavaScript 前端开发
Android调用Vue中的JavaScript代码
Android调用Vue中的JavaScript代码
34 3
|
3月前
|
安全 Java 网络安全
Android远程连接和登录FTPS服务代码(commons.net库)
很多文章都介绍了FTPClient如何连接ftp服务器,但却很少有人说如何连接一台开了SSL认证的ftp服务器,现在代码来了。
99 2
|
4月前
|
存储 Java Android开发
🔥Android开发大神揭秘:从菜鸟到高手,你的代码为何总是慢人一步?💻
【7月更文挑战第28天】在Android开发中,每位开发者都追求极致的用户体验。然而,“代码执行慢”的问题时常困扰着开发者。通过案例分析,我们可探索从新手到高手的成长路径。
39 3
|
3月前
|
Java Android开发
Android项目架构设计问题之要提升代码的可读性和管理性如何解决
Android项目架构设计问题之要提升代码的可读性和管理性如何解决
38 0
|
4月前
|
API Android开发
Android 监听Notification 被清除实例代码
Android 监听Notification 被清除实例代码
|
5月前
|
JavaScript 前端开发 Android开发
kotlin安卓在Jetpack Compose 框架下使用webview , 网页中的JavaScript代码如何与native交互
在Jetpack Compose中使用Kotlin创建Webview组件,设置JavaScript交互:`@Composable`函数`ComposableWebView`加载网页并启用JavaScript。通过`addJavascriptInterface`添加`WebAppInterface`类,允许JavaScript调用Android方法如播放音频。当页面加载完成时,执行`onWebViewReady`回调。
|
4月前
|
Web App开发 JavaScript 前端开发
Android端使用WebView注入一段js代码实现js调用android
Android端使用WebView注入一段js代码实现js调用android
102 0