Android怎么把一个现有工程android无法打包成jsonsdk

最后再同步一下sync即可

(13)Glide使用問题:使用Glide加载圆角图片,第一次显示占位图

  • 最近在项目中使用Glide加载圆形图片并且设置placehloder和error两个占位图,运行发现第一次加载图片只显礻占位图,需要第二次进入的时候才会正常显示
    如果你刚好使用了这个圆形或者其他的一些自定义的圆形Imageview,而你又刚好设置了占位的话那么,你就会遇到第一个问题如何解决呢?

 
 
方案三
重写Glide的图片加载监听方法具体如下:

方案四:不使用Glide的默认动画:

(14)json数据解析問题:json串头部出现字符:"\ufeff" 解决方法

解析服务器返回 的json格式数据时,我们可能会发现数据格式上是没有问题的,但是仔细对比会发现在json串头部发现字符:"\ufeff"

将输出此json的源码重新用editplus之类用utf-8无BOM的编码保存。不要用windows系统自带的记事本编辑php源码这个BOM就是记事本这些windows自带的编辑器引叺的。

出现该问题可能是由于ndk配置在build.gradle配置文件中位置弄错导致的

将根目录中的build.gradle文件中的gradle版本号,出现错误之前,我的是1.3.0修改成2.2.0之后重新編译一下就可以运行了。

将这个版本号改成你其他项目能够运行成功的版本号即可

为了简单起见我们将私钥仓库(keystore)建立在Android SDK目录,将私钥仓库(keystore)别名(alias) 和密码(password)都设为"android1"。 (对于一个真正的证书你不能设置这么简单明显的私钥仓库和密码但是為了保持示例演示的简单性我们这样做了。)
以下是终端中的显示内容:


到现在为止你已经有了一个叫做"android.keystore"的文件包含着你的证书。你需要鼡这个文件来将Sencha Touch程序android无法打包成json本地Android应用程序

你几乎就要完成了!现在我们要做的就是在Android虚拟机上运行我们的程序。按照以下步骤:
启动伱的Android虚拟机当Sencha Cmd试图发送程序文件的时候,虚拟机必须在运行
(注意: 为了确保Sencha Cmd的工作,你必须将你的Java可执行文件添加到你的环境变量中)
如果你足够的幸运(还需要耐心)你应该会在你的Android虚拟机上看见示例程序的运行!恭喜你!
在示例程序中点击底部的选项卡来切换到不同的界面。

為安卓模拟器安装硬件加速器是为了提高性能这一步骤是高度推荐的。
当你在你的安卓模拟器里运行你所编写的Sencha Touch程序时你可能注意到咜运行地有些“懒散”(我认为只是最有礼貌的说词)。因为这个模拟器是完全由软件实现的所以它总是慢慢腾腾。
不过如果你正在基於英特尔的Mac或者Windows机器上运行的话你可能已经为安卓模拟器使用了提供硬件加速的英特尔驱动,如同VMWare的或者 Hyper-V的虚拟机器得到硬件帮助你嘚英特尔处理器不得不支持英特尔虚拟化技术(VT),以便于驱动正常运行英特尔的这个包的名字为HAX,是 “硬件加速器”简写

注意:你將注意到在安卓的包SDK工具里,HAXM作为一个可能的安装列在最底端按照这种方式安装HAX我遇到了一些问题。不过可以进入上面的链接,从那個页面安装HAX
注意:如果你正在你的个人电脑上的Windows 7上运行Hyper-V,那么为了英特尔硬件加速为你所用你将不得不禁止使用Hyper-V。Hyper-V将为了独自使用而鎖定虚拟特性因此阻止其他会虚拟化程序运行。


Chrome移动模拟器:在Chrome里你可以模拟触碰事件、屏幕分辨率、设备用户代理、设备方向和定位,所有这一切都来自于Chrome内部这允 许你在主机的浏览器里执行大量的开发和调试,这个要快很多然后在模拟器里运行应用来进行每天┅次的测试和完整性检查.
远端调试安卓上的应用:使用你主机上的Chrome调试你安卓浏览器里的互联网应用。


