IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 移动开发 -> Android事件动机模式 -> 正文阅读

[移动开发]Android事件动机模式

1.事件动机模式简介

事件动机模式是一种架构模式。
事件动机模式的程序包含多个子模块、一个外部关系模块和一个纯计算工具类。
常见的子模块有Activity、Dialog、Toast、Fragment、SharedPreferences、FileManager、SqliteManager、HttpUtil、LocationManager等。

2.事件动机模式的性质

性质一:事件动机模式中,只存在外部关系模块调用子模块,不存在子模块调用外部关系模块,也不存在子模块调用其他子模块。
性质二:事件动机模式中,子模块只存在这六类供外部关系模块调用的方法:

  1. new XxxManager();子模块的构造器。例如new FileManager()
  2. void setListener();子模块设置监听器。例如Activity中登录按钮设置OnClickListener
  3. Data get();从子模块获取数据。例如Activity中获取编辑框内编辑的文本,再例如FileManager从文件读取文本;
  4. void set(Data);将数据刷新到子模块。例如ActivityString刷新到TextView文本框,再例如FileManager将文本保存到文件;
  5. void request(Data, OnResponseListener);子模块执行耗时任务。例如网络模块执行Http请求;
  6. 生命周期控制方法;控制子模块的生命周期。例如ActivitystartXxxActivity()mActivity.finish(),再例如mFileManager.open(filename)mFileManager.close()

3.事件动机模式的Java桌面程序版

任何Java桌面应用程序,都可以通过重构得到例子A这种形式的外部关系模块:
例子A:

public class XxxExternalRelations {
    ViewManager mViewManager;
    FileManager mFileManager;
    GpsManager mGpsManager;
    GeocoderManager mGeocoderManager;
    public XxxExternalRelations(Object param) {
        mViewManager = new ViewManager();
        mFileManager = new FileManager();
        mGpsManager = new GpsManager();
        mGeocoderManager = new GeocoderManager();
        mViewManager.setOnVvvListener((vparam) -> {
            // 调用mViewManager, mFileManager, HttpUtil, mGpsManager, mGeocoderManager, PureCalculation
        });
        mFileManager.setOnFffListener((fparam) -> {
            // 调用mViewManager, mFileManager, HttpUtil, mGpsManager, mGeocoderManager, PureCalculation
        });
        mGpsManager.setOnGggListener((gparam) -> {
            // 调用mViewManager, mFileManager, HttpUtil, mGpsManager, mGeocoderManager, PureCalculation
        });
    }
}

也就是说程序是这样执行的:先创建子模块并且给子模块设置监听器,然后等待事件的发生来执行其他代码。

4.事件动机模式的Android版

任何Android程序,都可以通过重构得到下面这种形式(下面的代码都可在“项目举例”的ProgramStructureGPS_20210630.zip项目文件中阅读):
ActivityLifecycleListener.java

package org.ourmap.programstructuregps.event_motive_mode;
public class ActivityLifecycleListener {
    public void onModulesCreated() {
    }
    public void onResume() {
    }
    public void onPause() {
    }
    public void onDestroy() {
    }
    public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
    }
}

BaseActivity.java

/**
 * 事件动机模式的View模块
 */
public abstract class BaseActivity extends Activity {
    private ActivityLifecycleListener mLifecycleListener;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(getLayoutResourceID());
        onCreateViewModule();
        newExternalRelations(); // new ExternalRelations(this) and  setLifecycleListener(), create modules, and set listeners for modules.
        if (mLifecycleListener != null) {
            mLifecycleListener.onModulesCreated();
        }
    }
    protected abstract int getLayoutResourceID();
    protected abstract void onCreateViewModule();
    protected abstract void newExternalRelations();
    protected void setLifecycleListener(ActivityLifecycleListener activityLifecycleListener) {
        mLifecycleListener = activityLifecycleListener;
    }
    @Override
    protected void onResume() {
        super.onResume();
        if (mLifecycleListener != null) {
            mLifecycleListener.onResume();
        }
    }
    ... // onPause(), onDestroy(), onRequestPermissionsResult()等类似于onResume()一样
}

BaseExternalRelations.java

package org.ourmap.programstructuregps.event_motive_mode;
/**
 * 事件动机模式的外部关系模块
 */
public class BaseExternalRelations<Activity extends BaseActivity> {
    protected Activity mActivity;
    public BaseExternalRelations(Activity activity) {
        mActivity = activity;
        mActivity.setLifecycleListener(newActivityLifecycleListener());
    }
    protected ActivityLifecycleListener newActivityLifecycleListener() {
        return new ActivityLifecycleListener(){
        };
    }
}

5.事件动机模式的原理

5.1 对方法进行拆解封装重构

对方法进行拆解封装重构的例子:

