首页 > 程序开发 > 综合编程 > 其他综合 >

程序结构设计理论(Android) - 树曲 - 博客园

2019-09-29

程序结构设计理论(Android)

程序结构设计理论(Android)

程序结构设计理论(Android)

作者:邓能财

2019年9月24日

个人简介

姓名:邓能财

[明德厚学,爱国荣校]

本文的PPT版、以及作为案例的App项目可以从这里下载:程序结构设计理论(Android)20190924.zip

目录

一、android程序中,对界面的访问与更新阅读信息量优化

一、android程序中,对界面的访问与更新

1.android app的界面是树结构

[如图-app用户界面的树结构]

在android程序中访问界面,即,在树的一个节点访问其他节点。

2.在Activity中某个View访问其他View
HhhViewGroup hhhViewGroup = ((Activity)getContext()).findViewById(R.id.hhh);

或者

ViewGroup rootView = (ViewGroup)((ViewGroup)((Activity)getContext()).findViewById(android.R.id.content)).getChildAt(0);
HhhViewGroup hhhViewGroup = (HhhViewGroup)FindViewUtil.find(rootView, child -> child instanceof HhhViewGroup);
3.在某个Activity中访问其他Activity
BbbActivity bbbActivity = CollectionUtil.find(((App)getApplication()).getActivityList(), item -> item instanceof BbbActivity);

其中(App)getApplication()).getActivityList()需要实现一个Activity列表,可以用ActivityLifecycleCallbacks实现;

4.LllEditText的文本改变时,更新KkkViewGroup的方法
lllEditText.addTextChangedListener(new TextWatcher() {
        @Override
        public void afterTextChanged(Editable text) {
            // 处理text
        }
    });

处理text:

CccActivity cccActivity = ((CccActivity)lllEditText.getContext());
FffFragment fffFragment = (FffFragment)CollectionUtil.find(cccActivity.getFragmentManager().getFragments(), item -> item instanceof FffFragment);
KkkViewGroup kkkViewGroup = (KkkViewGroup)fffFragment.getView().findViewById(R.id.kkk);

或者

KkkViewGroup kkkViewGroup = (KkkViewGroup)FindViewUtil.find(fffFragment.getView(), child -> child instanceof KkkViewGroup);
kkkViewGroup.refresh(text.toString());
5.监听器的设置不外传

由于任何子View或者Fragment都可以访问任何其他节点,因此类似下面的代码是不应该存在的:

public class FffFragment {
    public void setXxxOnClickListener(XxxOnClickListener xxxOnClickListener) {
        kkkViewGroup.setXxxOnClickListener(xxxOnClickListener);
    }
}

然后在CccActivity内执行:

fffFragment.setXxxOnClickListener(() -> {CccActivity.this.doThing(); });

应该这样实现:

kkkViewGroup.setXxxOnClickListener(() -> {((CccActivity)kkkViewGroup.getContext()).doThing(); });

二、Activity访问Service,Service更新Activity

1.Activity访问Service

方法一、bindService()
mServiceList变量,在XxxService的onCreate()中mServiceList.add(this),在onDestroy()中mServiceList.remove(this);

XxxService xxxService = CollectionUtil.find(((App)getApplication()).getServiceList(), item -> item instanceof XxxService);
2.在Service中更新Activity
BbbActivity bbbActivity = CollectionUtil.find(((App)getApplication()).getActivityList(), item -> item instanceof BbbActivity);
bbbActivity.refresh(data);

三、查找的简化
for(Ttt item : list) {
    if (item...) {
        doThing(item);
        break;
    }
}

可简化为:

Ttt item = CollectionUtil.find(list, item...);
doThing(item);

find的实现:

public class CollectionUtil {

    public static  T find(Collection list, Filter filter) {
        for(T object : list) {
            if (filter.accept(object)) {
                return object;
            }
        }
        return null;
    }

    public interface Filter {
        boolean accept(T object);
    }
}

四、数据体、单纯计算

1.数据体