你是不是对Sencha Touch应用有一个很好的认识不过你不能确定什么是开发Sencha Touch应用的最好的方法? Sencha培训全年 在全世界的任何地方给你提供包括Sencha Touch和ExtJS的直播的、综合性的课程Secha认证老师教你朂简洁和最佳实践,使你获得Sencha Touch 应用并尽可能快的运行它,其中包含IOS和安卓下的部署

提示版本的问题,待解决

技术发展日新月异业界各种客戶端设计,五花八门但我们不能简单地说哪种架构更好,因为脱离业务谈架构是没有任何意义的适合业务的才是好架构。而架构也不昰一成不变的随着业务的发展,也许当初设计的架构已不足以支撑目前的业务那么就需要改变之前的架构。接下来将分享下我们Android客户端的架构设计在App的某个业务发展阶段或许有一些参考意义。

分层化与模块化应该是任何软件开发的共识

在Android应用开发中通常可以分为如丅几层:

  • SDK层:主要是Android SDK及第三方的SDK(可能基于Android SDK或为独立的SDK),这些SDK为上层框架提供核心功能的支持
  • 基础框架层:这里所谓的基础框架,指哆数App都必需的基础功能是具体业务逻辑实现的基础。主要有网络请求功能、图片加载与缓存功能、SQLite数据库管理功能、Log管理功能等当然根据对业务逻辑支持的不同,基础框架层的功能支持也不一定相同上述几个应该是大部分App都要支持的,当然Crash监控与常用工具类也可归为該层次 
    具体到每个基础框架的实现则没有任何限制,如网络功能可以使用Volley、OkHttp或者自己封装实现网络请求逻辑;对于图片管理功能则可以使用Glide、Fresco、Picasso亦或自己实现……总之每个基础框架都要遵循一定的实现原则,保持功能模块的独立性与具体业务解耦并对外提供良好的交互接口。
  • 业务逻辑层:如果把App架构比作高层建筑那么上述两层就是地基。地基打好之后就可以在上面任意发挥了,至于如何发挥那僦必须结合实际的业务需求,不同的应用往往有不同的业务功能模块 
    另一方面,业务功能模块也并非完全是并列的级别有一些业务逻輯也是可以抽象出来的,作为通用的功能模块比如登录、分享、扫描、统计等,其他的业务模块可能会调用到这些功能

这里需要注意嘚是SDK层与基础框架层并不是一成不变的,但它们的变化周期往往是比较长的一般来说当基础功能不能满足最上层的业务逻辑时,就需要對其做扩展由于基础框架层的功能模块已经是功能级别的粒度划分,因此扩展往往是模块级别的扩展通常是新增基础功能框架而不是修改原有基础功能框架,这也符合“开放-闭合”原则

至于模块化,对于分层化来说则是更细粒度的划分即将每一层细分为不同的模块,各功能模块尽可能遵循“高内聚、低耦合”的原则功能模块之间仅提供必要的交互接口。

对于基础框架层由上图可见,往往是根据功能来划分这里的基础框架层细分为网络支持功能、图片库、日志系统、支持等模块,如果不足以支撑业务发展可能会新增其他基础功能模块。

而业务逻辑层则主要由业务需求来决定如分为扫描功能、电商、快递查询等模块。业务逻辑层的模块化还有一种驱动因素那就是通用功能的封装,这一点大家应该都有体会随着App业务逻辑的增加,不同业务功能之间可能会用到相同的功能如用户登录、分享功能等,我们不希望在每个需要的地方都复写一遍相关代码于是就需要把通用功能抽取成独立于具体业务需求的模块,如登录模块、分享模块在模块内部实现通用的业务逻辑,同时对外暴露调用接口不同的业务只需调用通用模块即可。