void functionX() {
    sentenceA();
    functionB();
    functionC();
}
private void functionB() {
    sentenceD();
    functionE();
}
private void functionE() {
    sentenceF();
}
private void functionC() {
    sentenceG();
    sentenceH();
}

对方法functionX()拆解封装重构之后得到:

void functionX() {
    sentenceA();
    sentenceD();
    sentenceF();
    sentenceG();
    sentenceH();
}

重构之前,functionX()方法调用语句sentenceF()形成的栈是:

functionX() > functionB() > functionE() > sentenceF()

重构之后,functionX()方法调用语句sentenceF()形成的栈是:

functionX() > sentenceF()

5.2 事件是程序执行的动机

例如,点击登录按钮执行登录这个过程,是点击事件导致了登录请求的执行。
再例如,点击桌面图标启动某个App这个过程,是点击事件导致了某个Activity的创建。
再例如,应用收到一个透传的推送消息而弹出某个提示这个过程,是网络消息事件导致程序的执行。
于是得到命题一,命题一:事件是程序执行的动机。
事件是程序执行的动机,意味着程序的方法栈的栈底是一个事件方法。
例如,执行登录网络请求时,程序的方法栈是:

onClick() > requestLogin() > HttpUtil.login();

其中onClick()就是登录按钮的OnClickListener监听器的事件方法。
对onClick()方法进行拆解封装重构之后,requestLogin()就消除了,执行登录网络请求的方法栈变为:

onClick() > HttpUtil.login();

于是得到结论A,结论A:对事件方法进行拆解封装重构之后,程序调用各个子模块的方法都是事件方法。

5.3 子模块的内部结构与外部关系

对于程序,为了让每个子模块内部都不调用其他子模块(包括Android的Activity),那必然需要构建一个“中间模块”来创建和调用各个子模块。
又由5.2节中的“结论A:程序调用各个子模块的方法都是事件方法”,那么只要把事件方法都迁移到“中间模块”,就可以让程序只存在“中间模块”调用子模块。于是程序满足了性质一“事件动机模式中只存在‘中间模块’调用子模块”。
至于怎样把事件方法迁移到“中间模块”,只要将监听器的设置放在“中间模块”即可。例如将mActivity.setLoginListener()mGpsManager.setLocationListener()放在“中间模块”中调用。
如果子模块的某个监听器只调用子模块本身,那么这个监听器只需要在子模块内部创建,不需要放在“中间模块”中。

命题二:任何一个本体都具有内部结构与外部关系,一内一外构成其整体。
本体的内部结构与外部关系:
本体的内部结构与外部关系.png
子模块的内部结构就是子模块内部的变量和方法等。由于只有“中间模块”的方法中调用了多个子模块,所以子模块的外部关系就是“中间模块”,于是将“中间模块”命名为外部关系模块。

5.4 事件动机模式Android版实现的技巧

Activity模块创建完成之后再创建外部关系模块,并把Activity传入外部关系模块的构造器中。然后在外部关系模块的构造器中优先执行mActivity.setLifecycleListener()。对于ActivityLifecycleListener,由于点击返回按钮会导致onDestroy()执行,所以将onDestroy()视为事件方法,onResume()、onRequestPermissionsResult()等也是这样,于是将这几个事件方法放在ActivityLifecycleListener监听器中。
BaseActivity.java

public abstract class BaseActivity extends Activity {
    private ActivityLifecycleListener mLifecycleListener;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(getLayoutResourceID());
        onCreateViewModule();
        newExternalRelations();
        if (mLifecycleListener != null) {
            mLifecycleListener.onModulesCreated();
        }
    }
    protected abstract int getLayoutResourceID();
    protected abstract void onCreateViewModule();
    protected abstract void newExternalRelations();
    protected void setLifecycleListener(ActivityLifecycleListener activityLifecycleListener) {
        mLifecycleListener = activityLifecycleListener;
    }
    @Override
    protected void onDestroy() {
        if (mLifecycleListener != null) {
            mLifecycleListener.onDestroy();
        }
        super.onDestroy();
    }
    ... // onResume(), onPause(), onRequestPermissionsResult()等类似于onDestroy()一样
}

MainActivity.java

    @Override
    protected void newExternalRelations() {
        new MainRelations(this);
    }

BaseExternalRelations.java

public class BaseExternalRelations<Activity extends BaseActivity> {
    protected Activity mActivity;
    public BaseExternalRelations(Activity activity) {
        mActivity = activity;
        mActivity.setLifecycleListener(newActivityLifecycleListener());
    }
    protected ActivityLifecycleListener newActivityLifecycleListener() {
        return new ActivityLifecycleListener(){
        };
    }
}

MainRelations.java

    public MainRelations(MainActivity mainActivity) {
        super(mainActivity);
        mGpsManager = new GpsManager(mainActivity.getApplicationContext());
        ...
        mGpsManager.setLocationListener(newLocationListener());
    }
    @Override
    protected ActivityLifecycleListener newActivityLifecycleListener() {
        return new ActivityLifecycleListener() {
            @Override
            public void onModulesCreated() { // 当各个模块都创建完成、设置监听器完成后,所执行的
            ... // do something
            }
            @Override
            public void onDestroy() {
            ... // do something
            }
        };
    }
    ...

