2014年3月2日星期日

[]快速构建Android REST客户端#2 - iMID

本文自动转发自我的博客: http://www.haofengjing.org/?p=1605

快速构建Android REST客户端#2

数据解析和存储

JsonPaser

如果你还在使用Android提供的JsonObject来解析JSON数据,是时候鸟枪换炮了! Android开发中常用的JsonPaser有这么几个:

  • Gson 由Google开发的Json Parser 使用简单,只需要引入一个jar包,相对于Android系统提供的parser,效率有明显的优势
  • Jackson 另一个颇有名气的项目,需要引入很多包相对比较复杂
  • FastJson 阿里主导的开源项目,要求类的每一个属性都具备getter/setter这一点我不能忍

Gson的使用方法异常简单,例如我们要解析以下数据:

1  2  3  4  5  6  7  8  9  10  11  12  13  14  15  16  17  18  19  20  21
String json ="{          "id": 1,          "name": "Dan Cederholm",          "username": "simplebits",          "url": "http://dribbble.com/simplebits",          "avatar_url": "http://dribbble.com/system/users/1/avatars/original/dancederholm-peek.jpg",          "location": "Salem, MA",          "twitter_screen_name": "simplebits",          "drafted_by_player_id": null,          "shots_count": 147,          "draftees_count": 103,          "followers_count": 2027,          "following_count": 354,          "comments_count": 2001,          "comments_received_count": 1509,          "likes_count": 7289,          "likes_received_count": 2624,          "rebounds_count": 15,          "rebounds_received_count": 279,          "created_at": "2009/07/07 21:51:22 -0400"      }"  

需要创建Player类,在该类中声明所有需要解析的属性:

1  2  3  4  5  6  7  8  9  10  11  12  13  14  15  16  17  18  19  20
public class Player {      private long id;      private String name;      private String url;      private String avatar_url;      private String location;      private String twitter_screen_name;      private String drafted_by_player_id;      private int shots_count;      private int draftees_count;      private int followers_count;      private int following_count;      private int comments_count;      private int comments_received_count;      private int likes_count;      private int likes_received_count;      private int rebounds_count;      private int rebounds_received_count;      private String created_at;  }  

使用Gson:

1  2  3  4  5
Gson gson = new Gson();  // Json to object  gson.fromJson(json, Player.class);  // Object to json  String json2 = gson.toJson(Player.class);  

本着"不会偷懒的程序员不是好程序员"这一遵旨,在Driibo的设计中,数据库中仅存储了Json数据,免去了分列的繁琐。缺点是读取数据时需要用Gson重新解析,对效率有一定影响。

ContentProvider

ContentProvider着实让人很头痛,实际上Android文档中提到,如果没有跨进程的需求,或者向其他应用分享数据的需求就不必使用ContentProvider。但ContentProvider为数据库的管理提供了更清晰的接口,并且为了使用CursorLoader,ContentProvider是必须构建的。

更多细节还请参阅 Api Guides – Content Providers

CursorAdapter & CursorLoader

使用CursorLoader是目前在Activity&Fragment中异步读取ContentProvider的最佳方案。CursorLoader还有一个更为强劲的功能,就是在接到数据变更的通知时会重新query一次,这样就保证了Cursor的数据始终与数据库同步。

基于以上两个特性,在列表中使用CursorAdapter填充数据可以有效的简化数据加载和更新的逻辑。


[]快速构建Android REST客户端#1 - iMID

本文自动转发自我的博客: http://www.haofengjing.org/?p=1604

日常使用的各种客户端:新浪微博客户端、Google+、Path、人人等,都属于REST App,如何快速的构建REST客户端也成为了近年来Google IO大会上的热门课题,而我在这方面也投入了近一年的经历(从项目经历来看,简直就是客户端专业户了,泪···)。下面我将以最近开发的Driibo(on github)为例,手把手带大家开发REST客户端。


应用架构


网络通讯

