1 类图

在【FJU项目】1像素进程保活(二)中,涉及到的几个类的类图如下所示(仅供参考):

实线箭头:关联

虚线箭头:依赖

重构前UML类图在上图中,OnePixelManager里面有太多的职责,违背了单一职责原则。里面还有很多地方违背了其它的设计原则,稍后通过代码进行分析。

2 代码分析

2.1 之前的OnePixelManager类源码如下:

package com.yds.jianshu.onepixel;

import android.app.Activity;

import android.content.Context;

import android.content.Intent;

import android.content.IntentFilter;

import java.lang.ref.WeakReference;

public class OnePixelManager {

private static final String TAG = "[OnePixelManager]";

private WeakReference mActivity;

private OnePixelReceiver onePixelReceiver;

/**

* 一像素广播接收者注册方法。该方法中初始化OnePixelReceiver,并添加了过滤条件

* 屏幕息屏和亮屏。然后注册该广播接收者

* @param context

*/

public void registerOnePixelReceiver(Context context){

IntentFilter filter = new IntentFilter();

filter.addAction(Intent.ACTION_SCREEN_OFF);

filter.addAction(Intent.ACTION_SCREEN_ON);

onePixelReceiver = new OnePixelReceiver();

context.registerReceiver(onePixelReceiver,filter);

}

/**

* 对广播接收者进行解注册

* @param context

*/

public void unregisterOnePixelReceiver(Context context){

if (null != onePixelReceiver){

context.unregisterReceiver(onePixelReceiver);

}

}

/**

* 开启一像素Activity

* @param context

*/

public void startOnePixelActivity(Context context){

Intent intent = new Intent();

intent.setClass(context,OnePixelActivity.class);

context.startActivity(intent);

}

/**

* 关闭一像素Activity

*/

public void finishOnePixelActivity(){

if(null!=mActivity){

Activity activity = mActivity.get();

if(null!=activity){

activity.finish();

}

mActivity = null;

}

}

/**

* 使用弱引用获取一像素的上下文

* @param activity

*/

public void setKeepAliveReference(OnePixelActivity activity){

mActivity = new WeakReference(activity);

}

}

上述代码中,总共有5个方法,但是职责却不是单一的,上述方法的作用如下:

registerOnePixelReceiver:一像素广播接收者注册方法。该方法中初始化OnePixelReceiver,并添加了过滤条件屏幕息屏和亮屏。然后注册该广播接收者

unregisterOnePixelReceiver:对广播接收者进行解注册

startOnePixelActivity:开启一像素Activity

finishOnePixelActivity:关闭一像素Activity

setKeepAliveReference:使用弱引用获取一像素的上下文

上述可以大致分为两个职责,一个是对Activity进行管理,一个是对广播接收者进行管理,但上述代码将其封装到了一个类中,不利于扩展,且耦合度比较高。所以可以将其拆分成两个管理类,一个用于管理Activity的ActivityManager,一个用于管理Receiver的ReceiverManager类。

2.2 写一个Manager接口,预留后用

package com.yds.jianshu.itf;

/**

* Created by yds

* on 2019/8/2.

*/

public interface Manager {

//预留接口

}

写一个抽象ActivityManager类

package com.yds.jianshu.manager;

import android.app.Activity;

import android.content.Context;

import com.yds.jianshu.itf.Manager;

import com.yds.jianshu.utils.ObjectUtil;

/**

* Created by yds

* on 2019/8/2.

*/

public abstract class ActivityManager implements Manager {

public abstract void startActivity(Context context);

public void finishActivity(Activity activity){

ObjectUtil.requireNonNull(activity,"activity is null");

activity.finish();

}

}

一般Activity有两种最常用的行为,一个是开启Activity,一个是关闭Activity,开启Activity可以根据其需求写具体的代码,所以这里将其设置为抽象类型,关闭Activity几乎是通用的,这里就在抽象类里实现。

2.3 具体的Activity管理类OnePixelActivityManager

package com.yds.jianshu.manager;

import android.app.Activity;

import android.content.Context;

import android.content.Intent;

import com.yds.jianshu.onepixel.OnePixelActivity;

import com.yds.jianshu.utils.ObjectUtil;

import java.lang.ref.WeakReference;

/**

* Created by yds

* on 2019/8/2.

*/