相当于Java桌面程序版这样的流程:

ViewManager mViewManager = new ViewManager();
new XxxExternalRelations(mViewManager);
    public XxxExternalRelations(mViewManager) {
        mViewManager.setOnVvvListener((vparam) -> {
            // 调用mViewManager, mFileManager, HttpUtil, mGpsManager, mGeocoderManager, PureCalculation
        });
        mFileManager = new FileManager();
        mGpsManager = new GpsManager();
        mGeocoderManager = new GeocoderManager();
        mFileManager.setOnFffListener((fparam) -> {
            // 调用mViewManager, mFileManager, HttpUtil, mGpsManager, mGeocoderManager, PureCalculation
        });
        mGpsManager.setOnGggListener((gparam) -> {
            // 调用mViewManager, mFileManager, HttpUtil, mGpsManager, mGeocoderManager, PureCalculation
        });
    }

对于携带参数数据的情况,参数视为业务数据(业务数据的概念在“5.6 事件动机模式的数据流图”),所以参数数据的变量放在外部关系模块中:
MainRelations.java

    public MainRelations(MainActivity mainActivity) {
        super(mainActivity);
        data = mActivity.getIntent().getData();
        mActivity.initViewWithData(data);
        ...
    }

对于Fragment,类似的方法如下:
XxxRelations.java

    public XxxRelations(XxxFragment xxxFragment) {
        super(xxxFragment);
        data = mFragment.getArguments().getData();
        mFragment.initViewWithData(data);
        ...
    }

5.5 纯计算

数据体:例如Java Bean、字符串、数字、byte数组、Bitmap等称之为数据体。View对象、File对象等不是数据体。
纯计算:以一组数据体作为输入、一组数据体作为输出的函数,称之为纯计算。

[dataD, dataE] = function(dataA, dataB, dataC)

在java语言中,纯计算封装为public static修饰的方法。第3节中的PureCalculation类就是一个纯计算工具类。
纯计算的性质:纯计算函数执行时,数据只在内存和CPU流动,不会涉及显示屏、文件等硬件模块和View、File等软件模块。

5.6 事件动机模式的数据流图

事件动机模式的数据流图:
事件动机模式的数据流图.png
“业务数据”通过“纯计算”得到“网络模块数据”的举例
登录时,带有手机号和验证码的Bean对象通过new Gson().toJson(bean)转化为json字符串,json字符串可直接用于网络请求。其中Bean对象是业务数据,new Gson().toJson(bean)是纯计算,json字符串是网络模块数据。
“业务数据”通过“纯计算”得到“视图模块数据”的举例
例子一,业务数据“int count”需要显示到TextView中,中间需要进行纯计算“stringCount = String.valueOf(count)”,得到视图模块数据stringCountstringCount可以直接传入TextView中显示出来;
例子二,有6个标签([tag0, tag1, tag2, tag3, tag4, tag5])和它们的选中状态(其中第{0, 1, 5}个是选中的)需要显示出来,由于显示的方式是列表,所以要将标签名和{0, 1, 5}转化为[{tag0, true}, {tag1, true}, {tag2, false}, {tag3, false}, {tag4, false}, {tag5, true}]这种列表形式才能直接被列表的Adapter使用,这一步转化就是纯计算。
“业务数据”通过“纯计算”得到“文件模块数据”的举例
View截图获取的Bitmap,需要转码为jpg格式得到byte[]比特数组,然后byte[]可以直接被FileManager写入图片文件,转码这一步是纯计算。

数据流图说明了命题三,命题三:程序执行的过程是内部通信与计算的过程。内部通信是指内存到其他硬件之间的通信。

6.项目举例

使用事件动机模式构建的项目:ProgramStructureGPS_20210630.zip。
其中包含了事件动机模式的Activity型基类、两种Fragment型基类、MainActivity实现类、MainRelations实现类、FileManager、PureCalculation等等,以及依据事件动机模式的思想构建的OkHttp封装类。
项目文件下载地址:
链接:https://pan.baidu.com/s/18cCiAzBQtz4xlkkqFdsX1g
提取码:wkl7

  移动开发 最新文章
Vue3装载axios和element-ui
android adb cmd
【xcode】Xcode常用快捷键与技巧
Android开发中的线程池使用
Java 和 Android 的 Base64
Android 测试文字编码格式
微信小程序支付
安卓权限记录
知乎之自动养号
【Android Jetpack】DataStore
上一篇文章      下一篇文章      查看所有文章
加:2021-07-24 11:36:36  更:2021-07-24 11:37:55 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/2 0:06:27-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码