原始的HttpClient开发成本较高,最好使用更为先进的库,比如以下这些:

  • Volley Google于2013 Google io大会上发布的网络通讯库,Google Play,Driibo均基于此库构建
  • AsyncHttpClient SonaType的一个开源库,移植到Android平台需要进行一些定制,
  • Retrofit Square的开源库,于Volley相比Retrofit更专注于网络请求和数据解析,贵在专一。

Volley在提供了高性能网络通讯功能的同时,对网络图片加载也提供了良好的支持,完全可以满足简单REST客户端的需求。

使用Volley

下载Volley源码

1
$ git clone https://android.googlesource.com/platform/frameworks/volley  

由于Volley直接提供了源码,我们必须自己build jar包,在Volley项目根目录下执行

1
$ ant jar  

然后将所得的Jar包导入到工程中。

请求队列

为了统一管理请求,我在RequestManager.java中维持了一个请求队列实例。

1  2  3  4  5  6
public static RequestQueue mRequestQueue = newRequestQueue();  private static RequestQueue newRequestQueue() {      RequestQueue requestQueue = new RequestQueue(openCache(), new BasicNetwork(new HurlStack()));      requestQueue.start();      return requestQueue;  }  

值得注意的是,Volley提供了中断特定请求的方法,利用这个特性可以在Activity关闭时中断该页面的请求,节省有限资源的消耗(节流省电,顶Google)。

1  2  3  4  5  6  7  8  9  10  11
// tag是中断请求所需的token  public static void addRequest(Request request, Object tag) {      if (tag != null) {          request.setTag(tag);      }      mRequestQueue.add(request);  }  public static void cancelAll(Object tag) {      mRequestQueue.cancelAll(tag);  }  

构建图片缓存

由于Volley提供了本地缓存,在Driibo中我只需要实现一个内存缓存:

1  2  3  4  5  6  7  8  9  10  11  12  13  14  15  16  17  18  19  20  21  22  23  24  25  26  27  28  29  30  31  32
package com.refactech.driibo.data;  import com.android.volley.toolbox.ImageLoader;  import com.refactech.driibo.util.ImageUtils;  import android.graphics.Bitmap;  import android.support.v4.util.LruCache;  /**   * Created by Issac on 7/19/13.   */  public class BitmapLruCache extends LruCache<String, Bitmap> implements ImageLoader.ImageCache {      public BitmapLruCache(int maxSize) {          super(maxSize);      }      @Override      protected int sizeOf(String key, Bitmap bitmap) {          return ImageUtils.getBitmapSize(bitmap);      }      @Override      public Bitmap getBitmap(String url) {          return get(url);      }      @Override      public void putBitmap(String url, Bitmap bitmap) {          put(url, bitmap);      }  }  

Driibo使用了一个全局的BitmapLruCache,取内存阈值的1/3作为图片缓存的大小,这样在界面跳转的时不必释放图片资源,更有效的利用内存并防止OOM:

1  2  3  4  5
 // 取运行内存阈值的1/3作为图片缓存      private static final int MEM_CACHE_SIZE = 1024 * 1024 * ((ActivityManager) AppData.getContext()              .getSystemService(Context.ACTIVITY_SERVICE)).getMemoryClass() / 3;      private static DiskBasedCache mDiskCache = (DiskBasedCache) mRequestQueue.getCache();  

图片加载

Volley提供了ImageLoader,NetworkImageView用于处理图片加载。其中NetworkImageView主要用于非滚动视图的图片加载,可直接替换ImageView。 对于列表中的图片加载我在Driibo中是这样处理的:

  1. 创建ImageLoader实例
1  2
 private static ImageLoader mImageLoader = new ImageLoader(mRequestQueue, new BitmapLruCache(              MEM_CACHE_SIZE));  
  1. 在ShotsAdapter中加载图片
1  2  3  4  5  6  7  8  9  10  11  12  13
  @Override      public void bindView(View view, Context context, Cursor cursor) {          Holder holder = getHolder(view);          if (holder.imageRequest != null) {              holder.imageRequest.cancelRequest();          }          ...          Shot shot = Shot.fromCursor(cursor);          holder.imageRequest = RequestManager.loadImage(shot.getImage_url(), RequestManager                  .getImageListener(holder.image, mDefaultImageDrawable, mDefaultImageDrawable));  ...  }  