public class OnePixelActivityManager extends ActivityManager {

private WeakReference mActivity;

/**

* 将{@link OnePixelActivity}的引用保存起来,用于后面监测到屏幕亮时关闭{@link OnePixelActivity},

* 使用弱引用,是因为如果O{@link OnePixelActivity}被回收了,那么就不需要再保存该对象的引用用于

* finish了

* @param activity

*/

public void registerActivityReference(Activity activity){

ObjectUtil.requireNonNull(activity,"activity is null");

mActivity = new WeakReference(activity);

}

@Override

public void startActivity(Context context) {

ObjectUtil.requireNonNull(context,"context is null");

Intent intent = new Intent();

intent.setClass(context, OnePixelActivity.class);

context.startActivity(intent);

}

public void finishOnePixelActivity(){

ObjectUtil.requireNonNull(mActivity,"mActivity is null");

Activity activity = mActivity.get();

ObjectUtil.requireNonNull(activity,"activity is null");

finishActivity(activity);

mActivity = null;

}

}

2.4 用于管理BroadcastReceiver的类

package com.yds.jianshu.manager;

import android.content.BroadcastReceiver;

import android.content.Context;

import com.yds.jianshu.itf.Manager;

/**

* Created by yds

* on 2019/8/2.

*/

public abstract class ReceiverManager implements Manager {

public BroadcastReceiver receiver;

public abstract void register(Context context);

public abstract void unregister(Context context);

public void createReceiver(BroadcastReceiver receiver){

this.receiver = receiver;

}

}

广播接收者一般有两个行为,一个是注册,一个是取消注册。因为注册和取消注册,都需要创建具体的Receiver实例,所以可以将其提取到父类中。

2.5 用于管理1像素receiver的OnePixelReceiverManager

package com.yds.jianshu.manager;

import android.content.Context;

import android.content.Intent;

import android.content.IntentFilter;

import com.yds.jianshu.onepixel.OnePixelReceiver;

import com.yds.jianshu.utils.ObjectUtil;

/**

* Created by yds

* on 2019/8/2.

*/

public class OnePixelReceiverManager extends ReceiverManager {

public OnePixelReceiverManager(){

createReceiver(new OnePixelReceiver());

}

@Override

public void register(Context context) {

ObjectUtil.requireNonNull(context,"context is null");

ObjectUtil.requireNonNull(receiver,"receiver is null");

IntentFilter filter = new IntentFilter();

filter.addAction(Intent.ACTION_SCREEN_OFF);

filter.addAction(Intent.ACTION_SCREEN_ON);

context.registerReceiver(receiver,filter);

}

@Override

public void unregister(Context context) {

ObjectUtil.requireNonNull(context,"context is null");

ObjectUtil.requireNonNull(receiver,"receiver is null");

context.unregisterReceiver(receiver);

}

}

上述代码符合单一职责原则,单一职责原则有如下定义:

单一职责原则:一个对象应该只包含单一的职责,并且该职责被完整封装在一个类中。

上述OnePixelReceiverManager符合单一职责,它主要是对OnePixelReceiver进行相关操作管理;OnePixelActivityManager 也符合单一职责,它主要是对OnePixelActivity进行相关管理。

上述代码中,有这么一段代码:

public class OnePixelReceiverManager extends ReceiverManager {

public OnePixelReceiverManager(){

createReceiver(new OnePixelReceiver());

}

}

public abstract class ReceiverManager implements Manager {

public BroadcastReceiver receiver;

public void createReceiver(BroadcastReceiver receiver){

this.receiver = receiver;

}

}

ReceiverManager 的createReceiver的参数是BroadcastReceiver ,在ReceiverManager的子类OnePixelReceiverManager 中调用createReceiver时,用OnePixelReceiver实例化了BroadcastReceiver,这符合里氏代换原则,其定义如下:

里氏代换原则:所有引用基类的地方必须能透明地使用其子类的对象。

在里氏代换原则中,应该将父类设计为抽象类或者接口,让子类继承父类或实现父接口,并实现在父类中声明方法,在运行时子类实例替换父类实例。更详细可参考【设计模式】里氏代换原则

设计ActivityManager和ReceiverManager是为了让代码符合开闭原则,因为这两个管理类中都提取了Activity和Receiver的共性方法,如果需要增加其它具体的Activity和Receiver管理类,只需创建一个新的具体类,而不需要修改ActivityManager和ReceiverManager代码,符合开闭原则,开闭原则定义如下:

开闭原则: 软件实体应该对扩展开放,对修改关闭。

设计Manager接口也是如此,该接口是预留接口,后续可能会用到。