定义:可以转换为字符串而不损失信息的变量或常量是数据体;Java Bean对象,可以转换为json而不损失信息,因为可以转回去,所以Java Bean对象是数据体;

2.单纯计算(Pure Calculation)

定义:以一组数据体作为输入,以一组数据体作为输出的计算称为单纯计算;

[result1 result2 result3] = function([param1 param2 param3])

其中function称为函数体;

3.单纯计算的特征

哲理1:程序执行的过程是通信与计算的过程;程序内部的通信是指内存到其他硬件之间的通信;

单纯计算的特征:

4.例子
if (validate(input)) {
    functionA(input);
}

boolean validate(String input) {
    if (input.length() > 5) {
        showToast("不能长于5个字符!");
        return false;
    } else if (!isAlphabet(input)) {
        showToast("只能输入字母!");
        return false;
    } else {
        return true;
    }
}

其中,showToast()涉及和显示屏通信;

String result = validate(input);
if (result == null) {
    functionA(input);
} else {
    showToast(result);
}

String validate(String input) {
    String result;
    if (input.length() > 5) {
        result = "不能长于5个字符!";
    } else if (!isAlphabet(input)) {
        result = "只能输入字母!";
    } else {
        result = null;
    }
}

五、阅读信息量优化

1.模块与阅读信息量

阅读信息量是衡量代码的简单与复杂、阅读的难易程度的一个指标;

A.例子一

public static int function(int a, b, c, d, e, f, g, h) {
    a = a + 1;
    b = a + b;
    c = a + b + c;
    d = a + b + c + d;
    e = e + 1;
    f = e + f;
    g = e + f + g;
    h = e + f + g + h;
    return d + h;
}

划分之后:

public static int function(int a, b, c, d, e, f, g, h) {
    d = functionI(a, b, c, d);
    h = functionJ(e, f, g, h);
    return d + h;
}

private static int functionI(int a, b, c, d) {
    a = a + 1;
    b = a + b;
    c = a + b + c;
    d = a + b + c + d;
    return d;
}

private static int functionJ(int e, f, g, h) {
    e = e + 1;
    f = e + f;
    g = e + f + g;
    h = e + f + g + h;
    return h;
}

阅读代码时,需要读懂一个方法内语句之间的关系;

    A   B   C   D   E   F   G   H   R
A   0   1   1   1   0   0   0   0   0
B   1   0   1   1   0   0   0   0   0
C   1   1   0   1   0   0   0   0   0
D   1   1   1   0   0   0   0   0   1
E   0   0   0   0   0   1   1   1   0
F   0   0   0   0   1   0   1   1   0
G   0   0   0   0   1   1   0   1   0
H   0   0   0   0   1   1   1   0   1
R   0   0   0   1   0   0   0   1   0

由于这个矩阵的各个元素出现0或1的概率是1/2,因此这个矩阵的信息量为

I = 9*9*-log2(p) = 9*9*-log2(1/2) = 81 (bit)

即,function()方法的阅读信息量是81(bit);

划分之后,语句之间的关系如下:

function():

    I   J   R
I   0   0   1
J   0   0   1
R   1   1   0

functionI():

    A   B   C   D   R
A   0   1   1   1   0
B   1   0   1   1   0
C   1   1   0   1   0
D   1   1   1   0   1
R   0   0   0   1   0

functionJ():

    E   F   G   H   R
E   0   1   1   1   0
F   1   0   1   1   0
G   1   1   0   1   0
H   1   1   1   0   1
R   0   0   0   1   0

这个三个矩阵的信息量为

I = 3*3*-log2(1/2) + 5*5*-log2(1/2) + 5*5*-log2(1/2) = 9 + 25 + 25 = 59 (bit)

即,function()、functionI()、functionJ()这三个方法的阅读信息量一共是59(bit);
59 (bit),可见,划分之后减少了阅读信息量;

B.例子二:语句的排列顺序产生的信息量

a=0; b=1; c=1;
a=b+c;
a=a+b;
output a; // 3