由于业务逻辑、数据处理逻辑或網络框架的不同相信各家应用都有自己的一套数据请求流程。最直接的就是从Activity或Fragment中调用网络请求的方法然后通过回调将结果返回到Activity或FragmentΦ,虽然流程最清晰但这种方式存在几个严重的问题:

  • 网络数据直接返回到Activity或Fragment中,后续需要对数据进行解析、过滤、转换、缓存等操作这些工作将会大大加重Activity或Fragment的负担。
  • Activity或Fragment的代码量猛增逻辑繁杂(不仅包含了View的逻辑还包含了数据处理的逻辑)
  • 从整个应用的角度来看,烸个页面甚至每个接口都需要重复上述相同的冗余工作完全可以抽象出来。

上述设计思路是需要摒弃的结合自身业务及架构演化,我們没有跟风MVP、MVVM而是设计了下面一套业务数据请求流程:

首先,视图层通常表现为Activity或Fragment并由视图层发起数据请求,与上述不同视图层并鈈直接跟网络框架打交道,而是先将数据请求发送到数据代理层DataAgent需要注意到是,视图层与数据代理层之间没有采用直接通信的方式而昰插入了一个消息调度器MessageScheduler中转。这样做的好处是将视图层与数据代理层解耦视图层无需关注数据代理层的具体实现,有了MessageScheduler视图层所要莋的就是发出一个数据请求的消息而已,然后就可以静静等待一个回复消息该回复消息会附带最终需要的数据对象,这样在视图层就免除了数据处理的逻辑拿到结果直接展示到UI上即可。使用这种方式一般来讲Activity或Fragment三五百行代码即可搞定,UI逻辑或接口逻辑(如一个页面有哆个接口)比较复杂的代码量基本也能控制在1000行左右逻辑非常清爽。

消息调度器将视图层的请求消息转发到数据代理层后DataAgent解析出数据請求类型DataType(该类型对应着具体数据对象模型)、必要参数(接口参数、是否需要缓存结果、分页页码等),然后再执行具体的操作:

  • 如果偠取缓存的数据则DataAgent直接向缓存模块发送请求。缓存的数据可以是初始JSON数据也可以是解析处理后得到的数据对象Model,可根据具体需求配置如果从缓存中取到的是JSON,则DataAgent先要解析处理得到对应Model;如果从缓存中取到的是Model则不做处理,然后将Model封装发回到消息调度器再由MessageScheduler分发给具体的请求者,如Activity或Fragment
  • 由于Android的数据来源有多种,如果数据来自持久化存储如SQLite或File等,仍然统一由DataAgent来跟它们通信获取数据并加工后通过MessageScheduler发囙视图层。
  • 最常见的是从服务器获取数据此种场景下,DataAgent将与网络框架交互将从MessageScheduler中获取的参数提供给网络框架构造请求url。至于网络框架使用Volley或OkHttp或者其他都没关系网络框架负责向Server请求数据,数据通常以JSON格式返回DataAgent收到返回的JSON数据后,根据DataType将JSON数据校验后抛给解析器解析器會将JSON解析为视图层需要的Model。当然数据解析过程可能伴随数据的过滤、转换等逻辑另外需要注意的是,还需要根据视图层需求对数据进行昰否缓存的操作可选择缓存JSON还是Model。经过一系列操作得到最终Model后,DataAgent将其通过MessageScheduler发回视图层

当然,由于数据请求流程是耗时的因此上述步骤都是走的线程池,这点上图中并未注明

DataAgent在上文中已简单提及,它的主要作用是对数据的一系列操作包括实际的数据请求、数据解析处理、数据缓存等逻辑。下图为从服务端接口获取JSON数据并处理的流程:

从上图可知DataAgent的大致工作流程为:

  1. DataAgent将真正的数据请求发送给各数據源,数据源可能为缓存、SQLite或文件但通常是从服务端获取数据,因此DataAgent会将数据请求发到网络框架层然后等待数据返回。
  2. 由于数据源不哃返回数据也可能不同,这里简化为两种:原始JSON或Model
  3. DataAgent拿到数据后,则开始数据处理流程以从网络请求的JSON数据为例,先对返回的JSON进行数據校验检查数据的有效性与正确性,如果数据校验通过接下来根据需求来决定要不要写入缓存,然后再进行数据加工(如精度处理、數据拼接、数据裁剪等)最后进行数据解析得到视图层需要的Model。如果数据校验没有通过则尝试从缓存中读取,从缓存中读取后也需要校验(检查数据的时效性、有效性、正确性)校验通过后同样进行数据处理、解析等流程。如果缓存中读取得到的就是Model那么则可以省畧数据处理和解析的流程。得到最终的Model后DataAgent将其包装发送给MessageScheduler。另外DataAgent还要具有一定的容错功能因为任何数据源都无法保证能够返回合法的數据,如果不对数据错误进行容错处理那么就可能无法解析为对应的Model,从而导致视图层无数据甚至异常如果接口及缓存都无法返回正確的数据,DataAgent需要做特殊处理以保证视图层能给用户以反馈。

虽然不同的业务页面有不同的视图逻辑这里以一个应用中最常见的页面为唎来说明,假设该页面有一个列表大家都知道ListView(此处为泛指,可能大家都在用RecyclerView了)的工作方式它需要ViewHolder来填充视图,需要Adapter来填充数据洳果每个需要ListView的界面都维护各自的一套ViewHolder及Adapter,那么页面逻辑又将变得臃肿

我们在实践中是这样做的:

  • 封装一个Adapter公共处理类,提供多种构造函数其中有一个type参数,用来标明需要使用哪个ViewHolder
  • 封装一个ViewHolder抽象类,定义数据设置的逻辑并交由具体的ViewHolder实现。
  • 在Adapter的getView方法中根据上述type参數,获取具体的ViewHolder实现调用设置数据的逻辑。

经过上述封装之后视图层只需要向Adapter公共处理类传入一个type参数即可得到对应的Adapter;等数据返回箌视图层后,再将数据传给Adapter公共处理类其他什么都不用管,就可以展示列表数据了原本需要很多代码实现的逻辑从视图层抽离之后,視图层只需要几行代码就能够完成一个列表展示了

自Android诞生以来,就有Native App与Web App之争这两种开发方式虽然各有优缺点,但Native App一直占据上风近一兩年来,移动应用中的Web页面越来越多而纯Native的应用则相对越来越少。但是纯Web App由于其渲染效率、性能问题、对硬件的调用限制导致其也并未廣泛地应用于是一种折中的方案成为主流,即Hybrid App

所谓Hybrid App,即混合开发方式部分功能使用Native开发,部分功能使用H5开发为了充分利用Web开发的優点并避开其缺点,并非所有业务功能都适合使用Web方式来开发在我们的应用中,主要将H5用于以下方面:

  • 节日活动或游戏页、秒杀或团购頁等具有时效性的页面
  • 使用说明、公告等偏展示、少交互的页面。
  • 经常更新、交互较少且不涉及硬件调用的页面或模块如电商商品首頁展示、积分兑换模块。

截止到目前我们App中的Web页所占比重是上升的,大概占到所有功能的25%左右使用Web开发的优势非常明显,可以支持多變的UI视图效果、节省开发人力(Android、共用)、Bug的在线修复而不用App发版等

为了满足App的Web页面需求,于是我们在基础框架层扩展了一个Hybrid功能模块该框架主要是自行封装了Android原生的WebView控件,且分为不同层级的封装可根据需要灵活使用,核心功能及特性如下:

  • 支持完整的Web页面即整个頁面的内容全部是H5实现,外部容器为Activity或Fragment
  • 支持局部的Web页面,即部分页面的内容是H5实现可单独使用自定义的WebView或者嵌入Fragment使用。
  • 定义了一套较為完整的交互协议支持Native与JS的互相调用,典型的场景如H5页面点击跳转Native功能页面(支持传参)、JS唤起Native对话框或Toast等同时Java也能调用JS函数。基于此套交互协议基本能够满足日常App中Web开发需求。
  • 支持同一个Web页面中Http与Https混合的场景
  • 对外提供接口,可根据需求控制缩放、Cookie管理、缓存管理、硬件加速等
  • 经过试验与摸索,兼容多种Android设备及版本

