﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>BlogJava-paulwong-随笔分类-ANDROID</title><link>http://www.blogjava.net/paulwong/category/51708.html</link><description /><language>zh-cn</language><lastBuildDate>Sat, 15 Jan 2022 13:31:34 GMT</lastBuildDate><pubDate>Sat, 15 Jan 2022 13:31:34 GMT</pubDate><ttl>60</ttl><item><title>Android Application Architecture 安卓APP架构[译]</title><link>http://www.blogjava.net/paulwong/archive/2015/12/18/428718.html</link><dc:creator>paulwong</dc:creator><author>paulwong</author><pubDate>Fri, 18 Dec 2015 05:07:00 GMT</pubDate><guid>http://www.blogjava.net/paulwong/archive/2015/12/18/428718.html</guid><wfw:comment>http://www.blogjava.net/paulwong/comments/428718.html</wfw:comment><comments>http://www.blogjava.net/paulwong/archive/2015/12/18/428718.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/paulwong/comments/commentRss/428718.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/paulwong/services/trackbacks/428718.html</trackback:ping><description><![CDATA[<h2>序</h2><p style="padding: 0px; margin: 8px 0px; line-height: 22.5px; letter-spacing: 0.5px; font-size: 12.5px; word-wrap: break-word; word-break: break-all; color: #333333; font-family: 'Microsoft YaHei', Verdana, sans-serif, 宋体; background-color: #ffffff;">本文介绍了文章作者从事了几年android应用的开发，经历2次架构变革，第一次集成了RxJava第二次集成了MVP，并将RxJava与MVP完美结合，实现了低耦合，代码简单，测试方便的架构。</p><p style="padding: 0px; margin: 8px 0px; line-height: 22.5px; letter-spacing: 0.5px; font-size: 12.5px; word-wrap: break-word; word-break: break-all; color: #333333; font-family: 'Microsoft YaHei', Verdana, sans-serif, 宋体; background-color: #ffffff;">其实我们在开发中也遇到过，Android入门门槛较低，如果前期对APP规划不清晰，Coder们对未来变化把握不准，技术架构经验不够强大，最终导致就是一个Activity几千行，里面写了大量的Private方法，拆成几个Fragment、封装出来几个类都是无法解决，结果就是看Activity难受的要死，纠结，看了不爽改也不是不改也不是，严重影响看的人的心情。并且怨天尤人这个是产品人员规划App不好，没有前瞻性，改来改去。。。</p><p style="padding: 0px; margin: 8px 0px; line-height: 22.5px; letter-spacing: 0.5px; font-size: 12.5px; word-wrap: break-word; word-break: break-all; color: #333333; font-family: 'Microsoft YaHei', Verdana, sans-serif, 宋体; background-color: #ffffff;">这篇文章就是使用新的结构解决该问题。</p><h1>安卓APP架构</h1><p style="padding: 0px; margin: 8px 0px; line-height: 22.5px; letter-spacing: 0.5px; font-size: 12.5px; word-wrap: break-word; word-break: break-all; color: #333333; font-family: 'Microsoft YaHei', Verdana, sans-serif, 宋体; background-color: #ffffff;">Android Application Architecture</p><blockquote style="padding: 3px 25px; margin: 20px 10px; position: relative; font-size: 10pt; line-height: 22px; border-left-width: 3px; border-left-color: #a4daf0; font-family: 'Microsoft YaHei', Verdana, sans-serif, 宋体; background-image: initial; background-color: #f4fdfd;"><p style="padding: 0px; margin: 8px 0px; line-height: 22.5px; letter-spacing: 0.5px; font-size: 12.5px; word-wrap: break-word; word-break: break-all;">Our journey from standard Activities and AsyncTasks to a modern MVP-based architecture powered by RxJava.</p></blockquote><p style="padding: 0px; margin: 8px 0px; line-height: 22.5px; letter-spacing: 0.5px; font-size: 12.5px; word-wrap: break-word; word-break: break-all; color: #333333; font-family: 'Microsoft YaHei', Verdana, sans-serif, 宋体; background-color: #ffffff;">这篇文章主要目的是讲述如何将传统的Activities 与 AsyncTasks 模式向目前主流的MVP架构基础的响应式编程框架过度。</p><p style="padding: 0px; margin: 8px 0px; line-height: 22.5px; letter-spacing: 0.5px; font-size: 12.5px; word-wrap: break-word; word-break: break-all; color: #333333; font-family: 'Microsoft YaHei', Verdana, sans-serif, 宋体; background-color: #ffffff;"><a href="http://static.oschina.net/uploads/img/201512/09114900_L0DC.jpeg" target="_blank" style="padding: 0px; margin: 0px; color: #ff8373; outline: 0px; font-size: 12px;"><img src="http://static.oschina.net/uploads/img/201512/09114900_L0DC.jpeg" alt="1*HrE2lljEfsCu1X_OUDfHYA" style="padding: 0px; margin: 10px 0px; border: 1px solid #dddddd; max-width: 640px; cursor: pointer; background: #f4f7f9;" /></a></p><blockquote style="padding: 3px 25px; margin: 20px 10px; position: relative; font-size: 10pt; line-height: 22px; border-left-width: 3px; border-left-color: #a4daf0; font-family: 'Microsoft YaHei', Verdana, sans-serif, 宋体; background-image: initial; background-color: #f4fdfd;"><p style="padding: 0px; margin: 8px 0px; line-height: 22.5px; letter-spacing: 0.5px; font-size: 12.5px; word-wrap: break-word; word-break: break-all;">Different parts of a software codebase should be independent, yet perfectly work together like a well-oiled machine&#8202;&#8212;&#8202;photo by Chester Alvarez.</p></blockquote><p style="padding: 0px; margin: 8px 0px; line-height: 22.5px; letter-spacing: 0.5px; font-size: 12.5px; word-wrap: break-word; word-break: break-all; color: #333333; font-family: 'Microsoft YaHei', Verdana, sans-serif, 宋体; background-color: #ffffff;">先畅享一下：~~~如果松耦合架构，分工明确，然后完美的组合在一起工作是一个很吊的事情。<br style="padding: 0px; margin: 0px;" />（转个图片还要写明白谁拍的，版权意识真强）</p><blockquote style="padding: 3px 25px; margin: 20px 10px; position: relative; font-size: 10pt; line-height: 22px; border-left-width: 3px; border-left-color: #a4daf0; font-family: 'Microsoft YaHei', Verdana, sans-serif, 宋体; background-image: initial; background-color: #f4fdfd;"><p style="padding: 0px; margin: 8px 0px; line-height: 22.5px; letter-spacing: 0.5px; font-size: 12.5px; word-wrap: break-word; word-break: break-all;">The Android dev ecosystem moves very quickly. Every week new tools are created, libraries are updated, blog posts are written and talks are given. If you go on holiday for a month, by the time you come back there will be a new version of the support library and/or Play Services.</p></blockquote><p style="padding: 0px; margin: 8px 0px; line-height: 22.5px; letter-spacing: 0.5px; font-size: 12.5px; word-wrap: break-word; word-break: break-all; color: #333333; font-family: 'Microsoft YaHei', Verdana, sans-serif, 宋体; background-color: #ffffff;">最近几年Android的生态链变化非常迅速，从底层的Android Api到应用层的各种开源的类库、工具更新非常迅速。一不留神就落后了。</p><blockquote style="padding: 3px 25px; margin: 20px 10px; position: relative; font-size: 10pt; line-height: 22px; border-left-width: 3px; border-left-color: #a4daf0; font-family: 'Microsoft YaHei', Verdana, sans-serif, 宋体; background-image: initial; background-color: #f4fdfd;"><p style="padding: 0px; margin: 8px 0px; line-height: 22.5px; letter-spacing: 0.5px; font-size: 12.5px; word-wrap: break-word; word-break: break-all;">I&#8217;ve been making Android apps with the ribot team for over three years. During this time, the architecture and technologies we&#8217;ve used to build Android apps have been continuously evolving. This article will take you through this journey by explaining our learnings, mistakes and the reasoning behind these architectural changes.</p></blockquote><p style="padding: 0px; margin: 8px 0px; line-height: 22.5px; letter-spacing: 0.5px; font-size: 12.5px; word-wrap: break-word; word-break: break-all; color: #333333; font-family: 'Microsoft YaHei', Verdana, sans-serif, 宋体; background-color: #ffffff;">我在Ribot团队从事Android应用开发工作三年多，伴随着公司技术的不断创新，积累了很多经验、错误以及在技术选型背后的故事。</p><h2>旧的应用架构</h2><blockquote style="padding: 3px 25px; margin: 20px 10px; position: relative; font-size: 10pt; line-height: 22px; border-left-width: 3px; border-left-color: #a4daf0; font-family: 'Microsoft YaHei', Verdana, sans-serif, 宋体; background-image: initial; background-color: #f4fdfd;"><p style="padding: 0px; margin: 8px 0px; line-height: 22.5px; letter-spacing: 0.5px; font-size: 12.5px; word-wrap: break-word; word-break: break-all;">The old times<br style="padding: 0px; margin: 0px;" />Back in 2012 our codebases used to follow a basic structure. We didn&#8217;t use any networking library and AsyncTasks were still our friends. The diagram below shows approximately how the architecture was.</p></blockquote><p style="padding: 0px; margin: 8px 0px; line-height: 22.5px; letter-spacing: 0.5px; font-size: 12.5px; word-wrap: break-word; word-break: break-all; color: #333333; font-family: 'Microsoft YaHei', Verdana, sans-serif, 宋体; background-color: #ffffff;">2012年那个时候，我们的代码都是用的原生Android，没有使用任何的网络请求框架，而是基于AsyncTasks书写。<br style="padding: 0px; margin: 0px;" /><a href="http://static.oschina.net/uploads/img/201512/09114859_sG5f.png" target="_blank" style="padding: 0px; margin: 0px; color: #ff8373; outline: 0px; font-size: 12px;"><img src="http://static.oschina.net/uploads/img/201512/09114859_sG5f.png" alt="1*TTtpcT4H80THBofnCtQ_L" style="padding: 0px; margin: 10px 0px; border: 1px solid #dddddd; max-width: 640px; cursor: pointer; background: #f4f7f9;" /></a>&gt;The code was structured in two layers: the data layer that was in charge of retrieving/saving data from REST APIs and persistent data stores; and the view layer, whose responsibility was handling and displaying the data on the UI.<br style="padding: 0px; margin: 0px;" />The APIProvider provides methods to enable Activities and Fragments to easily interact with the REST API. These methods use URLConnection and AsyncTasks to perform network calls in a separate thread and return the result to the Activities via callbacks.</p><p style="padding: 0px; margin: 8px 0px; line-height: 22.5px; letter-spacing: 0.5px; font-size: 12.5px; word-wrap: break-word; word-break: break-all; color: #333333; font-family: 'Microsoft YaHei', Verdana, sans-serif, 宋体; background-color: #ffffff;">代码分为两层，Data与View,Data层主要是用来从API获取数据，保存到持久化的db当中。View层主要就是把Data的数据显示到UI上。APIProvider提供方法出来，用于在Activity或者Fragment中方便的进行控制与交互。技术上将，使用URLConnection与AsyncTasks实现了一个异步的网络请求并将结果返回到调用的回调方法里面。</p><blockquote style="padding: 3px 25px; margin: 20px 10px; position: relative; font-size: 10pt; line-height: 22px; border-left-width: 3px; border-left-color: #a4daf0; font-family: 'Microsoft YaHei', Verdana, sans-serif, 宋体; background-image: initial; background-color: #f4fdfd;"><p style="padding: 0px; margin: 8px 0px; line-height: 22.5px; letter-spacing: 0.5px; font-size: 12.5px; word-wrap: break-word; word-break: break-all;">In a similar way, the CacheProvider contains methods that retrieve and store data from SharedPreferences or a SQLite database. It also uses callbacks to pass the result back to the Activities.</p></blockquote><p style="padding: 0px; margin: 8px 0px; line-height: 22.5px; letter-spacing: 0.5px; font-size: 12.5px; word-wrap: break-word; word-break: break-all; color: #333333; font-family: 'Microsoft YaHei', Verdana, sans-serif, 宋体; background-color: #ffffff;">相同的原理CacheProvider提供一系列方法，将SharedPreferences或者SQLite的数据取出来，并且返回给到Activity</p><p style="padding: 0px; margin: 8px 0px; line-height: 22.5px; letter-spacing: 0.5px; font-size: 12.5px; word-wrap: break-word; word-break: break-all; color: #333333; font-family: 'Microsoft YaHei', Verdana, sans-serif, 宋体; background-color: #ffffff;"><strong style="padding: 0px; margin: 0px;">问题</strong></p><blockquote style="padding: 3px 25px; margin: 20px 10px; position: relative; font-size: 10pt; line-height: 22px; border-left-width: 3px; border-left-color: #a4daf0; font-family: 'Microsoft YaHei', Verdana, sans-serif, 宋体; background-image: initial; background-color: #f4fdfd;"><p style="padding: 0px; margin: 8px 0px; line-height: 22.5px; letter-spacing: 0.5px; font-size: 12.5px; word-wrap: break-word; word-break: break-all;">The problems<br style="padding: 0px; margin: 0px;" />The main issue with this approach was that the View layer had too many responsibilities. Imagine a simple common scenario where the application has to load a list of blog posts, cache them in a SQLite database and finally display them on a ListView. The Activity would have to do the following:</p></blockquote><p style="padding: 0px; margin: 8px 0px; line-height: 22.5px; letter-spacing: 0.5px; font-size: 12.5px; word-wrap: break-word; word-break: break-all; color: #333333; font-family: 'Microsoft YaHei', Verdana, sans-serif, 宋体; background-color: #ffffff;">主要问题是View层有太多的累赘，以一个博客列表为例来讲述，比如博客需要显示一个ListView，从SQLite读取数据，Activity需要做到以下几点：</p><blockquote style="padding: 3px 25px; margin: 20px 10px; position: relative; font-size: 10pt; line-height: 22px; border-left-width: 3px; border-left-color: #a4daf0; font-family: 'Microsoft YaHei', Verdana, sans-serif, 宋体; background-image: initial; background-color: #f4fdfd;"><ol style="padding: 0px; margin: 10px 20px; line-height: 24px;"><li style="padding: 0px; margin: 0px;">Call a method loadPosts(callback) in the APIProvider</li><li style="padding: 0px; margin: 0px;">Wait for the APIProvider success callback and then call savePosts(callback) in the CacheProvider.</li><li style="padding: 0px; margin: 0px;">Wait for the CacheProvider success callback and then display the posts on the ListView.</li><li style="padding: 0px; margin: 0px;">Separately handle the two potential errors callback from the APIProvider and CacheProvider.</li></ol></blockquote><ol style="padding: 0px; margin: 10px 20px; line-height: 22.5px; color: #333333; font-family: 'Microsoft YaHei', Verdana, sans-serif, 宋体; font-size: 12.5px; background-color: #ffffff;"><li style="padding: 0px; margin: 0px;">执行APIProvider里面的loadPosts的方法，里面传入回调参数内容。</li><li style="padding: 0px; margin: 0px;">等待loadPosts执行成功后，执行回调里面的CacheProvider中的savePosts方法，savePosts也要传入回调参数。</li><li style="padding: 0px; margin: 0px;">等待savePosts执行成功后，执行回调里面的方法刷新ListView</li><li style="padding: 0px; margin: 0px;">分别书写代码处理2 3 两步的错误回调内容。</li></ol><blockquote style="padding: 3px 25px; margin: 20px 10px; position: relative; font-size: 10pt; line-height: 22px; border-left-width: 3px; border-left-color: #a4daf0; font-family: 'Microsoft YaHei', Verdana, sans-serif, 宋体; background-image: initial; background-color: #f4fdfd;"><p style="padding: 0px; margin: 8px 0px; line-height: 22.5px; letter-spacing: 0.5px; font-size: 12.5px; word-wrap: break-word; word-break: break-all;">This is a very simple example. In a real case scenario the REST API will probably not return the data like the view needs it. Therefore, the Activity will have to somehow transform or filter the data before showing it. Another common case is when the loadPosts() method takes a parameter that needs to be fetched from somewhere else, for example an email address provided by the Play Services SDK. It&#8217;s likely that the SDK will return the email asynchronously using a callback, meaning that we now have three levels of nested callbacks. If we keep adding complexity, this approach will result into what is known as callback hell.</p></blockquote><p style="padding: 0px; margin: 8px 0px; line-height: 22.5px; letter-spacing: 0.5px; font-size: 12.5px; word-wrap: break-word; word-break: break-all; color: #333333; font-family: 'Microsoft YaHei', Verdana, sans-serif, 宋体; background-color: #ffffff;">这还是一个比较简单的例子，在一些真实的场景中，远程的API可能没有返回程序的必须值，但是activity必须把数据处理完成之后才能显示结果。再一个例子就是如果loadPosts方法需要借助一些其他地方的返回参数时，类似用多线程去实现同步请求，为保证数据正常请求，意味着必须做一个三层的回调，如果再复杂一些，想理清楚这些回调就是很蛋疼的事情。</p><blockquote style="padding: 3px 25px; margin: 20px 10px; position: relative; font-size: 10pt; line-height: 22px; border-left-width: 3px; border-left-color: #a4daf0; font-family: 'Microsoft YaHei', Verdana, sans-serif, 宋体; background-image: initial; background-color: #f4fdfd;"><p style="padding: 0px; margin: 8px 0px; line-height: 22.5px; letter-spacing: 0.5px; font-size: 12.5px; word-wrap: break-word; word-break: break-all;">In summary:<br style="padding: 0px; margin: 0px;" />Activities and Fragments become very large and difficult to maintain<br style="padding: 0px; margin: 0px;" />Too many nested callbacks means the code is ugly and difficult to understand so painful to make changes or add new features.<br style="padding: 0px; margin: 0px;" />Unit testing becomes challenging, if not impossible, because a lot of the logic lives within the Activities or Fragments that are arduous to unit test.</p></blockquote><p style="padding: 0px; margin: 8px 0px; line-height: 22.5px; letter-spacing: 0.5px; font-size: 12.5px; word-wrap: break-word; word-break: break-all; color: #333333; font-family: 'Microsoft YaHei', Verdana, sans-serif, 宋体; background-color: #ffffff;">总之，回调多了之后，Activity与Fragment会乱的要死，并且一般人无法直视。</p><h2>牛逼的新架构出来了</h2><blockquote style="padding: 3px 25px; margin: 20px 10px; position: relative; font-size: 10pt; line-height: 22px; border-left-width: 3px; border-left-color: #a4daf0; font-family: 'Microsoft YaHei', Verdana, sans-serif, 宋体; background-image: initial; background-color: #f4fdfd;"><p style="padding: 0px; margin: 8px 0px; line-height: 22.5px; letter-spacing: 0.5px; font-size: 12.5px; word-wrap: break-word; word-break: break-all;">A new architecture driven by RxJava<br style="padding: 0px; margin: 0px;" />We followed the previous approach for about two years. During that time, we made several improvements that slightly mitigated the problems described above. For example, we added several helper classes to reduce the code in Activities and Fragments and we started using Volley in the APIProvider. Despite these changes, our application code wasn&#8217;t yet test-friendly and the callback hell issue was still happening too often.</p></blockquote><p style="padding: 0px; margin: 8px 0px; line-height: 22.5px; letter-spacing: 0.5px; font-size: 12.5px; word-wrap: break-word; word-break: break-all; color: #333333; font-family: 'Microsoft YaHei', Verdana, sans-serif, 宋体; background-color: #ffffff;">我们在蛋疼的架构中煎熬了2年，当然也尝试过很多方式，最终也只能是缓和一下乱的问题。我们在APIProvider使用了Volley，代替了AsyncHttpClient，但是其实是一个吊样。</p><blockquote style="padding: 3px 25px; margin: 20px 10px; position: relative; font-size: 10pt; line-height: 22px; border-left-width: 3px; border-left-color: #a4daf0; font-family: 'Microsoft YaHei', Verdana, sans-serif, 宋体; background-image: initial; background-color: #f4fdfd;"><p style="padding: 0px; margin: 8px 0px; line-height: 22.5px; letter-spacing: 0.5px; font-size: 12.5px; word-wrap: break-word; word-break: break-all;">It wasn&#8217;t until 2014 when we started reading about RxJava. After trying it on a few sample projects, we realised that this could finally be the solution to the nested callback problem. If you are not familiar with reactive programming you can read this introduction. In short, RxJava allows you to manage data via asynchronous streams and gives you many operators that you can apply to the stream in order to transform, filter or combine the data.</p></blockquote><p style="padding: 0px; margin: 8px 0px; line-height: 22.5px; letter-spacing: 0.5px; font-size: 12.5px; word-wrap: break-word; word-break: break-all; color: #333333; font-family: 'Microsoft YaHei', Verdana, sans-serif, 宋体; background-color: #ffffff;">不到2014年我们就开始进行RxJava的预研，然后尝试了一批简单的项目，感觉RxJava的方式是解决我们嵌套回调的终极解决办法。简单的说，RxJava允许你通过异步流的方式管理你的数据，并且还可以通过操作符（Operators）对Observable对象的变换</p><blockquote style="padding: 3px 25px; margin: 20px 10px; position: relative; font-size: 10pt; line-height: 22px; border-left-width: 3px; border-left-color: #a4daf0; font-family: 'Microsoft YaHei', Verdana, sans-serif, 宋体; background-image: initial; background-color: #f4fdfd;"><p style="padding: 0px; margin: 8px 0px; line-height: 22.5px; letter-spacing: 0.5px; font-size: 12.5px; word-wrap: break-word; word-break: break-all;">Taking into account the pains we experienced in previous years, we started to think about how the architecture of a new app would look. So we came up with this.</p></blockquote><p style="padding: 0px; margin: 8px 0px; line-height: 22.5px; letter-spacing: 0.5px; font-size: 12.5px; word-wrap: break-word; word-break: break-all; color: #333333; font-family: 'Microsoft YaHei', Verdana, sans-serif, 宋体; background-color: #ffffff;">我们用了几年的经验痛定思痛，搞了下面这么个东西，新的APP的架构图</p><p style="padding: 0px; margin: 8px 0px; line-height: 22.5px; letter-spacing: 0.5px; font-size: 12.5px; word-wrap: break-word; word-break: break-all; color: #333333; font-family: 'Microsoft YaHei', Verdana, sans-serif, 宋体; background-color: #ffffff;"><a href="http://static.oschina.net/uploads/img/201512/09114859_pxYz.png" target="_blank" style="padding: 0px; margin: 0px; color: #ff8373; outline: 0px; font-size: 12px;"><img src="http://static.oschina.net/uploads/img/201512/09114859_pxYz.png" alt="1*kCynNIa5PscRl41V2scosA-200" style="padding: 0px; margin: 10px 0px; border: 1px solid #dddddd; max-width: 640px; cursor: pointer; background: #f4f7f9;" /></a></p><blockquote style="padding: 3px 25px; margin: 20px 10px; position: relative; font-size: 10pt; line-height: 22px; border-left-width: 3px; border-left-color: #a4daf0; font-family: 'Microsoft YaHei', Verdana, sans-serif, 宋体; background-image: initial; background-color: #f4fdfd;"><p style="padding: 0px; margin: 8px 0px; line-height: 22.5px; letter-spacing: 0.5px; font-size: 12.5px; word-wrap: break-word; word-break: break-all;">Similar to the first approach, this architecture can be separated into a data and view layer. The data layer contains the DataManager and a set of helpers. The view layer is formed by Android framework components like Fragments, Activities, ViewGroups, etc.</p></blockquote><p style="padding: 0px; margin: 8px 0px; line-height: 22.5px; letter-spacing: 0.5px; font-size: 12.5px; word-wrap: break-word; word-break: break-all; color: #333333; font-family: 'Microsoft YaHei', Verdana, sans-serif, 宋体; background-color: #ffffff;">与第一种方法相似，这个架构也是分为Data层与View层，Data层包含DataManager与一堆Helper；View层是包含Fragments, Activities, ViewGroups等。</p><blockquote style="padding: 3px 25px; margin: 20px 10px; position: relative; font-size: 10pt; line-height: 22px; border-left-width: 3px; border-left-color: #a4daf0; font-family: 'Microsoft YaHei', Verdana, sans-serif, 宋体; background-image: initial; background-color: #f4fdfd;"><p style="padding: 0px; margin: 8px 0px; line-height: 22.5px; letter-spacing: 0.5px; font-size: 12.5px; word-wrap: break-word; word-break: break-all;">Helper classes (third column on diagram) have very specific responsibilities and implement them in a concise manner. For example, most projects have helpers for accessing REST APIs, reading data from databases or interacting with third party SDKs. Different applications will have a different number of helpers but the most common ones are:</p></blockquote><p style="padding: 0px; margin: 8px 0px; line-height: 22.5px; letter-spacing: 0.5px; font-size: 12.5px; word-wrap: break-word; word-break: break-all; color: #333333; font-family: 'Microsoft YaHei', Verdana, sans-serif, 宋体; background-color: #ffffff;">Helper主要是集成第三方的类库，以便于在代码中几行代码就可以清晰的实现某个功能，比如请求API，访问数据库等，虽然不同的应用程序都有不同的类库，但是他们无非就是以下这些内容：</p><blockquote style="padding: 3px 25px; margin: 20px 10px; position: relative; font-size: 10pt; line-height: 22px; border-left-width: 3px; border-left-color: #a4daf0; font-family: 'Microsoft YaHei', Verdana, sans-serif, 宋体; background-image: initial; background-color: #f4fdfd;"><ul style="padding: 0px; margin: 0px 0px 10px 20px; line-height: 24px;"><li style="padding: 0px; margin: 0px;">PreferencesHelper: reads and saves data in SharedPreferences.</li><li style="padding: 0px; margin: 0px;">DatabaseHelper: handles accessing SQLite databases.</li><li style="padding: 0px; margin: 0px;"><a href="http://square.github.io/retrofit/" style="padding: 0px; margin: 0px; color: #ff8373; outline: 0px; font-size: 12px;">Retrofit</a>&nbsp;services: perform calls to REST APIs. We started using Retrofit instead of Volley because it provides support for RxJava. It&#8217;s also nicer to use.</li></ul></blockquote><ul style="padding: 0px; margin: 0px 0px 10px 20px; line-height: 22.5px; color: #333333; font-family: 'Microsoft YaHei', Verdana, sans-serif, 宋体; font-size: 12.5px; background-color: #ffffff;"><li style="padding: 0px; margin: 0px;">从SharedPreferences中读取或者写入数据</li><li style="padding: 0px; margin: 0px;">读写SQLite数据库</li><li style="padding: 0px; margin: 0px;">类似与square的Retrofit服务，也就是Http Client,我们用Restrofit替代了Volley因为他支持Rxjava,并且更吊。</li></ul><blockquote style="padding: 3px 25px; margin: 20px 10px; position: relative; font-size: 10pt; line-height: 22px; border-left-width: 3px; border-left-color: #a4daf0; font-family: 'Microsoft YaHei', Verdana, sans-serif, 宋体; background-image: initial; background-color: #f4fdfd;"><p style="padding: 0px; margin: 8px 0px; line-height: 22.5px; letter-spacing: 0.5px; font-size: 12.5px; word-wrap: break-word; word-break: break-all;">Most of the public methods inside helper classes will return RxJava Observables.<br style="padding: 0px; margin: 0px;" />The DataManager is the brain of the architecture. It extensively uses RxJava operators to combine, filter and transform data retrieved from helper classes. The aim of the DataManager is to reduce the amount of work that Activities and Fragments have to do by providing data that is ready to display and won&#8217;t usually need any transformation.</p></blockquote><p style="padding: 0px; margin: 8px 0px; line-height: 22.5px; letter-spacing: 0.5px; font-size: 12.5px; word-wrap: break-word; word-break: break-all; color: #333333; font-family: 'Microsoft YaHei', Verdana, sans-serif, 宋体; background-color: #ffffff;">RxJava最核心的两个东西是Observables（被观察者，事件源）和Subscribers（观察者）,在Helper类中的Public方法，一般都会返回一个RxJava的Observables;DataManager是整个架构的大脑，他大量的使用Rxjava的operators对Helper返回来的数据进行的整合过滤、二次处理。</p><blockquote style="padding: 3px 25px; margin: 20px 10px; position: relative; font-size: 10pt; line-height: 22px; border-left-width: 3px; border-left-color: #a4daf0; font-family: 'Microsoft YaHei', Verdana, sans-serif, 宋体; background-image: initial; background-color: #f4fdfd;"><p style="padding: 0px; margin: 8px 0px; line-height: 22.5px; letter-spacing: 0.5px; font-size: 12.5px; word-wrap: break-word; word-break: break-all;">The code below shows what a DataManager method would look like. This sample method works as follows:</p></blockquote><p style="padding: 0px; margin: 8px 0px; line-height: 22.5px; letter-spacing: 0.5px; font-size: 12.5px; word-wrap: break-word; word-break: break-all; color: #333333; font-family: 'Microsoft YaHei', Verdana, sans-serif, 宋体; background-color: #ffffff;">下面用一个例子来说明DataManager是做什么的:</p><blockquote style="padding: 3px 25px; margin: 20px 10px; position: relative; font-size: 10pt; line-height: 22px; border-left-width: 3px; border-left-color: #a4daf0; font-family: 'Microsoft YaHei', Verdana, sans-serif, 宋体; background-image: initial; background-color: #f4fdfd;"><ol style="padding: 0px; margin: 10px 20px; line-height: 24px;"><li style="padding: 0px; margin: 0px;">Call the Retrofit service to load a list of blog posts from a REST API</li><li style="padding: 0px; margin: 0px;">Save the posts in a local database for caching purposes using the DatabaseHelper.</li><li style="padding: 0px; margin: 0px;">Filter the blog posts written today because those are the only ones the view layer wants to display.</li></ol></blockquote><ol style="padding: 0px; margin: 10px 20px; line-height: 22.5px; color: #333333; font-family: 'Microsoft YaHei', Verdana, sans-serif, 宋体; font-size: 12.5px; background-color: #ffffff;"><li style="padding: 0px; margin: 0px;">调用Retrofit的服务，去请求一个博客列表的API</li><li style="padding: 0px; margin: 0px;">用DatabaseHelper保存这些数据到数据库</li><li style="padding: 0px; margin: 0px;">过滤出这些BLOG哪些是今天写的，然后显示到UI界面上。</li></ol><blockquote style="padding: 3px 25px; margin: 20px 10px; position: relative; font-size: 10pt; line-height: 22px; border-left-width: 3px; border-left-color: #a4daf0; font-family: 'Microsoft YaHei', Verdana, sans-serif, 宋体; background-image: initial; background-color: #f4fdfd;"><p style="padding: 0px; margin: 8px 0px; line-height: 22.5px; letter-spacing: 0.5px; font-size: 12.5px; word-wrap: break-word; word-break: break-all;">Components in the view layer such as Activities or Fragments would simply call this method and subscribe to the returned Observable. Once the subscription finishes, the different Posts emitted by the Observable can be directly added to an Adapter in order to be displayed on a RecyclerView or similar.</p></blockquote><p style="padding: 0px; margin: 8px 0px; line-height: 22.5px; letter-spacing: 0.5px; font-size: 12.5px; word-wrap: break-word; word-break: break-all; color: #333333; font-family: 'Microsoft YaHei', Verdana, sans-serif, 宋体; background-color: #ffffff;">Observables发出一系列事件，Subscribers（例如 Activities or Fragments）处理这些事件,可以直接将数据显示到一些可以回收、重用的View上面。<br style="padding: 0px; margin: 0px;" />【BTW:如果一个Observerble没有任何的的Subscriber，那么这个Observable是不会发出任何事件的】</p><blockquote style="padding: 3px 25px; margin: 20px 10px; position: relative; font-size: 10pt; line-height: 22px; border-left-width: 3px; border-left-color: #a4daf0; font-family: 'Microsoft YaHei', Verdana, sans-serif, 宋体; background-image: initial; background-color: #f4fdfd;"><p style="padding: 0px; margin: 8px 0px; line-height: 22.5px; letter-spacing: 0.5px; font-size: 12.5px; word-wrap: break-word; word-break: break-all;">The last element of this architecture is the event bus. The event bus allows us to broadcast events that happen in the data layer, so that multiple components in the view layer can subscribe to these events. For example, a signOut() method in the DataManager can post an event when the Observable completes so that multiple Activities that are subscribed to this event can change their UI to show a signed out state.</p></blockquote><p style="padding: 0px; margin: 8px 0px; line-height: 22.5px; letter-spacing: 0.5px; font-size: 12.5px; word-wrap: break-word; word-break: break-all; color: #333333; font-family: 'Microsoft YaHei', Verdana, sans-serif, 宋体; background-color: #ffffff;">这个架构的另外一个模块是event bus，event bus可以让我们在Data层发出广播（不是Android的Broadcast）然后不同的模块去注册并接收不同的广播事件</p><blockquote style="padding: 3px 25px; margin: 20px 10px; position: relative; font-size: 10pt; line-height: 22px; border-left-width: 3px; border-left-color: #a4daf0; font-family: 'Microsoft YaHei', Verdana, sans-serif, 宋体; background-image: initial; background-color: #f4fdfd;"><p style="padding: 0px; margin: 8px 0px; line-height: 22.5px; letter-spacing: 0.5px; font-size: 12.5px; word-wrap: break-word; word-break: break-all;">Why was this approach better?<br style="padding: 0px; margin: 0px;" />RxJava Observables and operators remove the need for having nested callbacks.<br style="padding: 0px; margin: 0px;" /><a href="http://static.oschina.net/uploads/img/201512/09114859_ZwZa.jpeg" target="_blank" style="padding: 0px; margin: 0px; color: #ff8373; outline: 0px; font-size: 12px;"><img src="http://static.oschina.net/uploads/img/201512/09114859_ZwZa.jpeg" alt="1*BIsOCzJnc-SSU8fPXTiP1A" style="padding: 0px; margin: 10px 0px; border: 1px solid #dddddd; max-width: 640px; cursor: pointer; background: #f4f7f9;" /></a></p></blockquote><p style="padding: 0px; margin: 8px 0px; line-height: 22.5px; letter-spacing: 0.5px; font-size: 12.5px; word-wrap: break-word; word-break: break-all; color: #333333; font-family: 'Microsoft YaHei', Verdana, sans-serif, 宋体; background-color: #ffffff;">为什么这个方式这么牛逼，是因为Observables与operators可以去掉那一堆必须的回调方法</p><blockquote style="padding: 3px 25px; margin: 20px 10px; position: relative; font-size: 10pt; line-height: 22px; border-left-width: 3px; border-left-color: #a4daf0; font-family: 'Microsoft YaHei', Verdana, sans-serif, 宋体; background-image: initial; background-color: #f4fdfd;"><p style="padding: 0px; margin: 8px 0px; line-height: 22.5px; letter-spacing: 0.5px; font-size: 12.5px; word-wrap: break-word; word-break: break-all;">The DataManager takes over responsibilities that were previously part of the view layer. Hence, it makes Activities and Fragments more lightweight.<br style="padding: 0px; margin: 0px;" />Moving code from Activities and Fragments to the DataManager and helpers means that writing unit tests becomes easier.</p></blockquote><p style="padding: 0px; margin: 8px 0px; line-height: 22.5px; letter-spacing: 0.5px; font-size: 12.5px; word-wrap: break-word; word-break: break-all; color: #333333; font-family: 'Microsoft YaHei', Verdana, sans-serif, 宋体; background-color: #ffffff;">DataManager替代了传统架构中很多代码，从而使得Activity与Fragment变得更加轻量级。并且使得单元测试变得更加简单。</p><blockquote style="padding: 3px 25px; margin: 20px 10px; position: relative; font-size: 10pt; line-height: 22px; border-left-width: 3px; border-left-color: #a4daf0; font-family: 'Microsoft YaHei', Verdana, sans-serif, 宋体; background-image: initial; background-color: #f4fdfd;"><p style="padding: 0px; margin: 8px 0px; line-height: 22.5px; letter-spacing: 0.5px; font-size: 12.5px; word-wrap: break-word; word-break: break-all;">Clear separation of responsibilities and having the DataManager as the only point of interaction with the data layer, makes this architecture test-friendly. Helper classes or the DataManager can be easily mocked.</p></blockquote><p style="padding: 0px; margin: 8px 0px; line-height: 22.5px; letter-spacing: 0.5px; font-size: 12.5px; word-wrap: break-word; word-break: break-all; color: #333333; font-family: 'Microsoft YaHei', Verdana, sans-serif, 宋体; background-color: #ffffff;">DataManager成为了唯一的数据交互部分，这样清晰的架构使得更方便进行代码自测。</p><blockquote style="padding: 3px 25px; margin: 20px 10px; position: relative; font-size: 10pt; line-height: 22px; border-left-width: 3px; border-left-color: #a4daf0; font-family: 'Microsoft YaHei', Verdana, sans-serif, 宋体; background-image: initial; background-color: #f4fdfd;"><p style="padding: 0px; margin: 8px 0px; line-height: 22.5px; letter-spacing: 0.5px; font-size: 12.5px; word-wrap: break-word; word-break: break-all;">What problems did we still have?<br style="padding: 0px; margin: 0px;" />For large and very complex projects the DataManager can become too bloated and difficult to maintain.<br style="padding: 0px; margin: 0px;" />Although view layer components such as Activities and Fragments became more lightweight, they still have to handle a considerable amount of logic around managing RxJava subscriptions, analysing errors, etc.</p></blockquote><p style="padding: 0px; margin: 8px 0px; line-height: 22.5px; letter-spacing: 0.5px; font-size: 12.5px; word-wrap: break-word; word-break: break-all; color: #333333; font-family: 'Microsoft YaHei', Verdana, sans-serif, 宋体; background-color: #ffffff;"><strong style="padding: 0px; margin: 0px;">我们还有什么问题？</strong><br style="padding: 0px; margin: 0px;" />- 如果对于非常庞大并且复杂的项目来说，DataManger也会变得非常臃肿并且难以维护。<br style="padding: 0px; margin: 0px;" />- 尽管Activity与Fragment已经变得更加轻量级，但是对于错误异常的处理还是要在subscriptions的地方去书写。</p><h2>一体化的MVP模式</h2><blockquote style="padding: 3px 25px; margin: 20px 10px; position: relative; font-size: 10pt; line-height: 22px; border-left-width: 3px; border-left-color: #a4daf0; font-family: 'Microsoft YaHei', Verdana, sans-serif, 宋体; background-image: initial; background-color: #f4fdfd;"><p style="padding: 0px; margin: 8px 0px; line-height: 22.5px; letter-spacing: 0.5px; font-size: 12.5px; word-wrap: break-word; word-break: break-all;">Integrating Model View Presenter<br style="padding: 0px; margin: 0px;" />In the past year, several architectural patterns such as MVP or MVVM have been gaining popularity within the Android community. After exploring these patterns on a sample project and article, we found that MVP could bring very valuable improvements to our existing approach. Because our current architecture was divided in two layers (view and data), adding MVP felt natural. We simply had to add a new layer of presenters and move part of the code from the view to presenters.</p></blockquote><p style="padding: 0px; margin: 8px 0px; line-height: 22.5px; letter-spacing: 0.5px; font-size: 12.5px; word-wrap: break-word; word-break: break-all; color: #333333; font-family: 'Microsoft YaHei', Verdana, sans-serif, 宋体; background-color: #ffffff;">前几年开始，很多类似MVP与MVVM在Android的一些社区比较流行，经过研究之后，我们发现MVP模式是对我们目前的方案最有价值的改动。我们的两层架构View-Data与MVP的 Model-View架构天然融合，理念一致。我们只需要增加一个presenters层，然后把之前在view实现的代码移到上面就可以了。<br style="padding: 0px; margin: 0px;" /><a href="http://static.oschina.net/uploads/img/201512/09114859_msbn.png" target="_blank" style="padding: 0px; margin: 0px; color: #ff8373; outline: 0px; font-size: 12px;"><img src="http://static.oschina.net/uploads/img/201512/09114859_msbn.png" alt="1*NonRJ0uzzN9o1ygT6J421g" style="padding: 0px; margin: 10px 0px; border: 1px solid #dddddd; max-width: 640px; cursor: pointer; background: #f4f7f9;" /></a></p><blockquote style="padding: 3px 25px; margin: 20px 10px; position: relative; font-size: 10pt; line-height: 22px; border-left-width: 3px; border-left-color: #a4daf0; font-family: 'Microsoft YaHei', Verdana, sans-serif, 宋体; background-image: initial; background-color: #f4fdfd;"><p style="padding: 0px; margin: 8px 0px; line-height: 22.5px; letter-spacing: 0.5px; font-size: 12.5px; word-wrap: break-word; word-break: break-all;">The data layer remains as it was but it&#8217;s now called model to be more consistent with the name of the pattern.<br style="padding: 0px; margin: 0px;" /><strong style="padding: 0px; margin: 0px;">Presenters</strong>&nbsp;are in charge of loading data from the model and calling the right method in the view when the result is ready. They subscribe to Observables returned by the data manager. Therefore, they have to handle things like schedulers and subscriptions. Moreover, they can analyse error codes or apply extra operations to the data stream if needed. For example, if we need to filter some data and this same filter is not likely to be reused anywhere else, it may make more sense to implement it in the presenter rather than in the data manager.</p></blockquote><p style="padding: 0px; margin: 8px 0px; line-height: 22.5px; letter-spacing: 0.5px; font-size: 12.5px; word-wrap: break-word; word-break: break-all; color: #333333; font-family: 'Microsoft YaHei', Verdana, sans-serif, 宋体; background-color: #ffffff;">之前的Data层就是现在的MVP中的Model，Presenter现在负责从Model中加载数据，加载完成后后再去调用左边的在Activity、ViewGroup中的方法。Presenters的subscribe去接收data manager中的Observables广播出来的数据。<br style="padding: 0px; margin: 0px;" />举例说明，如果我们需要增加数据的过滤操作但是并不是所有地方都需要的那种，那就可以在presenter里面写这些代码，而不用写在公共的datamanager里面。</p><p style="padding: 0px; margin: 8px 0px; line-height: 22.5px; letter-spacing: 0.5px; font-size: 12.5px; word-wrap: break-word; word-break: break-all; color: #333333; font-family: 'Microsoft YaHei', Verdana, sans-serif, 宋体; background-color: #ffffff;">Below you can see what a public method in the presenter would look like. This code subscribes to the Observable returned by the dataManager.loadTodayPosts() method we defined in the previous section.</p><p style="padding: 0px; margin: 8px 0px; line-height: 22.5px; letter-spacing: 0.5px; font-size: 12.5px; word-wrap: break-word; word-break: break-all; color: #333333; font-family: 'Microsoft YaHei', Verdana, sans-serif, 宋体; background-color: #ffffff;">我们定义的dataManager.loadTodayPosts()会广播出数据给到对应的subscribes</p><p style="padding: 0px; margin: 8px 0px; line-height: 22.5px; letter-spacing: 0.5px; font-size: 12.5px; word-wrap: break-word; word-break: break-all; color: #333333; font-family: 'Microsoft YaHei', Verdana, sans-serif, 宋体; background-color: #ffffff;">The mMvpView is the view component that this presenter is assisting. Usually the MVP view is an instance of an Activity, Fragment or ViewGroup.</p><p style="padding: 0px; margin: 8px 0px; line-height: 22.5px; letter-spacing: 0.5px; font-size: 12.5px; word-wrap: break-word; word-break: break-all; color: #333333; font-family: 'Microsoft YaHei', Verdana, sans-serif, 宋体; background-color: #ffffff;">MVP的View并不是指的Android的View，而是一个界面组件的的实例，例如Activity, Fragment ， ViewGroup 在注册presenter的时候，需要把自己当前的实例传递进去。</p><pre style="padding: 5px; margin-top: 0px; margin-bottom: 0px; line-height: 18px; font-size: 9pt; font-family: 'Courier New', Arial; border: 1px solid #dddddd; color: #333333; background: #f6f6f6;"><code hljs"="" style="padding: 8px 5px; margin: 0px 2px; display: block; overflow-x: auto; color: red; font-family: Consolas, 'Bitstream Vera Sans Mono', 'Courier New', Courier, 'monospace !important'; border-radius: 3px; white-space: pre-wrap; word-wrap: break-word; word-break: break-all; background: #ffffff;"><span style="padding: 0px; margin: 0px; color: grey; font-style: italic;">// Activity onCreate 中的代码段 </span> <span style="padding: 0px; margin: 0px; font-weight: 700; color: navy;">if</span> (presenter == <span style="padding: 0px; margin: 0px; font-weight: 700; color: navy;">null</span>)         presenter = <span style="padding: 0px; margin: 0px; font-weight: 700; color: navy;">new</span> Presenter1();         presenter.onTakeView(<span style="padding: 0px; margin: 0px; font-weight: 700; color: navy;">this</span>);  </code></pre><blockquote style="padding: 3px 25px; margin: 20px 10px; position: relative; font-size: 10pt; line-height: 22px; border-left-width: 3px; border-left-color: #a4daf0; font-family: 'Microsoft YaHei', Verdana, sans-serif, 宋体; background-image: initial; background-color: #f4fdfd;"><p style="padding: 0px; margin: 8px 0px; line-height: 22.5px; letter-spacing: 0.5px; font-size: 12.5px; word-wrap: break-word; word-break: break-all;">Like the previous architecture, the view layer contains standard framework components like ViewGroups, Fragments or Activities. The main difference is that these components don&#8217;t subscribe directly to Observables. They instead implement an MvpView interface and provide a list of concise methods such as showError() or showProgressIndicator(). The view components are also in charge of handling user interactions such as click events and act accordingly by calling the right method in the presenter. For example, if we have a button that loads the list of posts, our Activity would call presenter.loadTodayPosts() from the onClick listener.</p></blockquote><p style="padding: 0px; margin: 8px 0px; line-height: 22.5px; letter-spacing: 0.5px; font-size: 12.5px; word-wrap: break-word; word-break: break-all; color: #333333; font-family: 'Microsoft YaHei', Verdana, sans-serif, 宋体; background-color: #ffffff;">这个架构与上一个架构不同的是，ViewLayer 也就是Activity这些，不会直接去订阅接收Observables发出的这些事件。而是只在Activity实现几个简单的显示错误、显示进度的方法（用接口interface来规范统一），然后把当前实例以参数形式传递给到对应事件的Presenter，由Presenter去执行这些显示错误、显示进度的方法。<br style="padding: 0px; margin: 0px;" />当然对于用户交互部分的按钮点击事件还是要在Activity中进行处理。</p><blockquote style="padding: 3px 25px; margin: 20px 10px; position: relative; font-size: 10pt; line-height: 22px; border-left-width: 3px; border-left-color: #a4daf0; font-family: 'Microsoft YaHei', Verdana, sans-serif, 宋体; background-image: initial; background-color: #f4fdfd;"><p style="padding: 0px; margin: 8px 0px; line-height: 22.5px; letter-spacing: 0.5px; font-size: 12.5px; word-wrap: break-word; word-break: break-all;">If you want to see a full working sample of this MVP-based architecture, you can check out our Android Boilerplate project on GitHub. You can also read more about it in the ribot&#8217;s architecture guidelines.</p></blockquote><p style="padding: 0px; margin: 8px 0px; line-height: 22.5px; letter-spacing: 0.5px; font-size: 12.5px; word-wrap: break-word; word-break: break-all; color: #333333; font-family: 'Microsoft YaHei', Verdana, sans-serif, 宋体; background-color: #ffffff;">关于MVP的文章可以自行百度一下，<code style="padding: 0px; margin: 0px; font-family: Consolas, 'Bitstream Vera Sans Mono', 'Courier New', Courier, 'monospace !important'; color: red;">MVP Android</code>&nbsp;关键词</p><blockquote style="padding: 3px 25px; margin: 20px 10px; position: relative; font-size: 10pt; line-height: 22px; border-left-width: 3px; border-left-color: #a4daf0; font-family: 'Microsoft YaHei', Verdana, sans-serif, 宋体; background-image: initial; background-color: #f4fdfd;"><p style="padding: 0px; margin: 8px 0px; line-height: 22.5px; letter-spacing: 0.5px; font-size: 12.5px; word-wrap: break-word; word-break: break-all;">Why is this approach better?</p></blockquote><p style="padding: 0px; margin: 8px 0px; line-height: 22.5px; letter-spacing: 0.5px; font-size: 12.5px; word-wrap: break-word; word-break: break-all; color: #333333; font-family: 'Microsoft YaHei', Verdana, sans-serif, 宋体; background-color: #ffffff;"><strong style="padding: 0px; margin: 0px;">为什么这个又最吊</strong></p><blockquote style="padding: 3px 25px; margin: 20px 10px; position: relative; font-size: 10pt; line-height: 22px; border-left-width: 3px; border-left-color: #a4daf0; font-family: 'Microsoft YaHei', Verdana, sans-serif, 宋体; background-image: initial; background-color: #f4fdfd;"><ul style="padding: 0px; margin: 0px 0px 10px 20px; line-height: 24px;"><li style="padding: 0px; margin: 0px;">Activities and Fragments become very lightweight. Their only responsibilities are to set up/update the UI and handle user events. Therefore, they become easier to maintain.</li><li style="padding: 0px; margin: 0px;">We can now easily write unit tests for the presenters by mocking the view layer. Before, this code was part of the view layer so we couldn&#8217;t unit test it. The whole architecture becomes very test-friendly.</li><li style="padding: 0px; margin: 0px;">If the data manager is becoming bloated, we can mitigate this problem by moving some code to the presenters.</li></ul></blockquote><ul style="padding: 0px; margin: 0px 0px 10px 20px; line-height: 22.5px; color: #333333; font-family: 'Microsoft YaHei', Verdana, sans-serif, 宋体; font-size: 12.5px; background-color: #ffffff;"><li style="padding: 0px; margin: 0px;">Activity与Fragment代码量大大降低，逻辑代码全部都丢给了Presenter,结果就是Activity只需要负责UI交互的按钮等代码。</li><li style="padding: 0px; margin: 0px;">对于Presenter可以写单独的单元测试代码，只需要对Presenter提供的方法测试即可</li><li style="padding: 0px; margin: 0px;">如果DataManager变得臃肿庞大了，我们可以分离这些代码到各自的Presenter中去。</li></ul><blockquote style="padding: 3px 25px; margin: 20px 10px; position: relative; font-size: 10pt; line-height: 22px; border-left-width: 3px; border-left-color: #a4daf0; font-family: 'Microsoft YaHei', Verdana, sans-serif, 宋体; background-image: initial; background-color: #f4fdfd;"><p style="padding: 0px; margin: 8px 0px; line-height: 22.5px; letter-spacing: 0.5px; font-size: 12.5px; word-wrap: break-word; word-break: break-all;">What problems do we still have?<br style="padding: 0px; margin: 0px;" /><strong style="padding: 0px; margin: 0px;">现在还有遗留什么问题</strong></p><p style="padding: 0px; margin: 8px 0px; line-height: 22.5px; letter-spacing: 0.5px; font-size: 12.5px; word-wrap: break-word; word-break: break-all;">Having a single data manager can still be an issue when the codebase becomes very large and complex. We haven&#8217;t reached the point where this is a real problem but we are aware that it could happen.</p></blockquote><p style="padding: 0px; margin: 8px 0px; line-height: 22.5px; letter-spacing: 0.5px; font-size: 12.5px; word-wrap: break-word; word-break: break-all; color: #333333; font-family: 'Microsoft YaHei', Verdana, sans-serif, 宋体; background-color: #ffffff;">只有一个DataManager仍旧是一个问题，尤其是当代码项目比较庞大的时候，当然我们还没有到达这个庞大的地步，尽管我们知道这个将来某天会发生。</p><blockquote style="padding: 3px 25px; margin: 20px 10px; position: relative; font-size: 10pt; line-height: 22px; border-left-width: 3px; border-left-color: #a4daf0; font-family: 'Microsoft YaHei', Verdana, sans-serif, 宋体; background-image: initial; background-color: #f4fdfd;"><p style="padding: 0px; margin: 8px 0px; line-height: 22.5px; letter-spacing: 0.5px; font-size: 12.5px; word-wrap: break-word; word-break: break-all;">It&#8217;s important to mention that this is not the perfect architecture. In fact, it&#8217;d be naive to think there is a unique and perfect one that will solve all your problems forever. The Android ecosystem will keep evolving at a fast pace and we have to keep up by exploring, reading and experimenting so that we can find better ways to continue building excellent Android apps.</p></blockquote><p style="padding: 0px; margin: 8px 0px; line-height: 22.5px; letter-spacing: 0.5px; font-size: 12.5px; word-wrap: break-word; word-break: break-all; color: #333333; font-family: 'Microsoft YaHei', Verdana, sans-serif, 宋体; background-color: #ffffff;">如果想有个完美的架构解决你所有问题是不可能的。TMD Android的整个生态圈变化太快，又TM的不标准，就导致我们不断的去探索探索。。。以致于去找到更吊的方法去做Android apps。</p><blockquote style="padding: 3px 25px; margin: 20px 10px; position: relative; font-size: 10pt; line-height: 22px; border-left-width: 3px; border-left-color: #a4daf0; font-family: 'Microsoft YaHei', Verdana, sans-serif, 宋体; background-image: initial; background-color: #f4fdfd;"><p style="padding: 0px; margin: 8px 0px; line-height: 22.5px; letter-spacing: 0.5px; font-size: 12.5px; word-wrap: break-word; word-break: break-all;">I hope you enjoyed this article and you found it useful. If so, don&#8217;t forget to click the recommend button. Also, I&#8217;d love to hear your thoughts about our latest approach.</p></blockquote><p style="padding: 0px; margin: 8px 0px; line-height: 22.5px; letter-spacing: 0.5px; font-size: 12.5px; word-wrap: break-word; word-break: break-all; color: #333333; font-family: 'Microsoft YaHei', Verdana, sans-serif, 宋体; background-color: #ffffff;">希望读了之后对我们的最新解决方案能有些建议想法。</p><p style="padding: 0px; margin: 8px 0px; line-height: 22.5px; letter-spacing: 0.5px; font-size: 12.5px; word-wrap: break-word; word-break: break-all; color: #333333; font-family: 'Microsoft YaHei', Verdana, sans-serif, 宋体; background-color: #ffffff;">【本文翻译的目的是在闲暇时间，研究新技术，用通俗技术语言写给自己看，便于日后方便查阅为目】<br style="padding: 0px; margin: 0px;" />原文：<a href="https://medium.com/ribot-labs/android-application-architecture-8b6e34acda65" style="padding: 0px; margin: 0px; color: #ff8373; outline: 0px; font-size: 12px;">https://medium.com/ribot-labs/android-application-architecture-8b6e34acda65</a><br style="padding: 0px; margin: 0px;" />MVP介绍：<a href="http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2015/0425/2782.html" style="padding: 0px; margin: 0px; color: #ff8373; outline: 0px; font-size: 12px;">http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2015/0425/2782.html</a><br style="padding: 0px; margin: 0px;" />RxAndroid:<a href="https://github.com/ReactiveX/RxAndroid" style="padding: 0px; margin: 0px; color: #ff8373; outline: 0px; font-size: 12px;">https://github.com/ReactiveX/RxAndroid</a><br style="padding: 0px; margin: 0px;" />Eventbus:<a href="https://github.com/greenrobot/EventBus" style="padding: 0px; margin: 0px; color: #ff8373; outline: 0px; font-size: 12px;">https://github.com/greenrobot/EventBus</a></p><img src ="http://www.blogjava.net/paulwong/aggbug/428718.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/paulwong/" target="_blank">paulwong</a> 2015-12-18 13:07 <a href="http://www.blogjava.net/paulwong/archive/2015/12/18/428718.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>六款值得推荐的android（安卓）开源框架简介【转】</title><link>http://www.blogjava.net/paulwong/archive/2014/07/09/415632.html</link><dc:creator>paulwong</dc:creator><author>paulwong</author><pubDate>Wed, 09 Jul 2014 08:56:00 GMT</pubDate><guid>http://www.blogjava.net/paulwong/archive/2014/07/09/415632.html</guid><wfw:comment>http://www.blogjava.net/paulwong/comments/415632.html</wfw:comment><comments>http://www.blogjava.net/paulwong/archive/2014/07/09/415632.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/paulwong/comments/commentRss/415632.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/paulwong/services/trackbacks/415632.html</trackback:ping><description><![CDATA[<span style="color: #0000ff;">1、volley </span><br /><br />项目地址 https://github.com/smanikandan14/Volley-demo<br /> (1)  JSON，图像等的异步下载；<br /> (2)  网络请求的排序（scheduling）<br /> (3)  网络请求的优先级处理<br /> (4)  缓存<br /> (5)  多级别取消请求<br /> (6)  和Activity和生命周期的联动（Activity结束时同时取消所有网络请求）<br /><br /><br /><span style="color: #0000ff;">2、android-async-http  </span><br /><br />项目地址：https://github.com/loopj/android-async-http<br />文档介绍：http://loopj.com/android-async-http/ <br /> (1) 在匿名回调中处理请求结果<br /> (2) 在UI线程外进行http请求<br /> (3) 文件断点上传<br /> (4) 智能重试<br /> (5) 默认gzip压缩<br /> (6) 支持解析成Json格式<br /> (7) 可将Cookies持久化到SharedPreferences<br /><br /><br /><span style="color: #0000ff;">3、Afinal框架</span><br /><br />项目地址：https://github.com/yangfuhai/afinal<br />主要有四大模块：<br /> (1) 数据库模块：android中的orm框架，使用了线程池对sqlite进行操作。<br /> (2) 注解模块：android中的ioc框架，完全注解方式就可以进行UI绑定和事件绑定。无需findViewById和setClickListener等。<br /> (3) 网络模块：通过httpclient进行封装http数据请求，支持ajax方式加载，支持下载、上传文件功能。<br /> (4) 图片缓存模块：通过FinalBitmap，imageview加载bitmap的时候无需考虑bitmap加载过程中出现的oom和android容器快速滑动时候出现的图片错位等现象。<br />             FinalBitmap可以配置线程加载线程数量，缓存大小，缓存路径，加载显示动画等。FinalBitmap的内存管理使用lru算法，<br />             没有使用弱引用（android2.3以后google已经不建议使用弱引用，android2.3后强行回收软引用和弱引用，详情查看android官方文档），<br />             更好的管理bitmap内存。FinalBitmap可以自定义下载器，用来扩展其他协议显示网络图片，比如ftp等。同时可以自定义bitmap显示器，<br />             在imageview显示图片的时候播放动画等（默认是渐变动画显示）。<br /><br /><br /><span style="color: #0000ff;">4、xUtils框架</span><br /><br />项目地址：https://github.com/wyouflf/xUtils<br />主要有四大模块：<br />  (1) 数据库模块：android中的orm框架，一行代码就可以进行增删改查；<br />            支持事务，默认关闭；<br />            可通过注解自定义表名，列名，外键，唯一性约束，NOT NULL约束，CHECK约束等（需要混淆的时候请注解表名和列名）；<br />            支持绑定外键，保存实体时外键关联实体自动保存或更新；<br />            自动加载外键关联实体，支持延时加载；<br />            支持链式表达查询，更直观的查询语义，参考下面的介绍或sample中的例子。          <br />  (2) 注解模块：android中的ioc框架，完全注解方式就可以进行UI，资源和事件绑定；<br />            新的事件绑定方式，使用混淆工具混淆后仍可正常工作；<br />            目前支持常用的20种事件绑定，参见ViewCommonEventListener类和包com.lidroid.xutils.view.annotation.event。<br />  (3) 网络模块：支持同步，异步方式的请求；<br />            支持大文件上传，上传大文件不会oom；<br />            支持GET，POST，PUT，MOVE，COPY，DELETE，HEAD，OPTIONS，TRACE，CONNECT请求；<br />            下载支持301/302重定向，支持设置是否根据Content-Disposition重命名下载的文件；<br />            返回文本内容的请求(默认只启用了GET请求)支持缓存，可设置默认过期时间和针对当前请求的过期时间。            <br />  (4) 图片缓存模块：加载bitmap的时候无需考虑bitmap加载过程中出现的oom和android容器快速滑动时候出现的图片错位等现象；<br />            支持加载网络图片和本地图片；<br />            内存管理使用lru算法，更好的管理bitmap内存；<br />            可配置线程加载线程数量，缓存大小，缓存路径，加载显示动画等...<br /><br /><br /><span style="color: #0000ff;">5、ThinkAndroid</span><br /><br />项目地址：https://github.com/white-cat/ThinkAndroid<br />主要有以下模块：<br />  (1)  MVC模块：实现视图与模型的分离。<br />  (2)  ioc模块：android中的ioc模块，完全注解方式就可以进行UI绑定、res中的资源的读取、以及对象的初始化。 <br />  (3)  数据库模块：android中的orm框架，使用了线程池对sqlite进行操作。  <br />  (4)  http模块：通过httpclient进行封装http数据请求，支持异步及同步方式加载。<br />  (5)  缓存模块：通过简单的配置及设计可以很好的实现缓存，对缓存可以随意的配置<br />  (6)  图片缓存模块：imageview加载图片的时候无需考虑图片加载过程中出现的oom和android容器快速滑动时候出现的图片错位等现象。<br />  (7)  配置器模块：可以对简易的实现配对配置的操作，目前配置文件可以支持Preference、Properties对配置进行存取。<br />  (8)  日志打印模块：可以较快的轻易的是实现日志打印，支持日志打印的扩展，目前支持对sdcard写入本地打印、以及控制台打印<br />  (9)  下载器模块:可以简单的实现多线程下载、后台下载、断点续传、对下载进行控制、如开始、暂停、删除等等。<br />  (10) 网络状态检测模块：当网络状态改变时，对其进行检<br /><br /><br /><span style="color: #0000ff;">6、LoonAndroid </span><br /><br />项目地址：https://github.com/gdpancheng/LoonAndroid<br />主要有以下模块：<br />  (1)  自动注入框架（只需要继承框架内的application既可）<br />  (2)  图片加载框架（多重缓存，自动回收，最大限度保证内存的安全性）<br />  (3)  网络请求模块（继承了基本上现在所有的http请求）<br />  (4)  eventbus（集成一个开源的框架）<br />  (5)  验证框架（集成开源框架）<br />  (6)  json解析（支持解析成集合或者对象）<br />  (7)  数据库（不知道是哪位写的 忘记了）<br />  (8)  多线程断点下载（自动判断是否支持多线程，判断是否是重定向）<br />  (9)  自动更新模块<br />  (10) 一系列工具类<br /><br />其中的 volley ，13 年有研究过，扩展性非常好，个人比较喜欢的风格。其他如 android-async-http、Afinal 也相当不错。<img src ="http://www.blogjava.net/paulwong/aggbug/415632.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/paulwong/" target="_blank">paulwong</a> 2014-07-09 16:56 <a href="http://www.blogjava.net/paulwong/archive/2014/07/09/415632.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Android开源项目分类汇总</title><link>http://www.blogjava.net/paulwong/archive/2014/01/09/408723.html</link><dc:creator>paulwong</dc:creator><author>paulwong</author><pubDate>Thu, 09 Jan 2014 03:03:00 GMT</pubDate><guid>http://www.blogjava.net/paulwong/archive/2014/01/09/408723.html</guid><wfw:comment>http://www.blogjava.net/paulwong/comments/408723.html</wfw:comment><comments>http://www.blogjava.net/paulwong/archive/2014/01/09/408723.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/paulwong/comments/commentRss/408723.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/paulwong/services/trackbacks/408723.html</trackback:ping><description><![CDATA[<p style="margin: 0px; padding: 0px; font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25.1875px; background-color: #efefef;"><span style="font-size: 18px;">分类整理了150个比较好的Android开源项目，已汇总到<a target="_blank" href="https://github.com/Trinea/android-open-project" style="color: #006699;">AndroidOpenProject@Github</a>，欢迎Star和Fork^_*</span></p><p style="margin: 0px; padding: 0px; font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25.1875px; background-color: #efefef;">&nbsp;</p><p style="margin: 0px; padding: 0px; font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25.1875px; background-color: #efefef;"><span style="font-size: 18px;">目前包括：</span></p><p style="margin: 0px; padding: 0px; font-family: Helvetica, Tahoma, Arial, sans-serif; line-height: 25.1875px; background-color: #efefef;"><a href="http://www.trinea.cn/android/android-open-source-projects-view/" style="color: #4183c4; font-family: Helvetica, arial, freesans, clean, sans-serif; font-size: 15px; line-height: 25px;">Android开源项目第一篇&#8212;&#8212;个性化控件(View)篇</a><br style="color: #777777; font-family: Helvetica, arial, freesans, clean, sans-serif; font-size: 15px; line-height: 25px;" /><em style="color: #777777; font-family: Helvetica, arial, freesans, clean, sans-serif; font-size: 15px; line-height: 25px;">&nbsp;&nbsp;包括ListView、ActionBar、Menu、ViewPager、Gallery、GridView、ImageView、ProgressBar等等</em><br style="color: #777777; font-family: Helvetica, arial, freesans, clean, sans-serif; font-size: 15px; line-height: 25px;" /><a href="http://www.trinea.cn/android/android-open-source-projects-dev-lib/" style="color: #4183c4; font-family: Helvetica, arial, freesans, clean, sans-serif; font-size: 15px; line-height: 25px;">Android开源项目第二篇&#8212;&#8212;工具库篇</a><br style="color: #777777; font-family: Helvetica, arial, freesans, clean, sans-serif; font-size: 15px; line-height: 25px;" /><em style="color: #777777; font-family: Helvetica, arial, freesans, clean, sans-serif; font-size: 15px; line-height: 25px;">&nbsp;&nbsp;包括依赖注入框架、图片缓存、网络相关、数据库ORM建模、Android公共库、高版本向低版本兼容库、多媒体等等</em><br style="color: #777777; font-family: Helvetica, arial, freesans, clean, sans-serif; font-size: 15px; line-height: 25px;" /><a href="http://www.trinea.cn/android/android-open-source-projects-excellent-project/" style="color: #4183c4; font-family: Helvetica, arial, freesans, clean, sans-serif; font-size: 15px; line-height: 25px;">Android开源项目第三篇&#8212;&#8212;优秀项目篇</a><br style="color: #777777; font-family: Helvetica, arial, freesans, clean, sans-serif; font-size: 15px; line-height: 25px;" /><em style="color: #777777; font-family: Helvetica, arial, freesans, clean, sans-serif; font-size: 15px; line-height: 25px;">&nbsp;&nbsp;比较有意思的完整的Android项目</em><br style="color: #777777; font-family: Helvetica, arial, freesans, clean, sans-serif; font-size: 15px; line-height: 25px;" /><a href="http://www.trinea.cn/android/android-open-source-projects-dev-tool/" style="color: #4183c4; font-family: Helvetica, arial, freesans, clean, sans-serif; font-size: 15px; line-height: 25px;">Android开源项目第四篇&#8212;&#8212;开发及测试工具篇</a><br style="color: #777777; font-family: Helvetica, arial, freesans, clean, sans-serif; font-size: 15px; line-height: 25px;" /><em style="color: #777777; font-family: Helvetica, arial, freesans, clean, sans-serif; font-size: 15px; line-height: 25px;">&nbsp;&nbsp;包括开发自测、自动化测试、编译打包相关工具</em><br style="color: #777777; font-family: Helvetica, arial, freesans, clean, sans-serif; font-size: 15px; line-height: 25px;" /><a href="http://www.trinea.cn/android/android-open-source-projects-excellent-personal-group/" style="color: #4183c4; font-family: Helvetica, arial, freesans, clean, sans-serif; font-size: 15px; line-height: 25px;">Android开源项目第五篇&#8212;&#8212;优秀个人和团体篇</a><br style="color: #777777; font-family: Helvetica, arial, freesans, clean, sans-serif; font-size: 15px; line-height: 25px;" /><em style="color: #777777; font-family: Helvetica, arial, freesans, clean, sans-serif; font-size: 15px; line-height: 25px;">&nbsp;&nbsp;乐于分享并且有一些很不错的开源项目的个人和组织，包括JakeWharton、Chris Banes、Koushik Dutta等大牛</em></p><img src ="http://www.blogjava.net/paulwong/aggbug/408723.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/paulwong/" target="_blank">paulwong</a> 2014-01-09 11:03 <a href="http://www.blogjava.net/paulwong/archive/2014/01/09/408723.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>移动设备抓包方法</title><link>http://www.blogjava.net/paulwong/archive/2013/12/30/408195.html</link><dc:creator>paulwong</dc:creator><author>paulwong</author><pubDate>Mon, 30 Dec 2013 03:23:00 GMT</pubDate><guid>http://www.blogjava.net/paulwong/archive/2013/12/30/408195.html</guid><wfw:comment>http://www.blogjava.net/paulwong/comments/408195.html</wfw:comment><comments>http://www.blogjava.net/paulwong/archive/2013/12/30/408195.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/paulwong/comments/commentRss/408195.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/paulwong/services/trackbacks/408195.html</trackback:ping><description><![CDATA[<br />ios抓包方法：<a href="http://www.99css.com/archives/1272" target="_blank">http://www.99css.com/archives/1272</a><br /><br /><br />android抓包方法：<a href="http://www.cnblogs.com/xyzlmn/p/3168065.html" target="_blank">http://www.cnblogs.com/xyzlmn/p/3168065.html</a><img src ="http://www.blogjava.net/paulwong/aggbug/408195.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/paulwong/" target="_blank">paulwong</a> 2013-12-30 11:23 <a href="http://www.blogjava.net/paulwong/archive/2013/12/30/408195.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>ANDROID APPS DATA资源</title><link>http://www.blogjava.net/paulwong/archive/2013/06/25/400952.html</link><dc:creator>paulwong</dc:creator><author>paulwong</author><pubDate>Tue, 25 Jun 2013 14:11:00 GMT</pubDate><guid>http://www.blogjava.net/paulwong/archive/2013/06/25/400952.html</guid><wfw:comment>http://www.blogjava.net/paulwong/comments/400952.html</wfw:comment><comments>http://www.blogjava.net/paulwong/archive/2013/06/25/400952.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/paulwong/comments/commentRss/400952.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/paulwong/services/trackbacks/400952.html</trackback:ping><description><![CDATA[<a href="http://stackoverflow.com/questions/10272155/getting-data-from-android-play-store" target="_blank">http://stackoverflow.com/questions/10272155/getting-data-from-android-play-store<br />
</a><br />
<br />
<a href="https://developer.android.com/distribute/googleplay/promote/linking.html" target="_blank">https://developer.android.com/distribute/googleplay/promote/linking.html</a><br />
<br />
<br /><a href="http://www.scriptrr.com/data-scrapping-get-android-google-play-app-info/" target="_blank">http://www.scriptrr.com/data-scrapping-get-android-google-play-app-info/</a><img src ="http://www.blogjava.net/paulwong/aggbug/400952.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/paulwong/" target="_blank">paulwong</a> 2013-06-25 22:11 <a href="http://www.blogjava.net/paulwong/archive/2013/06/25/400952.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>ANDROID APP 与 WEB APP的比较</title><link>http://www.blogjava.net/paulwong/archive/2013/05/26/399764.html</link><dc:creator>paulwong</dc:creator><author>paulwong</author><pubDate>Sat, 25 May 2013 16:59:00 GMT</pubDate><guid>http://www.blogjava.net/paulwong/archive/2013/05/26/399764.html</guid><wfw:comment>http://www.blogjava.net/paulwong/comments/399764.html</wfw:comment><comments>http://www.blogjava.net/paulwong/archive/2013/05/26/399764.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/paulwong/comments/commentRss/399764.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/paulwong/services/trackbacks/399764.html</trackback:ping><description><![CDATA[ANDROID APP 与 WEB APP有相似之处，都是需要在容器内运行，都可以对事件进行响应。
<div><br />
</div>
<div>WEB APP的核心组件是SERVLET，这是对游览器事件进行响应的一个类，事件有GET/POST等事件，不同的URL对应不同的SERVLET。</div>
<div>如果要输出不同的内容，则输出不同的HTML即可。<br />WEB APP的配置文件是WEB.XML，当容器启动时，会从这读取有多少个SERVLET。当浏览器发过来不同的URL请求时，会从中选择相应的SERVLET执行。</div>
<div><br />
</div>
<div>ANDROID APP的核心组件是ACTIVITY，这是一个对系统事件进行响应的一个类，事件有启动事件，菜单点击事件等，点击不同的地方对应不同的ACTIVITY。</div>
<div>如果要输出不同的内容，则输出不同的VIEW即可。<br />ANDROID APP的配置文件是MAINFRE.XML，当应用被部署到系统时，系统会从这读取有多少个ACTIVITY。当不同的事件发生时，系统会会从中选择相应的ACTIVITY执行。</div><img src ="http://www.blogjava.net/paulwong/aggbug/399764.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/paulwong/" target="_blank">paulwong</a> 2013-05-26 00:59 <a href="http://www.blogjava.net/paulwong/archive/2013/05/26/399764.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>演化理解 Android 异步加载图片</title><link>http://www.blogjava.net/paulwong/archive/2012/05/15/378229.html</link><dc:creator>paulwong</dc:creator><author>paulwong</author><pubDate>Tue, 15 May 2012 14:27:00 GMT</pubDate><guid>http://www.blogjava.net/paulwong/archive/2012/05/15/378229.html</guid><wfw:comment>http://www.blogjava.net/paulwong/comments/378229.html</wfw:comment><comments>http://www.blogjava.net/paulwong/archive/2012/05/15/378229.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.blogjava.net/paulwong/comments/commentRss/378229.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/paulwong/services/trackbacks/378229.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 在学习"Android异步加载图像小结"这篇文章时, 发现有些地方没写清楚，我就根据我的理解，把这篇文章的代码重写整理了一遍，下面就是我的整理。下面测试使用的layout文件：简单来说就是 LinearLayout 布局，其下放了5个ImageView。Code highlighting produced by Actipro CodeHighlighter (freeware)http://...&nbsp;&nbsp;<a href='http://www.blogjava.net/paulwong/archive/2012/05/15/378229.html'>阅读全文</a><img src ="http://www.blogjava.net/paulwong/aggbug/378229.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/paulwong/" target="_blank">paulwong</a> 2012-05-15 22:27 <a href="http://www.blogjava.net/paulwong/archive/2012/05/15/378229.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>