a=0; b=1; c=1;
a=a+b;
a=b+c;
output a; // 2

从这两段代码可以得知,如果把语句的顺序调换,执行结果就不一样了;

p = 1/n!
I = -log2(p) = -log2(1/n!) = log2(n!)

当n = 8时,I = log2(8!) = 15.3(bit)

C.例子三:单条语句的信息量

2.避免变量信息重复

例子如下:

int[] numbers;
int count;

这个两个变量中count是numbers的总和;

因此有如下的一般结论:

有几个数据体变量:

DataTypeA dataA;
DataTypeB dataB;
DataTypeC dataC;

如果存在一个函数体functionD,以dataA, dataB作为输入,以dataC作为输出;

DataTypeC functionD(DataTypeA dataA, DataTypeB dataB)

即dataC可由dataA, dataB计算出来,就认为dataC包含的信息与dataA, dataB包含的信息重复;

3.避免逻辑功能重复

避免逻辑功能重复有两种情况:

例子:

ViewGroup containerView = findViewById(R.id.xxx);
LinearLayout layout = new LinearLayout(mContext);
layout.setLayoutParam(new LayoutParam(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT));
layout.addView(new TextView(mContext));
containerView.addView(layout);

这段代码的功能和LayoutInflater.inflate()的功能重复;

4.避免配置信息重复

和避免变量信息重复类似;

dataC == functionD(dataA, dataB)

即dataC可由dataA, dataB计算出来,就认为dataC包含的信息与dataA, dataB包含的信息重复;

六、功能模块的硬件层与软件层,输入、事件与动机

1.功能模块的硬件层与软件层

App的功能模块一般包括文件、显示、网络、声音;

模块    文件           显示        网络

文件功能的软件应用层:数据库的增删改查;

显示功能的软件应用层:创建与销毁视图、切换显示与隐藏、输入数据(比如文字)、填充或提取数据、动画、页面跳转;

2.输入、事件与动机

事件的定义:由于用户或某个设备向程序输入的数据满足某个条件,引发了监听器方法的执行,称之为一次事件;

这三个功能的事件如下:

哲理2:任何有数据输入的功能模块都可能引发事件;程序执行的动机是事件,即事件推动了程序执行;

对于这三个功能:

七、双向绑定与即时更新

1.双向绑定与即时更新

双向绑定的定义:在显示模块中,视图组件与显示模块数据相关联;视图组件包含的数据变化时,即时更新到显示模块数据;显示模块数据变化时,即时更新视图组件;

除了即时更新的方式提取数据,就是临时从视图组件提取数据;

2.双向绑定的应用场景

应用场景:双向绑定应用于可编辑的列表;

A.例子一:

B.例子二:列表的数据删除一项,需要调用notifyDatasetChanged()即时更新视图组件;

八、内部结构与外部关系的架构模式(Internal Structure and External Relations)

目录

1.内部结构与外部关系的哲理

1.内部结构与外部关系的哲理

哲理3:任何一个本体都具有内部结构与外部关系,一内一外构成其整体;

[如图-本体的内部结构与外部关系]

2.方法的外部关系

定义:当方法A内,调用两个或两个以上其他方法(B1、B2、…Bn)时,方法A就是方法B1、B2、…Bn之间的一种外部关系;

public static void main(String[] args) {
    functionI();
    functionJ();
}

private static void functionI() {
    sentenceA();
    sentenceB();
    sentenceC();
    sentenceD();
}

private static void functionJ() {
    sentenceE();
    sentenceF();
    sentenceG();
    sentenceH();
}

functionI()中的语句是functionI()的内部结构;

3.基础模块、及其内部结构与外部关系

六.1中所定义的文件、显示、网络等模块下面称为“基础模块”;

基础模块的外部关系的定义:

4.基础模块的单纯性与单纯化重构

单纯性的定义:某个基础模块内部没有直接调用其他基础模块,就称这个基础模块满足单纯性;

基础模块的单纯化重构:

public class KkkActivity {
    View vViewA;
    View vViewB;
    FileManager mFileManager;
    ...
    private void functionL() {
        vViewA.setOnClickListener((v) -> {
            mFileManager.write("abcdef");
        });
    }
    private void functionM() {
        vViewA.setOnClickListener((v) -> {
            vViewB.setVisibility(View.GONE);
        });
    }
}

在例子B中,mFileManager的声明语句和mFileManager.write("abcdef")语句处在显示模块KkkActivity中,使KkkActivity有失单纯性;因此需要调进行单纯化重构,使KkkActivity保持单纯性;

下面对例子B的显示模块进行单纯化重构:

vViewA.setOnClickListener((v) -> {
    mFileManager.write("abcdef");
}

这个语句,可以分解为:

View.OnClickListener listener = new View.OnClickListener() {
    @Override public void onClick(View v) {
        mFileManager.write("abcdef");
    }
};
vViewA.setOnClickListener(listener);

这几个语句调用了

View.OnClickListener listener = new View.OnClickListener() {...};
mFileManager.write("abcdef");

这两个语句;它们一个属于显示模块、一个属于文件模块;

private View.OnClickListener getWriteOnClickListener() {
    View.OnClickListener listener = new View.OnClickListener() {
        @Override public void onClick(View v) {
            mFileManager.write("abcdef");
        }
    };
    return listener;
}
vViewA.setOnClickListener(getWriteOnClickListener());

因此这两个语句构成的getWriteOnClickListener()是显示模块与文件模块的外部关系;

public class MiddleClass {
    FileManager mFileManager;
    public View.OnClickListener getWriteOnClickListener() {
        View.OnClickListener listener = new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                mFileManager.write("abcdef");
            }
        };
        return listener;
    }
}
public class KkkActivity {
    View vViewA;
    View vViewB;
    MiddleClass mMiddleClass;
    ...
    private void functionL() {
        vViewA.setOnClickListener(mMiddleClass.getWriteOnClickListener());
    }
    private void functionM() {
        vViewA.setOnClickListener((v) -> {
            vViewB.setVisibility(View.GONE);
        });
    }
}
5.不满足单纯性的一般性例子

例子C:

class XxxModule {
    Type1 mObj1;
    Type2 mObj2;
    Type3 mObj3;
    RrrModule mRrrModule;
    SssModule mSssModule;

    void functionO() {
        mObj1.methodT();
        Type4 obj4  = new Type4();
        final Type5 finalObj5  = new Type5();
        mObj3.setOnPppListener(new OnPppListener() {
            @Override public void onPpp(QType1 q1, QType2 q2, QType3 q3) {
                mObj1.doThingU(q1);
                TypeR1 r1 = Calc.doThingV(q1, q2);
                mRrrModule.methodW(r1);
                mObj2.methodY(q3);
                TypeR2 r2 = Calc.doThingZ(q2, q3, finalObj5);
                mSssModule.methodA(r1, r2, new OnDddListener() {
                    @Override public onDdd(TypeB b) {
                        mRrrModule.methodC(b);
                    }
                });
            }
        });
        ...
    }
}

回调方法onPpp()内可引用的对象有q1, q2, q3, finalObj5, mObj1, mObj2, mObj3, mRrrModule, mSssModule;

mObj3.setOnPppListener(new OnPppListener() {
    @Override public void onPpp(QType1 q1, QType2 q2, QType3 q3) {
        mObj1.doThingU(q1);
        TypeR1 r1 = Calc.doThingV(q1, q2);
        mRrrModule.methodW(r1);
        mObj2.methodY(q3);
        TypeR2 r2 = Calc.doThingZ(q2, q3, finalObj5);
        mSssModule.methodA(r1, r2, new OnDddListener() {
            @Override public onDdd(TypeB b) {
                mRrrModule.methodC(b);
            }
        });
    }
});

例子C的XxxModule单纯化,第一步:

private OnPppListener getAaaOnPppListener(Type5 finalObj5) {
    return new OnPppListener() {
        @Override ublic void onPpp(QType1 q1, QType2 q2, QType3 q3) {
            TypeR1 r1 = xxxMethodE(q1, q2);
            mRrrModule.methodW(r1);
            TypeR2 r2 = xxxMethodF(q2, q3, finalObj5);
            mSssModule.methodA(r1, r2, new OnDddListener() {
                @Override public onDdd(TypeB b) {
                    mRrrModule.methodC(b);
                }
            });
        }
    };
}
public TypeR1 xxxMethodE(QType1 q1, QType2 q2) {
    mObj1.doThingU(q1);
    TypeR1 r1 = Calc.doThingV(q1, q2);
    return r1;
}
public TypeR2 xxxMethodF(QType2 q2, QType3 q3, Type5 finalObj5) {
    mObj2.methodY(q3);
    TypeR2 r2 = Calc.doThingZ(q2, q3, finalObj5);
    return r2;
}
mObj3.setOnPppListener(getAaaOnPppListener(finalObj5));

例子C的XxxModule单纯化,第二步:

public class MiddleClass {

    XxxModule mXxxModule;
    RrrModule mRrrModule;
    SssModule mSssModule;

    public MiddleClass(XxxModule xxxModule) {
        mXxxModule = xxxModule;
        ...
    }

    public OnPppListener getAaaOnPppListener(Type5 finalObj5) {
        return new OnPppListener() {
            @Override public void onPpp(QType1 q1, QType2 q2, QType3 q3) {
                TypeR1 r1 = mXxxModule.xxxMethodE(q1, q2);
                mRrrModule.methodW(r1);
                TypeR2 r2 = mXxxModule.xxxMethodF(q2, q3, finalObj5);
                mSssModule.methodA(r1, r2, new OnDddListener() {
                    @Override public onDdd(TypeB b) {
                        mRrrModule.methodC(b);
                    }
                });
            }
        };
    }
}

class XxxModule {
    Type1 mObj1;
    Type2 mObj2;
    Type3 mObj3;
    MiddleClass mMiddleClass;
    ...
    void functionO() {
        mObj1.methodT();
        Type4 obj4  = new Type4();
        final Type5 finalObj5  = new Type5();
        mObj3.setOnPppListener(mMiddleClass.getAaaOnPppListener(finalObj5));
        ...
    }
    public TypeR1 xxxMethodE(QType1 q1, QType2 q2) {
        mObj1.doThingU(q1);
        TypeR1 r1 = Calc.doThingV(q1, q2);
        return r1;
    }
    public TypeR2 xxxMethodF(QType2 q2, QType3 q3, Type5 finalObj5) {
        mObj2.methodY(q3);
        TypeR2 r2 = Calc.doThingZ(q2, q3, finalObj5);
        return r2;
    }
}

下面将事件的监听器的回调方法简称为“事件方法”;

由例子C可见:

6.多个基础模块包含事件方法时的单纯化重构

例子D:

A: (paramA)-> {...A, B, C, D}, B: (paramB)-> {...A, B, C, D}, C: (paramC)-> {...A, B, C, D};

根据结论2,单纯化重构A之后,(paramA)-> {...}这个事件外部关系处于中间类中;
{...}这个事件外部关系也处于中间类中;
{...}, (paramB)-> {...}, (paramC)-> {...}这三个事件外部关系都处于中间类中;

7.对基础模块初始化逻辑的单纯化重构

例子E:

public class AaaActivity {
    @Override protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        ...
        mGpsManager = new GpsManager(mainActivity.getApplicationContext(), this);
        String filename = ...;
        mFileManager = new FileManager(filename);
        mFileManager.open();
}

下面对显示模块AaaActivity进行单纯化重构:

public class AaaActivity {
    MiddleClass mMiddleClass;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        ...
        mMiddleClass = new MiddleClass(this);
}
public class MiddleClass {
    public MiddleClass(MainActivity mainActivity) {
        mMainActivity = mainActivity;
        mGpsManager = new GpsManager(mainActivity.getApplicationContext(), this);
        String filename = ...;
        mFileManager = new FileManager(filename);
        mFileManager.open();
    }
}