2.6 再看看OnePixelActivity里修改部分

package com.yds.jianshu.onepixel;

import android.app.Activity;

import android.os.Bundle;

import android.support.annotation.Nullable;

import android.util.Log;

import android.view.Gravity;

import android.view.Window;

import android.view.WindowManager;

import com.yds.jianshu.manager.OnePixelActivityManager;

public class OnePixelActivity extends Activity{

private static final String TAG = "[OnePixelActivity]";

private OnePixelActivityManager manager;

@Override

protected void onCreate(@Nullable Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setWindowAttributes();

initData();

Log.e(TAG,"onCreate");

}

private void initData(){

manager = new OnePixelActivityManager();

manager.registerActivityReference(this);//将引用传给OnePixelActivityManager

}

private void setWindowAttributes(){

Window window = getWindow();

window.setGravity(Gravity.LEFT|Gravity.TOP);

WindowManager.LayoutParams params = window.getAttributes();

params.x = 0;

params.y = 0;

params.height = 1;

params.width = 1;

window.setAttributes(params);

}

@Override

protected void onDestroy() {

super.onDestroy();

Log.e(TAG,"onDestroy");

}

@Override

protected void onStop() {

super.onStop();

Log.e(TAG,"onStop");

}

@Override

protected void onPause() {

super.onPause();

Log.e(TAG,"onPause");

}

@Override

protected void onStart() {

super.onStart();

Log.e(TAG,"onStart");

}

@Override

protected void onResume() {

super.onResume();

Log.e(TAG,"onResume");

}

}

2.7 OnePixelReceiver源码

package com.yds.jianshu.onepixel;

import android.content.BroadcastReceiver;

import android.content.Context;

import android.content.Intent;

import com.yds.jianshu.manager.OnePixelActivityManager;

public class OnePixelReceiver extends BroadcastReceiver {

private static final String TAG = "[OnePixelReceiver]";

private OnePixelActivityManager manager;

@Override

public void onReceive(Context context, Intent intent) {

String action = intent.getAction();

manager = new OnePixelActivityManager();

if (Intent.ACTION_SCREEN_ON.equals(action)){//如果亮屏,则关闭1像素Activity

manager.finishOnePixelActivity();

}else if(Intent.ACTION_SCREEN_OFF.equals(action)){//如果息屏,则开启1像素Activity

manager.startActivity(context);

}

}

}

2.8 OnePixelService源码部分

package com.yds.jianshu.onepixel;

import android.app.Service;

import android.content.Intent;

import android.os.IBinder;

import com.yds.jianshu.manager.OnePixelReceiverManager;

import com.yds.jianshu.manager.ReceiverManager;

public class OnePixelService extends Service {

private ReceiverManager manager;

public OnePixelService() {

}

@Override

public IBinder onBind(Intent intent) {

// TODO: Return the communication channel to the service.

throw new UnsupportedOperationException("Not yet implemented");

}

@Override

public int onStartCommand(Intent intent, int flags, int startId) {

manager = new OnePixelReceiverManager();//符合里氏代换原则

manager.register(this);//注册广播接收者

return START_STICKY;

}

@Override

public void onDestroy() {

manager.unregister(this);

}

}

在上述代码中,使用了OnePixelReceiverManager来实例化ReceiverManager ,符合里氏代换原则。

2.9 MainActivity代码

package com.yds.jianshu.mobile;

import android.content.Intent;

import android.support.v7.app.AppCompatActivity;

import android.os.Bundle;

import com.example.myapplication.R;

import com.yds.jianshu.onepixel.OnePixelService;

public class MainActivity extends AppCompatActivity{

private static final String TAG = "[MainActivity]";

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

initData();

}

private void initData(){

startOnePixelService();

}

private void startOnePixelService(){

Intent intent = new Intent();

intent.setClass(MainActivity.this, OnePixelService.class);

startService(intent);

}

@Override

protected void onDestroy() {

super.onDestroy();

}

}

该部分代码基本不变。

在此基础上,还增加了一个工具类,用于对对象判空

package com.yds.jianshu.utils;

/**

* Created by yds

* on 2019/8/2.

*/

public class ObjectUtil {

public static T requireNonNull(T object,String message){

if(object == null){

throw new NullPointerException(message);

}

return object;

}

}

3 重构后的UML图

暂时不提供

4 相关文章