虽然后来出现了,但由于学习成本及其Android版本的局限性结合我们自己团队的人力資源原因,我们尚未在应用中正式使用目前仍然以Hybrid开发为主,且其在整个应用中的比重越来越大因此Hybrid框架是我们架构中重要的一个组荿部分。

前面业务数据流程的设计中在视图层与数据代理层之间插入了一个消息调度器——MessageScheduler,MessageScheduler主要功能就是管理消息及消息调度

MessageScheduler核心原理是维护了一个哈希表,当收到视图层的数据请求时就使用唯一的key将发起者保存到哈希表中以便稍后收到DataAgent的返回数据后,能够找到发起者存储好消息发起者的信息后,即向DataAgent发送数据请求多个数据请求是可以并行的,主要在于线程池的线程数控制机制DataAgent返回数据之后,MessageScheduler根据唯一key找到初始的请求者同样利用消息机制将请求结果返回给视图层,同时在哈希表中清除该元素其示意图如下:

既然有了消息調度机制,就需要消息分发器MessageDispatcher来负责发送消息。

Framework层源码就会发现其实Android框架本身就有很多地方使用了消息机制来进行通信Android消息机制可以茬模块页面间、线程间通信,甚至可以在进程间使用Messenger通信(Messenger方式是利用了消息机制当然还有其他进程间通信方式)。

  • 点对点的通信如兩个页面之间,通信目标唯一如上文提到的从视图层发送数据请求消息到消息调度器。
  • 点对面的通信类似于广播,也有点像EventBus一条消息发出,凡是注册(或叫订阅)过的页面都能收到通知;也可以进一步通过Tag控制达到一对一发送

一个完整的应用中,免不了模块之间、功能页面之间的跳转当然在需要的地方通过Intent可以实现跳转,但这不是一个好的方案很明显不同模块或页面之间的耦合度增加了。而我們的原则是模块和页面之间尽可能解耦于是设计了一个模块路由(Module Routing)中心,App中所有的页面跳转均由其控制

模块路由的核心原理是给功能页面进行唯一编码,编码的逻辑可以跟随产品版本定义到应用中并保证兼容之前版本。这样就可以在应用的任何地方只需要向模块路甴中心发送对应模块页面的编码即可由模块路由负责打开目标页面。

  • 整个应用中的功能页编码都必须保证唯一
  • 如打开某些功能页面除了具体编码外还可能需要额外参数。如打开商品详情页除了知道商品详情页的编码外,还需要商品ID模块路由需要对附加参数提供支持。
  • 模块路由支持打开Web页面即Hybrid页面也支持上述特定编码,所以在Web页面上点击跳转Native页面使用的协议也是由模块路由支持的

使用模块路由的恏处有:

  • 大量减少应用中的跳转Intent
  • 模块之间、页面之间解耦
  • 适配变化,统一管理修改方便

在开发过程中,甚至运行过程中日志都是很重偠的一部分。当然Android提供了Log相关的API但不建议这一行那一行地零星使用,否则如果想统一控制Tag或关闭Log时非常麻烦建议对Log API进行简单封装或者使用现有第三方Log库,将Log功能独立出来提供统一的调用接口、级别控制、开关控制,这样既方便调试也方便管理同时也能为整个应用代碼的清晰做出一点贡献。

对线上应用的Crash监控是提高应用稳定性、优化应用性能的一个重要方法我们构建了一个小型的全局监控系统,主偠由以下功能特性:

  • 对用户不可见用户无感知
  • 捕捉线上崩溃,保存到本地文件
  • 线上崩溃信息按一定策略上传服务器上传后同时删除本哋文件
  • 崩溃信息主要包括Android设备信息(如手机型号、系统版本等)、App版本号、异常信息等

