基于对象消息编程的android开发框架

声明:本篇文章已授权微信公众号 guolin_blog (郭霖)独家发布

前言

    本着学习移动开发的目的看了郭神的《第一行代码》,但看完后我有种茫然的感觉。是的,知道了activity 、service等这些组件的用法,但如何搭建一个应用程序?一个个activity写么,每个activity臃肿而庞大,各种功能参合到一个activity?这无疑是很疯狂的。之前我大概了解php的开发,知道php开发有很多成熟的框架,比如thinkphp、Yii等框架。于是我在网上找android的开发框架。也许我没有耐心,我没有找到类似php的通用的android框架,许多框架基本是为了写代码或编程方便而集成的工具集,我不认为这属于程序框架,因此我决定自己写个框架。

     关于对象编程,我一直有个理念,就是对象之间的互动应该是通过消息来传递,而不是方法的调用。这样才能根本解除对象之间的耦合,对象、程序将更灵活。因此我着手写了对象消息编程框架,这个框架基本适于所有应用环境,包括web开发或本地应用,当然也适于android环境的开发。这里我将重点介绍对象消息编程框架如何应用在android开发上。

对象消息编程框架简介

     关于我的对象消息编程框架,这里只是简单的介绍,理解了框架原理就能容易理解框架如何在android上的应用了。

    一般我们的对象关系互动,基本是通过调用对方的方法,这种方式导致对象之间的耦合,对象失去了独立性。关于对象编程,我认为对象之间该通过消息的传递来互动,遵守以下约定:

1、对象之间只能通过收发消息来互动。一个对象不能调用另一个对象的方法、行为。对象的行为只能自己执行。

2、每个对象对收到的消息,采取或不采取行为完全取决对象本身。

3、对象由统一的创建者创建。

具体模型为:

源码程序包在cn.tianlong.tlobject 下,主要对象关系如下:

对象消息编程其实就是建立了一个对象模型、模板类—TLBaseModule。任何对象只要继承了这个类,将自动拥有消息处理、发送的能力。任何对象之间通过消息的传递来互动。消息为标准消息类(类TLMsg )。对象或者模块通过模块工厂TLObjectFactory创建,方便对象的创建、传递、保存、重复利用等。每个对象可以有自己的配置文件,配置文件为包含统一的配置项目,当然根据对象自身特点,可以增加特性项目。

具体对象消息编程框架理念及实现详见 https://blog.csdn.net/tianlong117 

android 对象消息编程框架

现在将对象消息框架应用到android环境上,源码结构如下:

     上图的源码结构,cn.tianlong.tlojbect 为通用消息对象编程框架 ,这是各种环境下的共同应用包。cn.tianlong.tlandroid为消息框架在android环境上的应用。其中base为基本包。utils 、view包为我将一些android组件进行了重新包装,我对android组件非常不满意,设计比较复杂,应用也麻烦,这些包仅仅是我的粗浅封装,大家可以根据自己的喜好是否采用或者重新封装、修改。这些我封装的组件不是框架的一部分,仅仅是为了编程而设计,框架的基本还是base包

      框架的基本流程可以说是mvc或者mvp模式,但我建议大家忘记mvc、mvp的概念。这里的对象都是通过消息而传递。用消息的理念来理解框架。那么对于一个activity来说 ,它仅仅是发出用户的输入消息,如最常用的按键消息,同时接受控件输出消息。activity不包含任何逻辑、业务功能。那么activtiy可以相当于mvc中的v。activity相当于一个输入输出模块,对于用户一个输入消息,activity捕获后发给对应的消息处理模块,消息处理模块针对该消息处理,将返回结果反馈给activity,activity将消息进行输出。

    由于对象之间互动通过发送消息,实际中activity可以给每个对象或组件发送消息,但为了消息流程清晰,我们建立一个appcenter,各组件可以通过这个app中心来传递消息,当然没有这样的硬性要求,同时appcenter还负责程序配置、初始化等。对于具体实现方式,有以下可参考模式:

对于功能简单的activity:

activity 直接将消息发送给appcenter,appcenter处理消息。

对于复杂的activity:

对于复杂程序,如果activtiy消息都传给appcenter,将导致appcenter臃肿、逻辑不清,因此可以针对activity单独配置一个app模块,由该模块处理相应的activity消息。

开发应用时,需自行继承appcenter或app来实现自己的个性模块。

下面我们看具体实现案例,当时我没有其他案例代码,于是对郭神的《第一行代码》里面一些案例进行了重新封装,主要目的是测试框架的可行性。(框架及demo代码见文章下)

案例一:

   在郭神的《第一行代码》中有个用来演示RecyelerView的聊天案例,我们这里对这个简单程序做以重构,用消息对象编程的方式来实现,基本代码还是原案例的,这里主要演示消息框架的原理。

我们先看activity 源码:

public class MainActivity extends TLBaseActivity {
    private List<Msg> msgList = new ArrayList<Msg>();
    private EditText inputText;
    private Button send;
    private RecyclerView msgRecyclerView;
    private MsgAdapter adapter;
    RecyclerView recyclerView ;
    RecyclerViewAdapterDatas adapterDatas ;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main_msg);
        inputText = (EditText) findViewById(R.id.input_text);
        TLMsg msg =createMsg().setAction("recyclerView")
            .setParam("activity",this)
           .setParam("id",R.id.msg_recycler_view)
           .setParam("laylout","linear")
           .setParam("spancount",3)
           .setParam("adapter","msgrecyclerViewAdapterdata");
        TLMsg resultMsg=putMsg(moduleFactory,msg);
        recyclerView=(RecyclerView)resultMsg.getParam("viewInstance");
        adapterDatas=(RecyclerViewAdapterDatas)resultMsg.getParam("adapterdata");
        send = (Button) findViewById(R.id.send);
        send.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                String content = inputText.getText().toString();
                if (!"".equals(content)) {
                    Msg rmsg = new Msg(content, Msg.TYPE_SENT);
                    putMsg(adapterDatas,new TLMsg("viewRefresh","msg",rmsg)) ;
                    inputText.setText(""); // 清空输入框中的内容
                }
            }
        });
    }
    @Override
    protected void onResume() {
        super.onResume();
    }
    @Override
    public TLMsg getMsg(Object fromWho, TLMsg msg) {
        return null;
    }
}

  前面说过所有的对象或组件通过对象工厂创建,因此,下面代码通过工厂获取recyclerView及其适配器。     

TLMsg msg =createMsg().setAction("recyclerView")
.setParam("activity",this)
.setParam("id",R.id.msg_recycler_view)
.setParam("laylout","linear")
.setParam("spancount",3)
.setParam("adapter","msgrecyclerViewAdapterdata");
TLMsg resultMsg=putMsg(moduleFactory,msg);
recyclerView=(RecyclerView)resultMsg.getParam("viewInstance");
adapterDatas=(RecyclerViewAdapterDatas)resultMsg.getParam("adapterdata");

首先构建工厂消息msg,然后将消息发送给工厂

putMsg(moduleFactory,msg);

通过返回的消息resultMsg里提取recyclerView、adapterDatas对象。为了方便,这里的recyclerView由我进行了重新包装的。

对于每一个聊天内容,我们将消息发给adapterDatas,由adapterDatas控制recyclerView显示。

putMsg(adapterDatas,new TLMsg("viewRefresh","msg",rmsg)) ;

在适配器RecyclerViewAdapterDatas中,适配器获取了activity传来的消息,执行方法viewRefresh进行页面刷新。

@Override
public void viewRefresh(Object fromWho, TLMsg msg) {
    dataList.add((Msg)msg.getParam("msg"));
    putMsg(appCenter,new TLMsg("setDatas","msgList",dataList)) ; //数据保存至appcenter,防止页面返回时数据丢失
    adapter.notifyItemInserted(dataList.size() - 1); // 当有新消息时,刷新ListView中的显示
    recyclerView.scrollToPosition(dataList.size() - 1); // 将ListView定位到最后一行

}

由这简单的案例看出,这里activity仅仅是获取消息、发送消息,对消息没有任何逻辑处理,同时也不控制recyclerView。对象的角色、及关系变得清晰。

案例二 手机信号及基站信息:

  现在我们看复杂点的案例-手机信号及基站信息。页面如下:

这个案例实现以下功能:

1、获取手机信号、基站信息  

2、根据基站信息查询互联网获取基站位置

3、将基站信息保存到本地、上传到服务器。可手动及自动保存、上传。自动保存启动时,5秒自动保存、上传一次。

该案例涉及了数据库读写、远端web查询、数据提交。

现在我们看主activity代码。

activity获取用户输入、创建相应的消息并传递给对应的app处理:

@Override
public void onClick(View v) {
    TLMsg msg =createMsg();
    switch (v.getId()) {
        case R.id.button_m:
            msg.setMsgId("startactivity");  ;
            msg.setParam("classname", RecoderActivity.class);
            putMsg(appCenter,msg);
            break;
        case R.id.button_post:
            msg.setAction("postData");
            putMyApp(msg);
            break;
        case R.id.button_save:
            msg.setAction("saveData");
            putMyApp(msg);
            break;
        case R.id.button_autosave:
            msg.clear();
            msg.setAction("autosaveData");
            putMyApp(msg);
            break;
    }
}

activity获取消息处理模块返回的结果,根据消息类别输出显示结果:

public TLMsg getMsg(Object fromWho, TLMsg msg) {
    switch (msg.getAction()) {
        case "getSignal":
            showResponse( msg) ;
            break;
        case "jizhan":
            showjizhan( msg) ;
            break;
        case "myrecords":
            myrecords( msg) ;
            break;
        case "postReturn":
            postReturn( msg) ;
            break;
        case "serviceReturn":
            serviceReturn( msg) ;
            break;
        case "saveReturn":
               runOnUiThread(new Runnable() {
                     @Override
                     public void run() {
                         savetext.setText("保存成功"+i+"次!");
                         i++;
                     }
              });
            break;
        default:
    }
    return  null ;
}
private void serviceReturn(TLMsg msg) {
    final String content;

    if(msg.getParam("error")!=null && (boolean)msg.getParam("error")==false)
    {
         content ="上传"+p+"次!"+ TLMsgUtils.msgToGson(msg);
         p++;
    }
    else
        if(msg.getParam("netstate")!=null &&(boolean)msg.getParam("netstate")==false )
    {
        content="没有打开网络";
    }
    else
        {
            content="上传错误"+m+"次!";
            m++;
        }
    postresulttext.setText(content);
}

activity 实现输入、输出功能,业务逻辑由对应的app模块TLSignalApp 来实现。在TLSignalApp 中,也是根据传来的消息执行各个业务功能或模块:

@Override
protected TLMsg myCheckMsgCmd(Object fromWho, TLMsg msg) {
    TLMsg returnMsg=null;
    switch (msg.getAction()) {
        case "setup":
            cell_id="";
            lac ="";
            putMsg(tltm,new TLMsg("init","listener",this)
                    .setParam("listenAction","getSignal"));
            break;
        case "getSignal":
            getSignal( msg);
            break;
        case "jizhanData":
            jizhandata(fromWho,msg);
            break;
        case "postData":
            postjizhan(data);
            break;
        case "postReturn":
            postReturn(fromWho,msg);
            break;
        case "serviceReturn":
            serviceReturn(fromWho,msg);
            break;
        case "saveData":
            saveData();
            break;
        case "autosaveData":
            putMsg(jztask,createMsg().setAction("startTask"));
            break;
        case "getData":
            returnMsg=createMsg().setParam("data",dbmsg);
            break;
        default:
    }
    return returnMsg ;
}

这里不进行详细分析了,由于对象之间通过消息传递实现互动,通过跟踪消息路径,逻辑比较清晰,因此代码也容易阅读。

结束语

       限于篇幅无法对框架详细介绍,有兴趣的朋友可在博客上进一步了解消息框架结构。熟悉了对象消息框架也很容易了解框架如何应用在android环境上了 。限于本人经历及知识,这只是本人的学习尝试和探索,框架的代码也很粗糙,仅仅是希望起到抛砖引玉的作用,共同探索编程之道吧。

源码地址:app20180926.rar_免费高速下载|百度网盘-分享无限制

     代码在android Studio 上开发 ,解压目录对应app目录 

           

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值