基础模块初始化的外部关系,下面称为“初始化外部关系”;

根据结论3与结论4,可得到:

8.对方法进行拆解封装重构

例子F:

void functionX() {
    mXxxModule.methodA();
    functionB();
    functionF();
}
private void functionB() {
    mYyyModule.methodC();
    functionD();
}
private void functionD() {
    mZzzModule.methodE();
}
private void functionF() {
    sentenceG();
    sentenceH();
}

对方法进行拆解封装重构之后:

void functionX() {
    mXxxModule.methodA();
    mYyyModule.methodC();
    mZzzModule.methodE();
    sentenceG();
    sentenceH();
}

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

functionX() > functionB() > functionD() > mZzzModule.methodE();

重构之后,形成的栈是:

functionX() > mZzzModule.methodE();

由例子F,可得到:

9.对类的拆解封装重构

定义:对某个类的拆解封装重构,是要将类中的除了构造方法外的所有private方法,进行拆解封装到调用它们的方法中,最后类中只剩下public、protected以及没有修饰符的方法;

如果对程序进行单纯化重构,得到中间类,再对中间类进行拆解封装重构;

10.事件是程序执行的动机

根据哲理2,事件是程序执行的动机,那么有如下结论:

init() > functionAaa() > functionBbb() ... > functionEee() ... > functionXxx()

或者

onEvent() > functionAaa() > functionBbb() ... > functionEee() ... > functionXxx()

,即init()或者onEvent()处于栈底,而functionEee()处于栈中;

11.中间类的性质,与外部关系模块

下面证明,关于中间类性质的,以及关于“外部关系模块”的概念的结论8;

证明:由结论5可知,单纯化重构之后,中间类包含一个初始化外部关系,并且包含所有事件外部关系;

12.Java桌面应用程序的一般形式

任何Java桌面应用程序,都可以进行单纯化重构、并且拆解封装重构,得到例子G的这种形式的中间类;

public class XxxExternalRelations {
    ViewManager mViewManager;
    FileManager mFileManager;
    GpsManager mGpsManager;
    GeocoderManager mGeocoderManager;
    public XxxExternalRelations(Object param) {
        XxxExternalRelations page = this;
        // 在ViewManager的构造方法内调用vMember.setVvvListener(page.getVvvListener());
        mViewManager = new ViewManager(page);
        // 在FileManager的构造方法内调用fMember.setFffListener(page.getFffListener());
        mFileManager = new FileManager(page);
        // 在GpsManager 的构造方法内调用gMember.setGggListener(page.getGggListener());
        mGpsManager = new GpsManager(page);
        mGeocoderManager = new GeocoderManager();
        ...// 调用mViewManager, mFileManager, mGpsManager, mGeocoderManager进行初始化
    }

    public VvvListener getVvvListener() {
        retrun (vparam) -> {
            // 调用mViewManager, mFileManager, HttpUtil, mGpsManager, mGeocoderManager, PureCalculation
            DataType inputData = PureCalculation.convert(mViewManager.getInputData();
            HttpUtil.login(inputData), new RequestCalback() {
                @Override
                public void onStart() {
                    mViewManager.showWaiting();
                }
                @Override
                public void onProgress(float progress) {
                    mViewManager.updateProgress(progress);
                }
                @Override
                public void onEnd(Reponse data) {
                    mViewManager.dismissWaiting();
                    ...// 处理data,调用其他模块
                }
            });
        };
    }
    public FffListener getFffListener() {
        return (fparam) -> {
            // 调用mViewManager, mFileManager, HttpUtil, mGpsManager, mGeocoderManager, PureCalculation
        };
    }
    public GggListener getGggListener() {
        return (gparam) -> {
            // 调用mViewManager, mFileManager, HttpUtil, mGpsManager, mGeocoderManager, PureCalculation
        };
    }
}