android 代码设置像素,【Android实例】用设计原则来重构1像素保活代码相关推荐

  1. android动态设置src,Android 代码里设置ImageView的src和background

    设置ImageView的src: image.setImageDrawable(getResources().getDrawable(R.drawable.blackk)); String path= ...

  2. android 代码设置圆角,Android中用Shape实现圆角和局部圆角

    本文讲解如何实现布局边框的部分圆角 大家可能都知道圆角实现其实很简单, 在drawable文件夹下新建xml文件加入以下代码 情景1: 四个角均为圆角 android:shape="rect ...

  3. android 动态设置margin,android 代码中设置margin

    场景:Android怎么在java代码中设置margin Android如何在java代码中设置margin 原创帖,转发请注明出处:http://thierry-xing.iteye.com/blo ...

  4. android seekbar 代码设置高度,Android - 如何更改默认的SeekBar厚度?

    Vaibhav Jani.. 30 你必须改变progressDrawable和thumb的SeekBar来调整它的厚度: android:id="@+id/seekBar" an ...

  5. android datepicker设置日期,Android DatePicker

    前言 话说日期时间选择控件许多项目都会用到,今天小可不才,也发一个自己写的日期选择控件 先上图 CC8V2$(JPZ`{WT42ICK7F}K.png demo.gif 1.首先自定义日期选择工具类 ...

  6. android 自定义设置界面,Android 设置界面之 Preference

    Android系统为设置界面的UI提供了一系列的接口,设置界面的部分和Activity是分离的,会有一个PreferenceScreen的对象 是根目录,在其中会包含CheckBoxPreferenc ...

  7. android gridview设置高度,android设置GridView高度自适应,实现全屏铺满效果

    使GridView每个item的高度自适应拉伸,达到整个GridView刚好铺满全屏的效果. public static void setGridViewMatchParent(GridView gr ...

  8. android 状态栏设置工具栏,Android状态栏工具

    参考了一些文章做了一些修改,变成了自己的工具类.其中有很多地方欠考虑,有待改进,欢迎路过的大佬给点建议. 经过前两篇的介绍我们对如何修改状态栏的效果有了大致的了解,本篇介绍一种使用更加简单的方式 设置 ...

  9. android 应用两个icon,Android 2.0环境下的图标设计原则

    创造一个统一外观,感觉完整的用户界面会增加你的产品附加价值.精炼的图形风格也使用户觉得用户界面更加专业. 本文档提供了一些信息,帮助你如何在应用界面的不同部分创造图标来匹配Android2.x框架下的 ...

最新文章

  1. LeetCode简单题之检查句子中的数字是否递增
  2. 运行ceph时,了解一下主要的进程。
  3. IntelliJ IDEA 详细图解最常用的配置 ,适合刚刚用的新人。
  4. C ++定义QML类型
  5. 计算机用户的特点,计算机应用基础 Windows的主要特点
  6. Checkpoint--实现步骤
  7. ccpc中国大学生首届程序设计竞赛
  8. mysql的模拟数据,员工的模拟数据,sql语句的应用,粘贴即用
  9. 《模拟电子技术基础》课程笔记(一)——绪论
  10. keil5破解失败【经验分享】
  11. 青龙面板之【追书神器】——5.29
  12. c语言关于性别的程序,输入性别并记录男女个数还要算出男女平均年龄的c语言程序怎样写...
  13. dpi、ppi、apm是什么
  14. 过等保是浪费钱吗?一定要过等保吗?
  15. 公众号被 SRS 大佬推荐是怎么样一种体验~~
  16. 人脸识别机CCC认证
  17. 【双剑合璧】Git和Github使用指南
  18. BUUCTF:[SWPU2019]神奇的二维码
  19. 非线性方程的数值解法
  20. 日常听歌哪款蓝牙耳机音质好?2021国产高性价比高音质蓝牙耳机分享

热门文章

  1. 《『若水新闻』客户端开发教程》——17.软件自动更新
  2. 初始化git仓库,并push到远端
  3. SQL2008,SQL2005存储过程解密
  4. Memcached的几种Java客户端(待实践)
  5. Node-ipc 热门包作者投毒“社死‘’,谁来保护开源软件供应链安全?
  6. 奇安信代码安全实验室帮助微软修复高危漏洞,获官方致谢
  7. 黑客可利用超声波秘密控制语音助手设备
  8. CW3 Clarifications
  9. AutoMapper,对象映射的简单使用
  10. VR一体机行业调研:用户活跃未达预期,广告收益前景堪忧