必须保存请求实例,并在列表滚动时取消上次的请求,以防止列表中图片加载错乱的情况。

Be Careful: 切不可在列表中混用NetworkImageView和ImageLoader,否则会出现图像无法加载的情况,原因未查证。。。


相关演讲


[]消息称乌海军护卫舰叛逃俄罗斯 目前正前往黑海_这是好莱坞大片的情节吗

本文自动转发自我的博客: http://www.haofengjing.org/?p=1602

消息称乌海军护卫舰叛逃俄罗斯 目前正前往黑海 乌海军旗舰Hetman Sahaidachny护卫舰

今日俄罗斯(RT)网站1日援引报道,乌海军旗舰Hetman Sahaidachny护卫舰挂起圣安德烈旗,脱离基辅指挥,叛逃俄罗斯。此前该舰在亚丁湾参加北约军演。

据俄罗斯参议员Igor Morozov表示,乌克兰海军这艘护卫舰已经投向了俄罗斯的怀抱,"目前该舰正在从地中海返回黑海,船员已完成了乌克兰武装力量指挥官亚努科维奇的命令。"

叛逃事件发生在周五乌克兰海军指挥官辞职之后,新政府代总统图尔奇诺夫任命了新的海军统帅。

据基辅时报报道,乌克兰新总理亚采纽克要求土耳其官方不要放该护卫舰通过博斯普鲁斯海峡,称船长违背了基辅政府发出的指令。


2014年3月1日星期六

[]Dropbox独树一帜的十大利器

本文自动转发自我的博客: http://www.haofengjing.org/?p=1600
DropBox虽然国外面临着有亚马逊、微软OneDrive、Google drive等强大竞争对手,国内的新浪微盘、360云盘、百度云、115网盘、金山云、酷盘、华为网盘等,也让国内云存储市场也异常火热。此番Dropbox入华为什么能这么火,到底有什么过人之处,几天小编结合自身的感受,从产品体验的角度去简单分析总结一下。 1.非常稳定。程序稳定不出现错误和崩溃。速度稳定,连接服务器一直很稳定。反观国内的一些网盘客户端经常莫名其妙的崩溃,用户体验非常不好。 2.安全保障。国内的网盘同步工具很容易因为运营不善挂掉,比如说前几年的迅雷5G网盘。而Dropbox从08年开始创建,运营一直良好,公司实力雄厚,最近估值更是达到了100亿美元,用户完全不用担心突然挂掉。 3.多平台云同步。Dropbox是最早支持也是覆盖最全面各大平台的,而其他的软件做不到。我一般在家里和公司使用,偶尔手机使用。 4.版本控制。应该是dropbox很大的一个特色,免费用户可以回溯30天的版本。非常贴心的功能,尤其是对于存储重要工作文档的用户。 5.增量同步。当用户Dropbox文件夹中的文件发生变化后,Dropbox只上传改变的文件部分,并实施同步。所以dropbox的同步速度很棒,对了解svn的用户来讲这个功能很贴心。 6.简洁无干扰。Dropbox安装好之后就静静在后台处理,不会干扰用户的任何工作,老老实实办事儿,很低调,而不像国内其他软件老是主动弹出干扰。 7.外链分享。非常方便的分享规则,只需要右键点击文件和文件夹就可以任意分享。一分部用户省去了建立FTP服务器的麻烦,细心的用户甚至可以利用这一功能搭建自己的静态网站。 8.协同工作。可以设定一个文件夹供多人一起协作,我一直用这个功能和同事共享文档和同步工作内容。 9.丰富的API。利用Dropbox提供的API有很多强大的功能,比如把重要的Gmail附件自动备份到Dropbox,比如备份Facebook的加星照片,比如自动定期备份网站源文件到Dropbox。 10.土豪的慷慨。用户可以通过各种方法把免费空间提升至20G。 通过Dropbox独树一帜的十大利器_DOIT.com.cn.