YOU'VE ENTERED A SIMPLE ANDROIDBLOG, WELCOME.

Develop And Improve。

极简天气开发日记Day06

Things have done

这两天比较有意思,对于Android的内存回收和管理方面有了一些理解,主要是通过动态改变主界面背景这一改动引发的。

实现方法

1.动态改变背景

首先,根据天气API返回的JSON数据中的condition字段判断当前天气来设置相应背景,背景图来自索尼自带天气APP,相当不错的素材,天气代码从官方给的说明来看相当多,但是实用的只有几个,所以直接用switch方便的判断

在工具包下新建了ChangeBackground类,Activity中传入主界面layout和天气代码condition_code

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
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
public class ChangeBackground{

public ChangeBackground(LinearLayout layout,int condition_code){
Time t=new Time(); // or Time t=new Time("GMT+8");
t.setToNow(); // get system time
// int year = t.year;
// int month = t.month+1;
// int date = t.monthDay;
int hour = t.hour;
// Drawable day_clearsky=resources.getDrawable(R.drawable.day_clearsky);

if(hour>=18||hour<=6){
//according to http://www.heweather.com/documents/condition-code
switch (condition_code) {
case 100:
layout.setBackgroundResource(R.drawable.night_clearsky);
break;
case 101:
layout.setBackgroundResource(R.drawable.night_cloudy);
break;
case 102:
case 103:
case 104:
layout.setBackgroundResource(R.drawable.night_partlycloudy);
break;
case 300:
case 301:
case 302:
case 303:
case 304:
case 305:
case 306:
case 307:
case 308:
case 309:
case 310:
case 311:
case 312:
case 313:
layout.setBackgroundResource(R.drawable.night_rain);
break;
case 400:
case 401:
case 402:
case 403:
case 404:
case 405:
case 406:
case 407:
layout.setBackgroundResource(R.drawable.night_snow);
break;
case 500:
case 501:
case 502:
case 503:
case 504:
case 507:
case 508:
layout.setBackgroundResource(R.drawable.day_fog);
break;
default:
layout.setBackgroundResource(R.drawable.night_clearsky);
break;
}
}else {
switch (condition_code) {
case 100:
layout.setBackgroundResource(R.drawable.day_clearsky);
break;
case 101:
layout.setBackgroundResource(R.drawable.day_cloudy);
break;
case 102:
case 103:
case 104:
layout.setBackgroundResource(R.drawable.day_partlycloudy);
break;
case 300:
case 301:
case 302:
case 303:
case 304:
case 305:
case 306:
case 307:
case 308:
case 309:
case 310:
case 311:
case 312:
case 313:
layout.setBackgroundResource(R.drawable.day_rain);
break;
case 400:
case 401:
case 402:
case 403:
case 404:
case 405:
case 406:
case 407:
layout.setBackgroundResource(R.drawable.day_snow);
break;
case 500:
case 501:
case 502:
case 503:
case 504:
case 507:
case 508:
layout.setBackgroundResource(R.drawable.day_fog);
break;
default:
layout.setBackgroundResource(R.drawable.day_clearsky);
break;
}
}
}
}

这里我遇到了一个问题,在模拟器里完美运行,但是真机却无法显示更新的背景,甚至有的机器在进入主界面直接崩溃,一开始我怀疑自己方法写的有问题,换了很多写法,用runOnUiThread之类的方法封装等等但是还是不行,最后怀疑是图片素材的问题,果然在裁剪图片素材分辨率到720*1080后终于可以显示出来了,原来Android对于图片分辨率有着很严的要求~

但是,新的问题又来了

2.万恶的OOM

真机跑通了,却发现还有着很严重的问题,在多次切换城市后出现了OOM,进一步查看程序运行时占用的内存,SONY Z2和SAMSUNG S6 EDGE下一致的达到了120M的可怕数字,后来我又在在线测试平台上发起了测试,还好并不是所有的机型都会消耗如此多的内存

http://pic.yupoo.com/333ddd/FPg5CYFF/EoPfl.png

但是问题还是需要解决的,在参考了别的博客后发现大致分为两种方法,一个是在合适时候回收图片占用内存,也就是重写Activity的onStop和onDestroy方法,添加以下代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
if(layout.getBackground() != null){

Bitmap oldBitmap = ((BitmapDrawable) layout.getBackground()).getBitmap();

layout.setBackground(null);

if(oldBitmap != null){

oldBitmap.recycle();

oldBitmap = null;

}

}

// Other code.

System.gc();

这里的System.gc()在查阅后发现对于Java和Android调用这句话的结局并不一定相同,Java中只是通知JVM程序员希望进行一次GC,但是并不一定会进行,而Android的虚拟机dalvik则会执行回收

在重写onDestroy后真机运行后内存从120M降到了80M,如果再重写onStop方法后内存再次降到40M,果然是图片缓存的锅,当然,onStop重写后会导致失去焦点后再次调用时背景消失,所以只能留onDestroy

另一种方法是通过BitmapFactory.decodeStream方法,创建出一个bitmap,再将其设为ImageView的 source,实际在使用这种方法时候,为了对比效果,我在DDMS中分别测试了这两种方法以及不使用内存优化方法的内存占用,发现比较奇怪的结果

图一:不使用优化
http://pic.yupoo.com/333ddd/FPg5Ddhc/JRQcF.png

图二:重写onDestroy
http://pic.yupoo.com/333ddd/FPg5ywH0/fJbtU.png

图三:BitmapFactory
http://pic.yupoo.com/333ddd/FPg5ywH0/fJbtU.png

这个结果有点意思啊,说好的decodeStream减少内存占用呢

最后,附上优化过后的在线测试结果
http://pic.yupoo.com/333ddd/FPg5ywH0/fJbtU.png

效果还不错,真机多次切换城市也没有出现OOM情况了

Things to do?

有点迷,提不起兴趣