android 代码设置像素,【Android实例】用设计原则来重构1像素保活代码
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像素保活代码相关推荐
- android动态设置src,Android 代码里设置ImageView的src和background
设置ImageView的src: image.setImageDrawable(getResources().getDrawable(R.drawable.blackk)); String path= ...
- android 代码设置圆角,Android中用Shape实现圆角和局部圆角
本文讲解如何实现布局边框的部分圆角 大家可能都知道圆角实现其实很简单, 在drawable文件夹下新建xml文件加入以下代码 情景1: 四个角均为圆角 android:shape="rect ...
- android 动态设置margin,android 代码中设置margin
场景:Android怎么在java代码中设置margin Android如何在java代码中设置margin 原创帖,转发请注明出处:http://thierry-xing.iteye.com/blo ...
- android seekbar 代码设置高度,Android - 如何更改默认的SeekBar厚度?
Vaibhav Jani.. 30 你必须改变progressDrawable和thumb的SeekBar来调整它的厚度: android:id="@+id/seekBar" an ...
- android datepicker设置日期,Android DatePicker
前言 话说日期时间选择控件许多项目都会用到,今天小可不才,也发一个自己写的日期选择控件 先上图 CC8V2$(JPZ`{WT42ICK7F}K.png demo.gif 1.首先自定义日期选择工具类 ...
- android 自定义设置界面,Android 设置界面之 Preference
Android系统为设置界面的UI提供了一系列的接口,设置界面的部分和Activity是分离的,会有一个PreferenceScreen的对象 是根目录,在其中会包含CheckBoxPreferenc ...
- android gridview设置高度,android设置GridView高度自适应,实现全屏铺满效果
使GridView每个item的高度自适应拉伸,达到整个GridView刚好铺满全屏的效果. public static void setGridViewMatchParent(GridView gr ...
- android 状态栏设置工具栏,Android状态栏工具
参考了一些文章做了一些修改,变成了自己的工具类.其中有很多地方欠考虑,有待改进,欢迎路过的大佬给点建议. 经过前两篇的介绍我们对如何修改状态栏的效果有了大致的了解,本篇介绍一种使用更加简单的方式 设置 ...
- android 应用两个icon,Android 2.0环境下的图标设计原则
创造一个统一外观,感觉完整的用户界面会增加你的产品附加价值.精炼的图形风格也使用户觉得用户界面更加专业. 本文档提供了一些信息,帮助你如何在应用界面的不同部分创造图标来匹配Android2.x框架下的 ...
最新文章
- LeetCode简单题之检查句子中的数字是否递增
- 运行ceph时,了解一下主要的进程。
- IntelliJ IDEA 详细图解最常用的配置 ,适合刚刚用的新人。
- C ++定义QML类型
- 计算机用户的特点,计算机应用基础 Windows的主要特点
- Checkpoint--实现步骤
- ccpc中国大学生首届程序设计竞赛
- mysql的模拟数据,员工的模拟数据,sql语句的应用,粘贴即用
- 《模拟电子技术基础》课程笔记(一)——绪论
- keil5破解失败【经验分享】
- 青龙面板之【追书神器】——5.29
- c语言关于性别的程序,输入性别并记录男女个数还要算出男女平均年龄的c语言程序怎样写...
- dpi、ppi、apm是什么
- 过等保是浪费钱吗?一定要过等保吗?
- 公众号被 SRS 大佬推荐是怎么样一种体验~~
- 人脸识别机CCC认证
- 【双剑合璧】Git和Github使用指南
- BUUCTF:[SWPU2019]神奇的二维码
- 非线性方程的数值解法
- 日常听歌哪款蓝牙耳机音质好?2021国产高性价比高音质蓝牙耳机分享