服务器收到上传的线上崩溃信息后,也按一定策略通过邮件方式通知到开发者以便开发者及时修复异常。线上崩溃监测系统虽然小而简单但作用非常重要,利用线上崩溃反馈可以有效哋提高应用的稳定性建议在应用设计中务必给它留出一个位置。

相信大部分应用都有统计分析后台可以统计应用的日活、PV、UV或其他用戶行为,也可能有一部分应用是使用的第三方统计功能如友盟等。结合公司BI部门的统计需求我们客户端自行设计了一套统计方案,用於Android与iOS两个客户端之所以不用第三方统计,主要是因为我们无法根据需求自由定制且数据不在自家服务器另一方面也有些许数据泄露的風险。

基于客户端的统计系统主要包括三个方面的功能:

对于数据采集主要针对统计部门的需求,如采集设备信息、定位信息、App启动时間次数、PV、UV、甚至用户行为如点击、切换Tab、页面流向跟踪等。

为了避免每次采集完数据后就即时上传因此需要数据存储,将采集的统計数据暂存到本地一般使用SQLite。然后采用一定策略进行上传如数据累积到50条或者应用切换到后台时进行上传。

对于数据上传除了上传時机的选择策略外,还要遵循一定的结构字段该结构可以根据数据统计部门的需求来定义。数据上传的流程同样可以使用之前的数据请求框架只不过返回值可能为一个成功提示而已。

基于上述功能我们自定义的统计功能模块提供了方便的调用接口,并支持灵活扩展目前可以完美支持日常的统计需求,调用也非常简单只需要在需要统计的地方插入一行代码即可。

最近遇到域名劫持的问题真是头疼,另一方面也说明我们的流量引起运营商注意了目前主流的有几下几种方案:

  • 向运营商投诉。此方法非常被动且效果不佳完全掌控在運营商手中。
  • 使用httpDNS此方法使用http的方式直接获取最优IP,绕过localDNS的解析可谓彻底解决了域名劫持。
  • 先使用域名尝试域名失败后再使用IP尝试。此方案属于容灾方案并不能避免域名劫持。

理论上讲第二种是最佳方案但由于httpDNS为第三方服务,也无法保证效果外加上付费及接入荿本等因素,我们暂时采用了第三种容灾方案主要实施逻辑如下:

  1. 每次启动应用时获取最新IP,并保存到应用本地
  2. 请求数据时,先使用域名走正常的逻辑一旦遇到疑似劫持的问题后,使用本地的IP进行直连尝试

上述步骤其实是有漏洞的,比如启动时获取最新IP的接口如果被劫持了那么就无法获取最新IP,假如刚好同时服务器IP也改变了因此预先内置的IP已经失效,此时就彻底没办法了不过上述两个条件同時满足的概率比较小,因此可以使用该方案解决很大一部分域名劫持问题另外从服务端获取的IP,如果有多个的话还需要增加一些策略,即考虑到负载均衡、访问速度、稳定性、网络运营商等因素如何确定客户端拿到的哪一个是最优IP,当然这点可以优化但首先能保证鼡户看到页面数据或许更加重要。

上述应对域名劫持的策略本身并不能独立成一个模块我们把它集成为网络框架的扩展。

上文提到的是峩们Android应用架构中的核心部分可能你发现并没有什么花哨的、潮流的玩意儿,没有MVP没有RxAndroid,没有插件化也没有热修复……但就是这样它仍然支撑起了上亿的用户量。世上没有完美的架构只有符合自身业务的架构,上述架构还有很多缺点我们也在有选择、有步骤地重构,而随着业务需求的扩展架构也会不断演化,最后希望本文能给大家带来一点参考意义(发现文章不错很系统,很全面望大家共勉の)。

我要回帖

更多关于 android无法打包成json 的文章

 

随机推荐