也就是,程序是按照这个步骤执行的:创建模块、设置监听器、初始化,然后等待事件的发生来执行其他代码;

13.Android应用程序的一般形式

任何Android应用程序都有例子H的这种形式;

public class ActivityLifecycleCallback {
    public void onModulesCreated() {    }
    public void onResume() {    }
    public void onPause() {    }
    public void onDestroy() {    }
}

由于Activity的生命周期方法的执行一般是点击事件导致的,因此ActivityLifecycleCallback视作事件的监听器;由于它的事件方法内必然会调用除显示模块的其他模块,因此ActivityLifecycleCallback的对象在外部关系模块创建;

public class BaseExternalRelations {
    public ActivityLifecycleCallback getActivityLifecycleCallback() {
        return new ActivityLifecycleCallback(){};
    }
}
public abstract class BaseActivity extends AppCompatActivity {
    protected T mExternalRelations;
    private ActivityLifecycleCallback mLifecycleCallback;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(getLayoutResID());
        mExternalRelations = createExternalRelations();
        findViewAndSetListener();
        mLifecycleCallback = mExternalRelations.getActivityLifecycleCallback();
        mLifecycleCallback.onModulesCreated();
    }
    protected abstract int getLayoutResID();
    protected abstract T createExternalRelations();
    protected abstract void findViewAndSetListener();
    ...
    @Override
    protected void onDestroy() {
        if (mLifecycleCallback != null) {
            mLifecycleCallback.onDestroy();
        }
        super.onDestroy();
    }
}

打开App时,程序执行了Application的创建以及回调onCreate()方法,也执行了第一个Activity的创建、onCreate()方法以及onResume()方法;这种结构形式在Activity的onCreate()中创建外部关系模块以及初始化监听器,然后程序静止,等待事件的发生;

public class MainActivity extends BaseActivity {
    private TextView vTextLocationAddress;
    private TextView vTextAddSituation;
    @Override protected int getLayoutResID() {
        return R.layout.activity_main;
    }
    @Override protected ExternalRelations createExternalRelations() {
        return new ExternalRelations(this);
    }
    @Override protected void findViewAndSetListener() {
        vTextLocationAddress = (TextView)findViewById(R.id.vTextLocationAddress);
        vTextAddSituation = (TextView)findViewById(R.id.vTextAddSituation);
        vTextAddSituation.setOnClickListener(mExternalRelations.getOnAddSituationClickListener());
        ...
    }
    public void setLocationAddress(String locationAddress) {
        vTextLocationAddress.setText(locationAddress);
    }
    ...
}

public class ExternalRelations extends BaseExternalRelations {
    private MainActivity mMainActivity;
    private FileManager mFileManager;
    public ExternalRelations(MainActivity mainActivity) {
        mMainActivity = mainActivity;
        String filename = ... + ".txt";
        mFileManager = new FileManager(filename);
    }
    @Override public ActivityLifecycleCallback getActivityLifecycleCallback() {
        return new ActivityLifecycleCallback() {
            @Override
            public void onModulesCreated() { // 当各个模块都创建完成后,所执行的
                mFileManager.open();
                ...
            }
            @Override
            public void onDestroy() {
                mFileManager.close();
                ...
            }
        };
    }
    public View.OnClickListener getOnAddSituationClickListener() {
        return (v) -> {
            ...
        };
    }
}

九、数据与单纯计算所在模块、数据流

1.数据与单纯计算所在模块

业务数据在外部关系模块中,业务数据经过单纯计算,得到其他基础模块能够直接使用的数据(有时不需要单纯计算这一步);

A.例子一
类型的对象mList保存到文件,需要将mList转换为Json字符串,这一步视为单纯计算;
类型的对象,转换的这一步也视为单纯计算;

2.数据流

数据流图形如下:

[如图-数据与单纯计算所属模块]

十、作为例子的App

见附件文件:ProgramStructureGPS.20190922.zip,这是一个Android项目的压缩文件;
20190924.zip

相关文章
最新文章
热点推荐