精华内容
参与话题
问答
  • android架构

    2014-06-30 09:53:19
    1、架构图直观2、架构详解 2.1、Linux Kernel2.1、Android Runtime2.3、Libraries2.4、Application Framework2.5、Applications ...图1、Android系统架构(来源于:android sdk) 可以很明显
    • 1、架构图直观
    • 2、架构详解
      • 2.1、Linux Kernel
      • 2.1、Android Runtime
      • 2.3、Libraries
      • 2.4、Application Framework
      • 2.5、Applications
    • 3、总结

    1、架构图直观

    下面这张图展示了Android系统的主要组成部分:

    Android_system_architecture

    图1、Android系统架构(来源于:android sdk)

    可以很明显看出,Android系统架构由5部分组成,分别是:Linux Kernel、Android Runtime、Libraries、Application Framework、Applications。第二部分将详细介绍这5个部分。

    2、架构详解

    现在我们拿起手术刀来剖析各个部分。其实这部分SDK文档已经帮我们做得很好了,我们要做的就是拿来主义,然后再加上自己理解。下面自底向上分析各层。

    2.1、Linux Kernel

    Android基于Linux 2.6提供核心系统服务,例如:安全、内存管理、进程管理、网络堆栈、驱动模型。Linux Kernel也作为硬件和软件之间的抽象层,它隐藏具体硬件细节而为上层提供统一的服务。

    如果你学过计算机网络知道OSI/RM,就会知道分层的好处就是使用下层提供的服务而为上层提供统一的服务,屏蔽本层及以下层的差异,当本层及以下层发生了变化不会影响到上层。也就是说各层各司其职,各层提供固定的SAP(Service Access Point),专业点可以说是高内聚、低耦合。

    如果你只是做应用开发,就不需要深入了解Linux Kernel层。

    2.2、Android Runtime

    Android包含一个核心库的集合,提供大部分在Java编程语言核心类库中可用的功能。每一个Android应用程序是Dalvik虚拟机中的实例,运行在他们自己的进程中。Dalvik虚拟机设计成,在一个设备可以高效地运行多个虚拟机。Dalvik虚拟机可执行文件格式是.dex,dex格式是专为Dalvik设计的一种压缩格式,适合内存和处理器速度有限的系统。

    大多数虚拟机包括JVM都是基于栈的,而Dalvik虚拟机则是基于寄存器的。两种架构各有优劣,一般而言,基于栈的机器需要更多指令,而基于寄存器的机器指令更大。dx 是一套工具,可以將 Java .class 转换成 .dex 格式。一个dex文件通常会有多个.class。由于dex有時必须进行最佳化,会使文件大小增加1-4倍,以ODEX结尾。

    Dalvik虚拟机依赖于Linux 内核提供基本功能,如线程和底层内存管理。

    2.3、Libraries

    Android包含一个C/C++库的集合,供Android系统的各个组件使用。这些功能通过Android的应用程序框架(application framework)暴露给开发者。下面列出一些核心库:

    • 系统C库——标准C系统库(libc)的BSD衍生,调整为基于嵌入式Linux设备
    • 媒体库——基于PacketVideo的OpenCORE。这些库支持播放和录制许多流行的音频和视频格式,以及静态图像文件,包括MPEG4、 H.264、 MP3、 AAC、 AMR、JPG、 PNG
    • 界面管理——管理访问显示子系统和无缝组合多个应用程序的二维和三维图形层
    • LibWebCore——新式的Web浏览器引擎,驱动Android 浏览器和内嵌的web视图
    • SGL——基本的2D图形引擎
    • 3D库——基于OpenGL ES 1.0 APIs的实现。库使用硬件3D加速或包含高度优化的3D软件光栅
    • FreeType ——位图和矢量字体渲染
    • SQLite ——所有应用程序都可以使用的强大而轻量级的关系数据库引擎

    2.4、Application Framework

    通过提供开放的开发平台,Android使开发者能够编制极其丰富和新颖的应用程序。开发者可以自由地利用设备硬件优势、访问位置信息、运行后台服务、设置闹钟、向状态栏添加通知等等,很多很多。

    开发者可以完全使用核心应用程序所使用的框架APIs。应用程序的体系结构旨在简化组件的重用,任何应用程序都能发布他的功能且任何其他应用程序可以使用这些功能(需要服从框架执行的安全限制)。这一机制允许用户替换组件。

    所有的应用程序其实是一组服务和系统,包括:

    • 视图(View)——丰富的、可扩展的视图集合,可用于构建一个应用程序。包括包括列表、网格、文本框、按钮,甚至是内嵌的网页浏览器
    • 内容提供者(Content Providers)——使应用程序能访问其他应用程序(如通讯录)的数据,或共享自己的数据
    • 资源管理器(Resource Manager)——提供访问非代码资源,如本地化字符串、图形和布局文件
    • 通知管理器(Notification Manager——使所有的应用程序能够在状态栏显示自定义警告
    • 活动管理器(Activity Manager——管理应用程序生命周期,提供通用的导航回退功能

    2.5、Applications

    Android装配一个核心应用程序集合,包括电子邮件客户端、SMS程序、日历、地图、浏览器、联系人和其他设置。所有应用程序都是用Java编程语言写的。更加丰富的应用程序有待我们去开发!

    3、总结

    从上面我们知道Android的架构是分层的,非常清晰,分工很明确。Android本身是一套软件堆叠(Software Stack),或称为「软件叠层架构」,叠层主要分成三层:操作系统、中间件、应用程序。从上面我们也看到了开源的力量,一个个熟悉的开源软件在这里贡献了自己的一份力量。

    现在我们对android的系统架构有了一个整体上的了解,我将用一个例子来深入体会一下,但是考虑到此系列希望0基础的人也能看懂,在介绍例子之前将介绍一下Android应用程序的原理及一些术语,可能需要几篇来介绍。敬请关注!

    展开全文
  • Android架构

    千次阅读 2010-09-25 14:56:00
    1、架构图直观 2、架构详解 2.1、Linux Kernel 2.1、Android Runtime 2.3、...Android系统架构(来源于:android sdk)可以很明显看出,Android系统架构由5部 分组成,分别是:Linux Kernel、Android Runtime、Libra




    Android_system_architecture

    图1、Android系统架构(来源于:android sdk)

    可以很明显看出,Android系统架构由5部分组成,分别是:Linux Kernel、Android Runtime、Libraries、Application Framework、Applications。第二部分将详细介绍这5个部分。

    2、架构详解

    现在我们拿起手术刀来剖析各个部分。其实这部分SDK文档已经帮我们做得很好了,我们要做的就是拿来主义,然后再加上自己理解。下面自底向上分析各层。

    2.1、Linux Kernel

    Android基于Linux 2.6提供核心系统服务,例如:安全、内存管理、进程管理、网络堆栈、驱动模型。Linux Kernel也作为硬件和软件之间的抽象层,它隐藏具体硬件细节而为上层提供统一的服务。

    如果你学过计算机网络知道OSI/RM,就会知道分层的好处就是使用下层提供的服务而为上层提供统一的服务,屏蔽本层及以下层的差异,当本层及以下层发生了变化不会影响到上层。也就是说各层各司其职,各层提供固定的SAP(Service Access Point),专业点可以说是高内聚、低耦合。

    如果你只是做应用开发,就不需要深入了解Linux Kernel层。

    2.2、Android Runtime

    Android包含一个核心库的集合,提供大部分在Java编程语言核心类库中可用的功能。每一个Android应用程序是Dalvik虚拟机中的实例,运行在他们自己的进程中。Dalvik虚拟机设计成,在一个设备可以高效地运行多个虚拟机。Dalvik虚拟机可执行文件格式是.dex,dex格式是专为Dalvik设计的一种压缩格式,适合内存和处理器速度有限的系统。

    大多数虚拟机包括JVM都是基于栈的,而Dalvik虚拟机则是基于寄存器的。两种架构各有优劣,一般而言,基于栈的机器需要更多指令,而基于寄存器的机器指令更大。dx 是一套工具,可以將 Java .class 转换成 .dex 格式。一个dex文件通常会有多个.class。由于dex有時必须进行最佳化,会使文件大小增加1-4倍,以ODEX结尾。

    Dalvik虚拟机依赖于Linux 内核提供基本功能,如线程和底层内存管理。

    2.3、Libraries(本地库)

    Android包含一个C/C++库的集合,供Android系统的各个组件使用。这些功能通过Android的应用程序框架(application framework)暴露给开发者。下面列出一些核心库:

    • 系统C库——标准C系统库(libc)的BSD衍生,调整为基于嵌入式Linux设备
    • 媒体库——基于PacketVideo的OpenCORE。这些库支持播放和录制许多流行的音频和视频格式,以及静态图像文件,包括MPEG4、 H.264、 MP3、 AAC、 AMR、JPG、 PNG
    • 界面管理——管理访问显示子系统和无缝组合多个应用程序的二维和三维图形层
    • LibWebCore——新式的Web浏览器引擎,驱动Android 浏览器和内嵌的web视图
    • SGL——基本的2D图形引擎
    • 3D库——基于OpenGL ES 1.0 APIs的实现。库使用硬件3D加速或包含高度优化的3D软件光栅
    • FreeType ——位图和矢量字体渲染
    • SQLite ——所有应用程序都可以使用的强大而轻量级的关系数据库引擎

    2.4、Application Framework

    通过提供开放的开发平台,Android使开发者能够编制极其丰富和新颖的应用程序。开发者可以自由地利用设备硬件优势、访问位置信息、运行后台服务、设置闹钟、向状态栏添加通知等等,很多很多。

    开发者可以完全使用核心应用程序所使用的框架APIs。应用程序的体系结构旨在简化组件的重用,任何应用程序都能发布他的功能且任何其他应用程序可以使用这些功能(需要服从框架执行的安全限制)。这一机制允许用户替换组件。

    所有的应用程序其实是一组服务和系统,包括:

    • 视图(View)——丰富的、可扩展的视图集合,可用于构建一个应用程序。包括包括列表、网格、文本框、按钮,甚至是内嵌的网页浏览器
    • 内容提供者(Content Providers)——使应用程序能访问其他应用程序(如通讯录)的数据,或共享自己的数据
    • 资源管理器(Resource Manager)——提供访问非代码资源,如本地化字符串、图形和布局文件
    • 通知管理器(NotificationManager——使所有的应用程序能够在状态栏显示自定义警告
    • 活动管理器(Activity Manager——管理应用程序生命周期,提供通用的导航回退功能

    2.5、Applications

    Android装配一个核心应用程序集合,包括电子邮件客户端、SMS程序、日历、地图、浏览器、联系人和其他设置。所有应用程序都是用Java编程语言写的。更加丰富的应用程序有待我们去开发!

    3、总结

    从上面我们知道Android的架构是分层的,非常清晰,分工很明确。Android本身是一套软件堆叠(Software Stack),或称为「软件叠层架构」,叠层主要分成三层:操作系统、中间件、应用程序。从上面我们也看到了开源的力量,一个个熟悉的开源软件在这里贡献了自己的一份力量。

    现在我们对android的系统架构有了一个整体上的了解,我将用一个例子来深入体会一下,但是考虑到此系列希望0基础的人也能看懂,在介绍例子之前将介绍一下Android应用程序的原理及一些术语

    转自:http://www.cnblogs.com/skynet/archive/2010/04/15/1712924.html

    展开全文
  • 14天学会安卓开发(第一天)Android架构与环境搭建

    千次阅读 多人点赞 2012-12-18 02:14:54
    14天学会安卓开发  作者:神秘的N (英文名 corder_raine) 联系方式:369428455(反馈) 交流群:284552167(示例,原文档...第一天Android架构与环境搭建... 4 1.1 android基础... 4 1.1.1 Android是什么?. 4

    14天学会安卓开发  
    作者:神秘的N (英文名  corder_raine)
    联系方式:369428455(反馈)
    交流群:284552167(示例,原文档下载)


    版权为作者所有,如有转载请注明出处

    目录


    第一天Android架构与环境搭建... 4
    1.1 android基础... 4

    1.1.1 Android是什么?. 4
    1.1.2 Android的特点! 5
    1.1.3 Android优缺点! 5
    1.1.4 Android架构... 6

    1.2搭建android环境... 10

    1.2.1 安装JavaJDK 并配置java环境变量. 10
    1.2.2 下载eclipse安装ADT插件... 12
    1.2.3 安装androidsdk 并更新版本... 15
    1.2.4 配置android环境变量. 18
    1.2.5 配置ADV安卓虚拟机 并写hello android 测试... 19
    1.2.6 特别赠送:直接下载AndroidDeveloper Tools即可省略以上5个步骤... 22


    第一天 Android架构与环境搭建
    1.1 android基础
    1.1.1 Android是什么?
    Ø  是一个针对移动设备的操作系统和软件平台
    Ø  基于Linux内核
    Ø  由 Google和开放手机联盟OHA开发的
    Ø  容许使用Java语言来开发和管理代码
    Ø  Android开放源代码,Android遵从Apache Software License (ASL)2.0版本的协议
    Ø  Android于2007年11月5日开放手机联盟成立时发布

    注:开放手机联盟 (OHA)

    QQ截图20121204032540.png 

    1.1.2 Android的特点!
    Ø  应用框架可以重复使用,其组件也可以更换。
    Ø  Dalvik虚拟机针对移动设备进行了优化。
    Ø  优化的图形能力支持2D、3D图形(OpenGL ES 1.0 )。
    Ø  集成了基于开源WebKit引掣的浏览器。
    Ø  SQLite作为结构化数据存储。
    Ø  多媒体支持多种音频、视频格式。
    Ø  GSM Telephony (hardware dependent)
    Ø  支持蓝牙Bluetooth,3G和WiFi
    Ø  支持照相机、GPS、指南针和加速度仪等传感器硬件。
    Ø  丰富的开发环境。包括模拟机、调试工具、内存运行检测,以及为EclipseIDE所写的插件。

    1.1.3 Android优缺点!
    优点

    Ø  源代码完全开放。
    Ø  采用了对有限内存、电池和CPU优化过的虚拟机Dalvik,Android的运行速度比想象的要快很多。
    Ø  运营商(中国移动等)的大力支持,产业链条的热捧。
    Ø  良好的盈利模式(3/7 开),产业链条的各方:运营商、制造商、独立软件生产商都可以获得不错的利益。将移动终端的评价标准从硬件向软件转变,极大的激发了软件开发者的热情。
    Ø  Android的源代码遵循Apache V2软件许可,而不是通常的GPL v2许可。有利于商业开发。
    Ø  具有强大的Linux社区的支持。




    缺点
    Ø    Google提供了一套Java核心包(J2SE 5,J2SE 6)的有限子集,尚不承诺遵守Java任何Java规范,可能会造成Java阵营的进一步分裂。
    Ø  现有应用完善度不太够,需要的开发工作量较大。
    Ø  模拟器调试手段不十分丰富,速度慢。





    1.1.4 Android架构
    2.png 

    Linux Kernel& Android内核

    Ø  Android 基于Linux内核,但不是Linux
    Ø  内核提供系统核心服务,如进程、内存、电源管理,网络连接,驱动与安全等。
    Ø  并不包括全部的Linux。
    Ø  Linux 内核位于硬件和软件堆之间的抽象层
    u  核心服务:安全机制、内存管理、进程管理、网络、硬件驱动。
    u  内核扮演的是硬件层和系统其它层次之间的一个抽象层的概念。
    u  操作系统的初始化和编程接口和标准的Linux 系统是有所不同的。


    Libraries

    Ø  C/C++库:被各种Android 组件使用通过应用程序框架开发者可以使用其功能包括:
    Ø  媒体库:MPEG4 H.264 MP3 JPG PNG .....
    Ø  WebKit/LibWebCore:Web 浏览引擎
    Ø  SQLite 关系数据库引擎
    Ø  2D,3D 图形库、引擎



    Function Libraries
    Ø  WebKit
    Ø  基于开源WebKit的浏览器
    Ø  支持CSS、Javascript、DOM、Ajax
    Ø  多媒体框架
    Ø  基于PacketVideo OpenCORE平台
    Ø  支持标准音频、视频
    Ø  SQLite
    Ø  轻型数据库,支持多种平台


    Native Servers-Surface
    Ø  为多种应用提供2D、3D表面设计
    3.png 
    Native Servers-Audio
    Ø  音频处理

    4.png 

    Hardware Abstraction Libs
    Ø  硬件虚拟层
    Ø  User space C/C++ library layer
    Ø  硬件接口驱动
    Ø  使Android平台逻辑与硬件接口分离
    5.png 
    DVM vs JVM

    Ø  DVM
    u  Google
    u  Dalvik excutable
    JVM
    u  Sun
    u  Java bytecode


    Applications Framework
    Ø  Activity manager
    u  管理运行应用程序
    Ø  Content Provider
    u  在各应用之间共享数据
    Ø  Resource Manager
    u  管理非代码资源
    Ø  Notification Manager
    u  显示用户提示和状态栏
    Ø  Views System
    u  可扩展显示,可构建UI

    6.png 

    应用和框架
    Ø  核心应用,例如联系人,电子邮件,电话,浏览器,日历,地图, ...
    Ø  充分访问所有核心应用框架API
    Ø  简化组件的重用
    Ø  用Java 编写应用程序


    Applications
    Ø  JAVA编写的应用程序

    7.png 



    1.2搭建android环境
    :如果想从头开始学怎么搭建android开发环境的请从1.2.1开始
    如果想直接学开发了,请跳过此步骤,1.2.6节直接下载谷歌提供的开发工具进行开发.

    1.2.1 安装Java JDK 并配置java环境变量.
    下载JDK(官方推荐使用1.6版本)


    安装JDK略过

    打开环境变量窗口方法:右键【我的电脑】--单击【属性】--单击【高级】--单击【环境变量】。
    在上方的用户变量中依次新建如下变量,并分别填入如下路径:


    à变量名:JAVA_HOME
    变量值:C:Javajdk1.6.0_22(此路径为JAVA安装路径)


    à变量名:PATH
    变量值:%JAVA_HOME%/bin

    à变量名:CLASSPATH
    变量值:.;%JAVA_HOME%/lib/tools.jar;%JAVA_HOME%/lib/dt.jar

    8.png 

    测试环境变量配置是否成功
    【开始】--【运行】--输入【cmd】--输入【javac】--按【回车键】若看到以下信息,则代表配置成功。

    9.png 


    1.2.2 下载eclipse 安装ADT插件
    Eclipse下载地址:http://www.eclipse.org/downloads/(javaJ2EE都行)


    10.png 
    安装ADT


    注意:
    安装ADT的方法有两种
    一  在线安装(输入Name和Location即可在线安装,不推荐使用,因为在线更新灰常慢)  
    Name:Andriod Plugin
    Location:https://dl-ssl.google.com/android/eclipse/



    11.png 
    12.png 


    执意想要在线更新的朋友,我们只需要配置一下hosts文件(翻墙不用我说吧?)
    Hosts文件只需要在C盘搜索一下就出来了
    13.png 

    在文件的末尾添加下面一句:74.125.237.1dl-ssl.google.com
    (记得右键吧hosts文件只读的勾去了)

    14.png 
    二  离线安装(离线安装要断网,不然它会自动联网安装的)

    15.png 
          离线更新有两种方法
    1点local..选择解压出来的ADT文件夹(好处是解包已在外部完成了,可以直接更新,不用等待,推荐使用)
    2.点archive选择打包的ADT(好处是不用在外部解包,但是不可直接更新,要等eclipse解包完ADT.ZIP才能进行安装,不推荐使用)
    如果推荐使用的方法不行,哪就用其他方法吧!
    1.2.3 安装android sdk 并更新版本
    安装完ADT之后它会提示你重启eclipse,重启完后会提示选择在线更新SDK还是选现有的SDK(这里只说明选现有的SDK)
    注意:记得选第二个,默认的是让你选路径下载SDK的


    离线安装Sdk

    16.png 
    17.png 
    找到SDK路径应用一下就可以了

    18.png 
    管理自己的SDK,升级或者更新

    19.png 
    20.png 
    在自己需要的版本上打勾然后按install   (一般开发都用2.1,谷歌会提示你95%的开发者都在用2.1之类的话的)


    点击install后如下图,选择所有再点install

    21.png 
    更新完后就大功告成了
    1.2.4 配置android环境变量.
          在上方的用户变量中找到之前创建的【PATH】变量,双击它,然后在【变量值】                                            的最后面添加上内容
    【;E:Androidandroid-sdk-windows        ools;E:Androidandroid-sdk-windowsplatform-tools】
    其中的分号不能少,分号在这里是起到分隔的作用。
      配置完成之后,分别点击【开始】--【运行】--输入【cmd】--输入【android -h】--按【回车键】,若看到以下信息,则代表配置成功。
    22.png 
    1.2.5 配置ADV 安卓虚拟机 并写hello android 测试
    23.png 
    24.png 
    25.png 

    1.2.6 特别赠送:直接下载AndroidDeveloper Tools即可省略以上5个步骤
    直接下载AndroidDeveloper Tools  即可使用
    官方已经推出集成ADT 和最新SDK(4.2版本)的eclipse了
    命名为AndroidDeveloper Tools
    或者联系作者获取

    如需安装其他版本SDK请看第3步

    26.png 



    27.png 
    28.png 
    写第一个android程序

    29.png 
    30.png 
    31.png 
    32.png 
    33.png 
    第一个程序就创建好了,如下图启动你的程序
    34.png 








    如图,测试成功.第一天的android课程结束.

    35.png 







    源代码下载
    HelloAndroid源码
    展开全文
  • Android 架构 ~ MVP 架构Android 中的实践

    万次阅读 多人点赞 2017-01-30 16:05:08
    本文通过登录案例介绍了 MVP 架构Android App 中的实践和使用心得,同时也在 CSDN 首页推荐

    欢迎转载,转载请标明出处:
    http://blog.csdn.net/johnny901114/article/details/54783106
    本文出自:【Chiclaim的博客】

    为什么要重视程序的架构设计

    对程序进行架构设计的原因,归根结底是为了提高生产力。架构设计是程序模块化,做到模块内部的高聚合和模块之间的低耦合(如依赖注入就是低耦合的集中体现)。

    这样做的好处是使得程序开发过程中,开发人员主需要专注于一点,提高程序开发的效率,并且更容易进行后续的测试以及定位问题。

    但是,设计不能违背目的,对于不同量级的工程,具体的架构实现方式必然不同,不要为了设计而设计,为了架构而架构。比如一个android app如果只有几个Java文件,那只需要做点模块和层次的划分就可以了。引入框架或者架构增加了工作量,降低了生产力。

    所以在开发的时候需要考虑:

    1)当前这个项目是否需要以最快速度上线。比如有些创业公司,争取的就是时间,公司老板是要拿着这个app是去找投资的。

    2)如果这个项目开发周期还可以,第一个版本就可以把app架构做好。因为一个App肯定是朝着慢慢做大的方向去的,如果等业务到了一定程度了,再去重构的话,成本就有点大。

    什么是MVP?

    MVP架构由MVC发展而来。在MVP中,M代表Model,V代表View,P代表Presenter。

    Model 负责获取数据,数据的来源可以是网络或本地数据库等;

    View 负责界面数据的展示,与用户进行交互;

    Presenter 是Model与View之间的通信的桥梁,将Model与View分离开来。

    MVP架构图:
    MVP

    所以MVP的架构有如下好处:

    1)降低了View和Model的耦合,通过Presenter层来通信;

    2)把视图层抽象到View接口,逻辑层抽象到Presenter接口,提高了代码的可读性、可维护性;

    3)Activity和Fragment功能变得更加单一,只需要处理View相关的逻辑;

    4)Presenter抽象成接口,就可以有多种实现,方便单元测试。

    下面就来实际的体验一下MVP在项目中的使用吧!(用户注册文章详情两个例子)

    用户注册

    功能界面如下图所示(注册、登录):

    20170130125437322

    下面是完整的代码,主要实现了验证码注册、登录的功能,可能代码比较多:

    Model部分

    public class UserEngine extends BaseEngine {
    
        public static final int ID_LOGIN = 1;
        public static final int ID_REGISTER = 2;
    
        private UserApi userApi;
    
        private UserEngine(Callback callback, int... ids) {
            super(callback, ids);
            userApi = ApiFactory.createService(UserApi.class, true);
        }
    
        public static UserEngine getInstance(Callback callback, int... ids) {
            return new UserEngine(callback, ids);
        }
    
        /**
         * 用户登录
         *
         * @param phone    手机号码
         * @param password 密码
         */
        public void login(String phone, String password) {
            //请求服务器
            //成功失败,通过回调通知
        }
    
        /**
         * 用户注册
         */
        public void register(String phone, String password) {
            //请求服务器
            //成功失败,通过回调通知
        }
    }
    
    

    View

    
    public interface BaseView {
    
        void showToast(String message);
    
        void showLoading();
    
        void hideLoading();
    
    }
    
    public interface ILoginView extends BaseView {
    
        /**
         * 切换 登录/注册 界面
         */
        void switchUiByActionType(int actionType);
    
        /**
         * 用户名错误
         *
         * @param errorMsg 错误消息
         */
        void setUsernameError(String errorMsg);
    
        /**
         * 验证码错误
         */
        void setCodeError(String errorMsg);
    
        /**
         * 密码错误
         *
         * @param errorMsg 错误消息
         */
        void setPasswordError(String errorMsg);
    
        /**
         * 登录成功
         */
        void loginSuccess();
    
        /**
         * 校验验证码成功
         *
         * @param data 成功数据
         */
        void verifySmsCodeSuccess(Object data);
    
        /**
         * 发送验证码成功
         *
         * @param data 成功数据
         */
        void sendSmsCodeSuccess(Object data);
    
        /**
         * 获取手机号支持的国家
         *
         * @param data 成功数据
         */
        void getSupportCountrySuccess(Object data);
    
    }
    
    //Activity 实现IView接口
    public class UserLoginActivity extends BaseActivity<UserLoginBinding> implements ILoginView
            , MyCountDownTimer.CountDownCallback {
    
    
        private static final int ACTION_TYPE_LOGIN = 1;
        private static final int ACTION_TYPE_REGISTER = 2;
    
    
        private LoginPresenterImpl loginPresenter;
    
        private MyCountDownTimer countDownTimer;
    
        private int actionType;
    
        public static void launchForLogin(Context context) {
            Intent intent = new Intent(context, UserLoginActivity.class);
            intent.putExtra("actionType", ACTION_TYPE_LOGIN);
            context.startActivity(intent);
        }
    
    
        public static void launchForRegister(Context context) {
            Intent intent = new Intent(context, UserLoginActivity.class);
            intent.putExtra("actionType", ACTION_TYPE_REGISTER);
            context.startActivity(intent);
        }
    
        @Override
        protected void initParams() {
            super.initParams();
            //默认为登录界面
            actionType = getIntent().getIntExtra("actionType", ACTION_TYPE_LOGIN);
            loginPresenter = new LoginPresenterImpl(this);
            countDownTimer = new MyCountDownTimer(60000, 1000, this);
        }
    
        @Override
        protected void initViews() {
            super.initViews();
            setTitle("登录");
    
            binding.btnLoginRegister.setOnClickListener(this);
            binding.tvGetCode.setOnClickListener(this);
            binding.tvToggleUi.setOnClickListener(this);
    
            loginPresenter.initSMSSDK(this);
            loginPresenter.switchUiByActionType(actionType);
        }
    
        @Override
        protected int getLayoutId() {
            return R.layout.activity_user_login_layout;
        }
    
        @TargetApi(Build.VERSION_CODES.KITKAT)
        @Override
        public void onClick(View view) {
            super.onClick(view);
            switch (view.getId()) {
                case R.id.tv_get_code:
                    loginPresenter.sendVerificationCode(binding.etUsername.getText().toString());
                    break;
                case R.id.btn_login_register:
                    if (actionType == ACTION_TYPE_LOGIN) {
                        loginPresenter.login(xxx);
                    } else {
                        loginPresenter.submitVerificationCode(xxx);
                    }
                    break;
                case R.id.tv_toggle_ui:
                    if (VersionUtils.hasKITKAT()) {
                        TransitionManager.beginDelayedTransition(binding.llContainer);
                    }
                    loginPresenter.switchUiByActionType(
                            actionType == ACTION_TYPE_LOGIN ? ACTION_TYPE_REGISTER : ACTION_TYPE_LOGIN);
                    break;
            }
        }
    
        @Override
        public void showToast(String message) {
            ToastUtils.showShortToast(this, message);
        }
    
    
        @Override
        protected void onDestroy() {
            super.onDestroy();
            if (countDownTimer != null) {
                countDownTimer.cancel();
            }
            loginPresenter.destroy();
        }
    
        @Override
        public void switchUiByActionType(int actionType) {
            this.actionType = actionType;
            if (actionType == ACTION_TYPE_REGISTER) {
                setTitle("注册");
                binding.tvToggleUi.setText(R.string.flag_login);
                binding.rlPhoneCode.setVisibility(View.VISIBLE);
                binding.btnLoginRegister.setText(R.string.btn_register);
            } else {
                setTitle("登录");
                binding.tvToggleUi.setText(R.string.flag_register);
                binding.rlPhoneCode.setVisibility(View.GONE);
                binding.btnLoginRegister.setText(R.string.btn_login);
            }
        }
    
        @Override
        public void showLoading() {
            showLoadingDialog();
        }
    
        @Override
        public void hideLoading() {
            hideLoadingDialog();
        }
    
        @Override
        public void setUsernameError(String errorMsg) {
            binding.etUsername.requestFocus();
            binding.tilUsername.setError(errorMsg);
    
        }
    
        @Override
        public void setCodeError(String errorMsg) {
            binding.etCode.requestFocus();
            binding.tilPhoneCode.setError(errorMsg);
        }
    
        @Override
        public void setPasswordError(String errorMsg) {
            binding.etPassword.requestFocus();
            binding.tilPassword.setError(errorMsg);
        }
    
        @Override
        public void loginSuccess() {
            finish();
        }
    
    
        @Override
        public void verifySmsCodeSuccess(Object data) {
            loginPresenter.sendVerificationCode(binding.etCode.getText().toString());
        }
    
        @Override
        public void sendSmsCodeSuccess(Object data) {
            binding.tvGetCode.setClickable(false);
            countDownTimer.start();
        }
    
        @Override
        public void getSupportCountrySuccess(Object data) {
            //返回支持发送验证码的国家列表
            Log.d("SMS", data.toString());
            ArrayList<HashMap<String, String>> cs = (ArrayList) data;
            for (HashMap<String, String> map : cs) {
                Log.d("SMS", map.toString());
                for (Map.Entry<String, String> entry : map.entrySet()) {
                    System.out.println(entry.getKey() + "-" + entry.getValue());
                }
            }
        }
    
        @Override
        public void onTimerTick(long millisUntilFinished) {
            binding.tvGetCode.setText(String.format(getString(R.string.count_down_timer)
                    , millisUntilFinished / 1000L));
        }
    
        @Override
        public void onTimerFinish() {
            binding.tvGetCode.setClickable(true);
            binding.tvGetCode.setText(R.string.get_varification_code);
        }
    
    }
    
    
    

    Presenter

    public interface BasePresenter {
        void destroy();
    }
    
    public interface ILoginPresenter extends BasePresenter{
    
        void switchUiByActionType(int actionType);
    
        void onUsernameError(String errorMsg);
    
        void onPasswordError(String errorMsg);
    
        void onCodeError(String errorMsg);
    
        void submitVerificationCode(String phone, String code, String password);
    
        void sendVerificationCode(String phone);
    
        void login(String username, String password);
    
        void register(String username, String password, String code);
    
        void loginSuccess();
    
        void registerSuccess();
    
        void loginFailed(String errorMsg);
    
        void registerFailed(String errorMsg);
    
        void verifySmsCodeSuccess(Object data);
        void sendSmsCodeSuccess(Object data);
        void getSupportCountrySuccess(Object data);
    
        void smsFailed(int event, Object data);
    
        void initSMSSDK(Context context);
    }
    
    public class LoginPresenterImpl implements ILoginPresenter,
            BaseEngine.Callback, SMSCallback {
    
        private UserEngine userEngine;//相当于Model
    
        private ILoginView loginView;
    
        private SMSEventHandler smsEventHandler;
    
        public LoginPresenterImpl(ILoginView loginView) {
            this.loginView = loginView;
            userEngine = UserEngine.getInstance(this, UserEngine.ID_LOGIN, UserEngine.ID_REGISTER);
        }
    
        @Override
        public void initSMSSDK(Context context) {
            SMSSDK.initSDK(context, "15da6511b04f5", "ec275402ed1402d13d37132c55ae90c0");
            smsEventHandler = new SMSEventHandler(this);
            //注册短信回调
            SMSSDK.registerEventHandler(smsEventHandler);
        }
    
        public void switchUiByActionType(int actionType) {
            if (loginView != null) {
                loginView.switchUiByActionType(actionType);
            }
        }
    
        @Override
        public void onUsernameError(String errorMsg) {
            if (loginView != null) {
                loginView.setUsernameError(errorMsg);
            }
        }
    
        @Override
        public void onCodeError(String errorMsg) {
            if (loginView != null) {
                loginView.setCodeError(errorMsg);
            }
        }
    
        @Override
        public void onPasswordError(String errorMsg) {
            if (loginView != null) {
                loginView.setPasswordError(errorMsg);
            }
        }
    
        @Override
        public void sendVerificationCode(String phone) {
            String error;
            if ((error = checkPhone(phone)) != null) {
                onUsernameError(error);
                return;
            }
    
            if (loginView != null) {
                loginView.showLoading();
            }
            SMSSDK.getVerificationCode("86", phone.trim());
        }
    
        @Override
        public void submitVerificationCode(String phone, String code, String password) {
            String error;
            if ((error = checkPhone(phone)) != null) {
                onUsernameError(error);
                return;
            } else if ((error = checkCode(code)) != null) {
                onCodeError(error);
                return;
            } else if ((error = checkPassword(password)) != null) {
                onPasswordError(error);
                return;
            }
    
            SMSSDK.submitVerificationCode("86", phone.trim(), code.trim());
        }
    
        @Override
        public void register(String phone, String password, String code) {
            String error;
            if ((error = checkPhone(phone)) != null) {
                onUsernameError(error);
                return;
            } else if ((error = checkCode(code)) != null) {
                onCodeError(error);
                return;
            } else if ((error = checkPassword(password)) != null) {
                onPasswordError(error);
                return;
            }
            if (loginView != null) {
                loginView.showLoading();
            }
            if (userEngine != null) {
                userEngine.register(phone, password);
            }
        }
    
    
        @Override
        public void login(String phone, String password) {
    
            String error;
            if ((error = checkPhone(phone)) != null) {
                onUsernameError(error);
                return;
            }
            if ((error = checkPassword(password)) != null) {
                onPasswordError(error);
                return;
            }
    
            if (loginView != null) {
                loginView.showLoading();
            }
            if (userEngine != null) {
                userEngine.login(phone, password);
            }
        }
    
    
        @Override
        public void loginSuccess() {
            if (loginView != null) {
                loginView.hideLoading();
                loginView.showToast("登录成功");
                loginView.loginSuccess();
            }
        }
    
        @Override
        public void registerSuccess() {
            if (loginView != null) {
                loginView.hideLoading();
                loginView.showToast("登录成功");
                loginView.loginSuccess();
            }
        }
    
        public void loginFailed(String errorMsg) {
            if (loginView != null) {
                loginView.hideLoading();
                loginView.showToast(errorMsg);
            }
        }
    
    
        public void registerFailed(String errorMsg) {
            if (loginView != null) {
                loginView.hideLoading();
                loginView.showToast(errorMsg);
            }
        }
    
        @Override
        public void onSuccess(int id, Object data) {
            switch (id) {
                case UserEngine.ID_LOGIN:
                    loginSuccess();
                    break;
    
                case UserEngine.ID_REGISTER:
                    registerSuccess();
                    break;
            }
        }
    
        @Override
        public void onError(int id, int code, String msg) {
            switch (id) {
                case UserEngine.ID_LOGIN:
                    loginFailed(msg);
                    break;
    
                case UserEngine.ID_REGISTER:
                    registerFailed(msg);
                    break;
            }
        }
    
    
        /**
         * 验证码校验成功
         */
        @Override
        public void verifySmsCodeSuccess(Object data) {
            if (loginView != null) {
                loginView.hideLoading();
                loginView.verifySmsCodeSuccess(data);
            }
        }
    
        /**
         * 获取验证码成功
         */
        @Override
        public void sendSmsCodeSuccess(Object data) {
            if (loginView != null) {
                loginView.hideLoading();
                loginView.showToast("验证码发送成功,注意查收");
                loginView.sendSmsCodeSuccess(data);
            }
        }
    
        /**
         * 返回支持发送验证码的国家列表
         */
        @Override
        public void getSupportCountrySuccess(Object data) {
            if (loginView != null) {
                loginView.hideLoading();
                loginView.getSupportCountrySuccess(data);
            }
        }
    
        public void smsFailed(int event, Object data) {
            if (loginView != null) {
                loginView.hideLoading();
                String error = ((Throwable) data).getMessage();
                try {
                    SmsError smsError = new Gson().fromJson(error, SmsError.class);
                    error = smsError.getDetail();
                } catch (Exception e) {
                    e.printStackTrace();
                }
                loginView.showToast(error);
            }
        }
    
    
        @Override
        public void smsSuccess(int event, Object data) {
            //回调完成
            if (event == SMSSDK.EVENT_SUBMIT_VERIFICATION_CODE) {
                verifySmsCodeSuccess(data);
            } else if (event == SMSSDK.EVENT_GET_VERIFICATION_CODE) {
                sendSmsCodeSuccess(data);
            } else if (event == SMSSDK.EVENT_GET_SUPPORTED_COUNTRIES) {
                getSupportCountrySuccess(data);
            }
        }
    
        @Override
        public void smsError(int event, Object data) {
            if (data != null && (data instanceof Throwable)) {
                smsFailed(event, data);
            }
        }
    
    
        @Override
        public void destroy() {
            loginView = null;
            if (smsEventHandler != null) {
                SMSSDK.unregisterEventHandler(smsEventHandler);
            }
        }
    
        private String checkCode(String code) {
            if (TextUtils.isEmpty(code)) {
                return ("请输入验证码");
            }
            return null;
        }
    
        private String checkPhone(String phone) {
            if (TextUtils.isEmpty(phone)) {
                return ("请输入手机号");
            }
    
            if (!StringUtils.isMobilePhone(phone.trim())) {
                return ("手机号格式有误");
            }
            return null;
        }
    
        private String checkPassword(String password) {
            if (TextUtils.isEmpty(password.trim())) {
                return "密码不能为空";
            } else if (password.length() < 6) {
                return "密码必须大于6位";
            }
            return null;
        }
    
    
        private static class SMSEventHandler extends EventHandler {
            SMSCallback callback;
    
            public SMSEventHandler(SMSCallback callback) {
                this.callback = callback;
            }
    
            @Override
            public void afterEvent(final int event, int result, final Object data) {
                if (result == SMSSDK.RESULT_COMPLETE) {
                    new Handler(Looper.getMainLooper()).post(new Runnable() {
                        @Override
                        public void run() {
                            callback.smsSuccess(event, data);
                        }
                    });
                } else {
                    new Handler(Looper.getMainLooper()).post(new Runnable() {
                        @Override
                        public void run() {
                            callback.smsError(event, data);
                        }
                    });
                    ((Throwable) data).printStackTrace();
                }
            }
        }
    }
    
    

    上面的代码有详细的注释,方法名定义的也比较形象,一看就知道干什么的。

    如果明白了MVP架构的流程图,上面的代码虽然有点长,但是非常很好理解:

    Activity 实现了ILoginView接口,所以Activity就是View 层;

    Model层呢,在这里就是请求网络。

    我们并没有让Activity和Model直接交互,而是通过Presenter层来作为沟通桥梁的。

    所以Activity里组合了Presenter:

    public class UserLoginActivity extends BaseActivity<UserLoginBinding> implements ILoginView
            , MyCountDownTimer.CountDownCallback {
    
    
        private static final int ACTION_TYPE_LOGIN = 1;
        private static final int ACTION_TYPE_REGISTER = 2;
    
        private ILoginPresenter loginPresenter; //Presenter
    
        //省略其他代码...
    
    

    在Presenter中组合了ILoginView

    public class LoginPresenterImpl implements ILoginPresenter,
            BaseEngine.Callback, SMSCallback {
    
        private UserEngine userEngine;//相当于Model
    
        private ILoginView loginView;
        
        //省略其他代码...
    
    }
    

    这样Presenter和View之间包含了彼此,就可以彼此通信了。这样就把Activity(View) 和 Model之间实现了低耦合。

    使用MVP架构需要注意的地方

    1)释放资源(在用户离开界面的时候,记得释放Presenter的资源)

    @Override
    public void destroy() {
    
        loginView = null;
        
        userEngine.destroy();
        
        if (smsEventHandler != null) {
            SMSSDK.unregisterEventHandler(smsEventHandler);
        }
    }
    

    2)方法命名/有些方法应该放在IView接口里还是接口的实现者Activity里的问题

    我也看了其他一些MVP的例子,很多也是基于登录的例子,比如在登录成功后,跳到主界面,在IView接口定了 goMain()goMainActivity() 我觉得这样是不妥的。

    假设用户登录成功后的逻辑变了,不跳到主界面了而是其他的逻辑了,那在ILoginView顶层接口里定义goMain()goMainActivity()就不合适了,因为用不到了,总不能在goMain方法里不写跳到主界面而是写其他代码的逻辑吧,这样方法名和里面的代码就不匹配了。如果更改方法名,那所以实现该接口的类都需要改方法名了,耦合又变大了。

    我的建议是,既然是登录成功的逻辑,那就在ILoginView接口里定义loginSuccess()方法,不管以后登录成功做什么逻辑都可以在loginSuccess()里实现。而不应该直接把业务逻辑和方法名绑定死了,并且还把绑定死的方法名放在ILoginView顶层接口里,因为业务逻辑是很容易发生变化的。所以应该定义一个通用的方法名loginSuccess()

    有人说goMain()goMainActivity(),你看多清晰,一看我就知道是干什么的。但是loginSuccess()不知道做什么逻辑,还得详细看loginSuccess()里的代码。 我觉得考虑的也有一定的道理,但是这不能作为把业务逻辑和方法名绑定死了放到顶层接口里的理由。
    如果你出于这种考虑也很好解决的,直接在实现ILoginView的Activity里定义 goMain()goMainActivity() 方法,然后在loginSuccess()里调用goMain()goMainActivity()

    3)有些代码可以放在Activity又可以放到Presenter,该怎么抉择?

    我们在使用验证码注册的时候,当用户点击获取验证码的时候,开发者可能就下意识的就在在Activity中调用SMSSDK的API来获取验证码,然后在Activity中处理获取成功和失败的逻辑。

    乍一看功能实现没问题,我们可以在Activity中调用SMSSDK的API来获取验证码,也可以在Presenter里调用SMSSDK的API来获取验证码。在使用MVP架构的时候我们时常遇到这样的抉择,在哪里写都可以实现功能,我们该怎么抉择呢?

    其实这个时候SMSSDK(只不过SMSSDK是第三方提供的API而已)就是充当着Model的角色,因为SMSSDK就是去请求网络,然后发送验证码的,如果我们直接在Activity(View)中调用了,那么Model和View又耦合了,所以应该放在Presenter中来做。假设有一天发送验证码的SDK我们替换成了其他第三方的SDK了,在View层我们不需要修改一行代码,只需要修改Presenter就可以了。


    通过上面一个登录的例子,有些读者看到接口中这么多方法,瞬间感觉这个MVP不仅没有帮我们解决问题,反而是问题的制造者。不是这样的!假设我们使用熟悉的MVC开发的时候,我们可能是这样的实现的:

    //由于篇幅的原因,省略了大量的代码,保留主要逻辑代码
    public class UserLoginActivity extends BaseActivity<UserLoginBinding> {
    
        private UserEngine userEngine;
    
    	//请求登录接口
        private void requestLogin() {
            showLoadingDialog();
            userEngine.login(xxx);
        }
    
    	//请求注册接口
        private void requestRegister() {
            showLoadingDialog();
            userEngine.register(xxx);
        }
    
        @Override
        public void onClick(View v) {
            switch (v.getId()) {
                case R.id.tv_user_login:
                    requestLogin();
                    break;
                case R.id.tv_register:
                    requestRegister();
                    break;
            }
        }
    
        @Override
        public void onSuccess(int id, Object content) {
            super.onSuccess(id, content);
            switch (id) {
                case userEngine.ID_LOGIN:
                    //处理登录成功后的逻辑
                    break;
                case userEngine.ID_REGISTER:
                    //处理注册成功后的逻辑
                    break;
            }
        }
    
        @Override
        public void onError(int id, String msg) {
            super.onError(id, msg);
        }
    
    }
    

    上面的代码直接Activity中操作Model,耦合变得比较大了。而且随着业务的增多Activity的代码会越来越臃肿。

    其实MVP也就是在上面的代码之上做出一些改良而已,上面我们在View中直接操作Model,现在呢?MVP只不过是View和Model不直接通信了,通过Presenter来通信,Activity(View)操作Presenter,Presenter来操作Model,这样View和Model实现了间接的通信了。

    聪明的读者可能又有问题了,分层(View、Presenter)可以啊,但是也不至于每层都设计一个接口吧?那么以接口的形式给我们带来什么好处了呢?

    1)代码更加清晰

    这样在一定程度上避免了开发者在一个方法里有太多的代码,因MVP强制要求把各个业务都封装在方法里然后调用。

    2)做好业务的顶层设计

    在开发的时候,当产品原型出来通过了评审后,因为业务都出来了嘛,开发这块就可以把View、Presenter接口的各个函数名全部设计好,做好顶层设计,这也倒逼开发者对这个需求这块一定要有着全面的理解。如果对业务不了解是无法设计出接口的。到时候往方法里填代码就可以了。

    3)解耦

    我想大家应该注意到了,在View一层我们使用Presenter的时候都是通过IPresenter接口来定义的,而不是该接口的实现着。这样做方便后面替换,这也是面向接口编程的好处。到时候业务逻辑变了,我们只要重新实现IPresenter接口,然后在View中替换下IPresenter的实现者即可,而View层不需要修改代码。

    MVP模式实现文章详情

    如果对上面的注册的例子理解了,实现这个功能就非常简单了。由于篇幅的原因,具体的代码细节就不帖出来了。把代码的接口设计出来。

    该界面主要有加载文章、评论列表、评论、分享等功能.

    public interface IArticleDetailView extends BaseView{
        //加载文章失败
        void onLoadArticleFailed();
        //加载文章成功
        void onLoadArticleSuccess(Article article);
        //加载评论列表
        void onLoadCommentSuccess(Object data);
        //加载评论列表失败
        void onLoadCommentFailed(String msg);
        //添加评论成功
        void addCommentSuccess(Comment comment);
        //添加评论失败
        void addCommentFailed(String errorMsg);
        //分享
        void shareArticle();
    }
    
    //在Activity中实现IArticleDetailView接口细节我不贴出来了,根据要求实现即可。
    
    
    //下面是Presenter接口
    
    public interface IArticleDetailPresenter extends BasePresenter{
        //加载文章
        void loadArticle(Long id);
        //文章加载成功
        void loadArticleSuccess(Article article);
        //文章加载失败
        void loadArticleFailed(String error);
        //加载文章评论列表
        void loadComments(int articleId);
        //加载文章评论列表成功
        void loadCommentSuccess(Object data);
        //加载文章评论列表失败
        void loadCommentFailed(String msg);
        //添加评论
        void addComment(Comment comment);
        //添加评论成功
        void addCommentSuccess(Comment comment);
        //添加评论失败
        void addCommentFailed(String errorMsg);
    }
    
    //至于Presenter调用Model的细节也不贴出来了。Model写好了直接调用调用就可以了。
    
    

    是不是很简单,只要把顶层的接口设计出来,接下来就是在方法里填代码就可以了。

    Google android architecture 例子的参考

    上面的View和Presenter接口都是新开新建的, Google android-architecture-todo-mvp-dagger sample 是把View和Presenter放在一个Contract类中, 如下所示 :

    AddEditTaskContract.java 包含了View和Presenter. 这样组装也是不错的选择. 可读性更好, 也非常容易找.

    /**
     * This specifies the contract between the view and the presenter.
     */
    public interface AddEditTaskContract {
    
        interface View extends BaseView<Presenter> {
    
            void showEmptyTaskError();
    
            void showTasksList();
    
            void setTitle(String title);
    
            void setDescription(String description);
    
            boolean isActive();
        }
    
        interface Presenter extends BasePresenter {
    
            void saveTask(String title, String description);
    
            void populateTask();
        }
    }
    

    如果你觉得本文帮助到你,给我个关注和赞呗!

    我编写了一份 超详细的 Android 程序员所需要的技术栈思维导图

    如果有需要可以移步到我的 GitHub -> AndroidAll,里面包含了最全的目录和对应知识点链接,帮你扫除 Android 知识点盲区。

    由于篇幅原因只展示了 Android 部分思维导图:

    超详细的Android技术栈

    展开全文
  • Android架构组件

    千次阅读 2017-08-15 10:30:57
    这篇架构指南面向有一定Android开发基础并想了解高质量、高稳定性App最佳实践及推荐架构的开发者。 注意:这篇指南假设读者熟悉Android Framework,如果你是Android开发新手,建议先去学习入门系列课程,这些课程也...
  • Android架构须知

    千次阅读 2015-12-30 15:55:06
    如:AsyncTask3.0之后和之前的区别、Android 5.0的新的API、Android 6.0 不能用HttpClient 、AS2.0的新特性 等等。2.掌握热门技术并了解其原理。如:RxJava(响应式框架)、Retrofit(请求框架可以配合RxJava)、MVP...
  • Android架构组件-App架构指南

    万次阅读 多人点赞 2017-11-08 00:55:21
    与传统的桌面应用程序不同,Android应用程序的结构要复杂得多,在大多数情况下,它们只在桌面快捷启动方式中有一个入口,并且作为单个进程运行。一个典型的Android应用程序是由多个 app组件(Android四大组件) 构成的...
  • Android架构详解

    千次阅读 2012-08-16 21:36:13
    Android系统架构由5部分组成,分别是:Linux Kernel、Android Runtime、Libraries、Application ... Android架构  1、Linux Kernel  Android基于Linux 2.6提供核心系统服务,例如:安全、内存管理、进程管
  • Android开发——微信Android架构历史

    千次阅读 2017-08-13 20:31:54
    图1-架构演进到了微信架构的v2.x时代,随着业务的快速发展,消息通知不及时和Android 2.3版本之前webview内存泄露问题开始突显。由于代码、内存、apk大小都在增长,对系统资源的占用越来越多,导致微信进程容易被...
  • Android架构组件-WorkManager

    万次阅读 2018-05-21 20:41:52
    使用WorkManager安排任务 WorkManager API可以轻松指定可延迟的异步任务以及何时运行,这些API可让您创建任务并将其交给WorkManager,以便立即或在适当的时间运行。例如,应用程序可能需要不时从网络下载新资源。...
  • Android架构和特征

    千次阅读 2010-07-06 09:07:00
    架构从SDK文档中,偷来一幅Android平台的架构图,如上。在整个架构最底层红彤彤的部分,是Linux Kernel在移动平台的一个移植,它隐藏了硬件、网络等相关的细节,为上层提供了一个相对纯洁的统一接口。除非要做的是...
  • Android架构组件之ViewModel

    千次阅读 2017-11-27 15:17:09
    Android架构组件之ViewModelViewModel概念及用途ViewModel用来存储和管理UI相关的数据,可于将一个Activity或Fragment组件相关的数据逻辑抽象出来,并能适配组件的生命周期,如当屏幕旋转Activity重建后,ViewModel...
  • Android 架构师成长之路

    千次阅读 多人点赞 2017-09-11 14:56:53
    前言 ...其中,稳坐榜首的仍然是Java编程语言,...从普遍的企业的角度来看,存在的问题是:后台被认为是技术核心,客户端却被认为技术含量不高,甚至小企业会让后台人员顺便开发简单的客户端,或者让后台的架构师管理...
  • Android架构组件-Lifecycle

    千次阅读 2018-07-30 22:09:07
    生命周期 LifecycleOwner 实现自定义LifecycleOwner 生命周期感知组件的最佳实践 生命周期感知组件的用例 处理停止事件 ...生命周期感知组件执行操作以响应另一个组件(例如活动和片段)的生命周期状态的更改。...
  • Android架构指南

    千次阅读 2019-02-15 15:49:06
    1. 基于Google官方推荐的MVVM架构 采用ViewModel+LiveData,建立数据驱动模型,这种模型对Android组件有生命周期感知的能力。 参考连接: https://developer.android.com/jetpack/docs/getting-started 2. 采用路由...
  • Android架构介绍

    千次阅读 2018-06-27 19:19:28
    Android架构介绍 Google提供的4层架构图很经典,但为了更进一步透视Android系统架构,本文更多的是以进程的视角,以分层的架构来诠释Android系统的全貌,阐述Android内部的环环相扣的内在联系。 Loader层 Boot ...
  • Android架构设计

    2015-04-11 14:39:33
    阶段一 Android架构师值oop及EIT思想 阶段二 Android架构师之框架原理及架构 阶段三 Android架构师之设计研究 阶段四 Android架构师之A段架构师
  • 一种更清晰的Android架构

    千次阅读 多人点赞 2015-03-23 10:14:37
    过去几个月以来,通过在Tuenti网站上与@pedro_g_s和@flipper83(安卓开发两位大牛)进行友好讨论之后,我决定写这篇关于架构Android应用的文章。 我写这篇文章的目的是想把我在过去几个月体悟到的小方法以及在调查...
  • [Android] Android架构

    千次阅读 2010-08-07 21:50:00
    Android架构
  • Android架构中添加AutoDispose解决RxJava内存泄漏

    万次阅读 多人点赞 2018-03-02 00:59:45
    如何通过使用 RxLifecycle 解决Android开发中RxJava的可能会导致的内存泄漏问题; RxLifecycle 内部的实现原理; 在文章的最后,我提到了 AutoDispose 这个库,这个库同样可以解决Android生命周期组件导致的RxJava...

空空如也

1 2 3 4 5 ... 20
收藏数 29,328
精华内容 11,731
关键字:

android架构