2016 Google IO - Android application architecture

Android application architecture - MVP, MVC, MVVM…?

No, It’s does not matter. It’s good for you. It’s good for you to scale their application, have it stable, test it well.

Make Application Work Offline

  • Remove Network From Use Flows
    Example: Like Function. when you want to like and you’re seeing a model dialog. User doesn’t need to know about that. See a screenshot and optimize it.

图1,是按照用户使用流程来执行网络请求并更新UI.
图2,没有按照用户使用流程工作,先更新Model,接着更新UI,同时会执行网络请求,请求完后再次更新Model和更新UI.
图3,是图2的进化版,加入了Application Logic. 比如: 当用户点击like, 后台send like to server, 同时用户切换了应用,当用户切换回来,如果出现内存不足,回收了应用,那么application 和 activity都是全新的实例,Application Logic用来记录like前后的状态,保证like的切换前后状态正确。

  • Background Processes
    当网络请求没有按照用户使用流程工作,网络请求后台任务队列很关键,很多时候网络请求需要依照一定顺序。比如:用户点击了like,马上又点击了unlike,那么like和unlike这两条网络就必须按顺序执行保证正确UI更新。

网络后台队列和本地缓存队列最好分开两条队列。网络后台队列都是比较耗时,本地缓存队列相对比较快,一般200-200ms就完成。如果一条队列会网络后台执行会拖慢本地缓存。

例如: User -> Favorites list Page -> Add a favorite -> Go back to Favorites list Page.

For better UX, going back favorites list page After add a favorite should not see a loading page. How to fixed ?

Optimize for Bad Network

Prefetching
  • Adaptive Content Fetching
  • Adaptive Behavior
  • Balance for available storage
  • Alert user before fetching big content(emerging markets)
  • Allow user to configure

Example:

  1. 新闻类应用, 让用户设置每天早上更新新闻的的时间,例如6:30 - 7:30
    用JobScheduler设计定时任务fetching数据,根据当时的网络状态,是否充电,电量容量等属性综合。
  2. 视频类app,有选项让用户先缓存视频。
  3. 地图类app,可以预先下载地图包
  4. Google+:

    4.1 Detect new posts ——> notify user ——> user tap ——> fetch ——> refresh UI (需要3.0s)

    4.2 Detect new posts ——> fetch ——> notify user ——> user tap ——> refresh UI (需要0.3s)
    下面流程的效果比上面优化10陪,用户体验更好。

Data Sever - New in N
  • Finer user control over data
  • No data on the background
    • Unless whitelisted by the user
  • Only in metered networks
1
2
3
4
5
6
7
8
ConnectivityManager connMgr;
if(connMgr.isActiveNetworkMetered()){
switch connMgr.getRestrictBackgroundStatus()){
case RESTRICT_BACKGROUND_STATUS_ENABLED:
case RESTRICT_BACKGROUND_STATUS_WHITELISTED:
case RESTRICT_BACKGROUND_STATUS_DISABLED:
}
}
Data Synchronization
  • Operational Transform
  • Conflict Free Replication
  • Consistency Model

For a example

Client1 , Client2 is conflict. How to fixed? Versioning.

1
2
3
4
5
6
7
8
9
10
11
12
In server:
{
"user": {
"name" : "Yigit",
"last_name": "Boyar",
"fav_color": "blue"
"version": 10
}
}

//HTTP POST
update?fav_color="green"&version = 10

For a example, User Likes a Post

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class Post{
private String text;
private boolean liked;
}

private void likePost(Post post){
post.setLiked(true);
postModel.update(post);
webservice.likePost(post.getId());
}

private void fetchFeed(){
List<Post> posts = webservice.fetchFeed();
postModel.savePosts(posts);
}

But what happens is , next time like, that was another request
and it fetches the list we’re posting at. It just overrides what you have put there. And How to fixed?

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
33
34
public class Post{
private String text;
private boolean liked;
private boolean likedLocal;
}

private void likePost(Post post){
post.setLikedLocal(true);
postModel.update(post);
webservice.likePost(post.getId());
}

private void fetchFeed(){
List<Post> posts = webservice.fetchFeed();
postModel.savePosts(posts);
}

public boolean isLikedAgg(){
if(likedLocal == null){
return liked;
}
return likedLocal;
}

public int getLikeCountAgg(){
if(likedLocal == null || likedLocal == liked){
return likeCount;
}
if(likedLocal){
return likeCount + 1;
}else{
return likeCount - 1;
}
}
Network
  • Design your API for the client
  • Make use of server farms, pass down metadata
  • batch request
  • Use Job Scheduler

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    //bad API
    {
    "user":{
    "name": "Michael"
    "photoUrl": "http://"
    }
    }

    //good API
    {
    "user":{
    "name": "Michael"
    "photoUrl": {
    "width": 300
    "height": 500
    "url":"http://"
    "palette":{}
    }
    }
    }
Summarization
  • Architect for UX
  • Have a real local model
  • Don’t think request - response, think sync
  • De-couple, when it makes sense
  • Act early

更多 Google I/O 2016: Android 演讲视频汇总

Loading comments box needs to over the wall