原文: http://blog.youkuaiyun.com/u012859646/article/details/16802391
一 . 引子
在Titanium里(本文只以Alloy模式为例),通过对 app/assets/iphone 或 app/assets/android里的相关文件进行修改, 可以修改启动画面. 在iphone下,启动画面是不能少的, 不然你通不过苹果的审核. 网上也有不少讨论, 如何在iphone下去掉启动画面, 苹果官方的文档里有介绍一个trick, 就是用一张和你app首屏一样的画面来做为启动画面, 这样会让的app"看起来"没有启动画面, 感觉上能更快一些. 但是, 这本质上还是存在一个启动画面, 鉴于IOS的这种要求, 本文主要讨论的是Android下的相关事宜.
你可能会问, 在android下,修改app/assets/android/default.png不就可以了, 其它还有什么文章可做. 本文想解决有的几个问题
- 更复杂的画面控制, 如使用动画效果
- 更少的内存占用. 下面会提到, titanium里, 目前的启动画面实现上有些问题, 会带来多余的内存消耗
- 控制启动画面显示的时间
二. titanium安卓启动画面的实现分析
首先说说内存不合理占用的问题. 从理论上来说用Ti开发的项目会比原生的多些内存消耗, 一堆的Proxy对象, 加上对原生对象的一些封装, 会在内存中留下更多的东西来. 所以, 在Ti的开发中对于内存的使用更应该是要很谨慎. 特别是做一些内存消耗较大的app,如图片相关的应用. 一不小心, 很快就会out of memory.
而Ti中对于启动画面的实现是不太"科学"的, 会导致启动的图片一直驻留在内存中. 我们可以通过android SDK中的monitor工具, 使用DUMP HPRO file, 导出app的内存映像, 再用SDK tools里提供的hprof-conv 工具转化成"Eclipse Memory Analyzer"能够读取的格式. 就能够对一个app的内存消耗一探究竟了. 下面一个例子.
图1 . 一个app的内存映象
这里给出内存占用的前三名. 第一是主要是一些系统库和资源相关. 第二名是图片的LRU cache, 根据实现的源代码, 图片的cache最大会为一个app可用内存空间的1/8, 这是代码是写死的, 不过在内存不足或不在前台时, 可能会清空cache.
第三名就是我们需要特别关注的了, 这是一个Bitmap对象, 大小是2.4M, 这个内存占用对一个app来说可是不小. 我们可以从Bitmap的属性看出, 这个图的大小是 640*960, 这个刚好是我测试机的分辨率. 我们可以进一步做, 将这个对象下的bytes,即具体数据全部导出成文件(这是一个raw RGBA格式). 然后用GIMP打开, 这个图正是app的启动画面. 而且这个Bitmap会一直常驻内存, 占用着2M多的空间. 你在Ti的JS代码里也没办法将其释放掉. 而占据的空间和屏幕分辨率直接相关, 如果是更高分辨率的屏幕, 这个内存占用会更大.
我们需要找出其实现方式 . 开始以为启动画面会在源代码里的实现, 翻了半天没看到相关的线索. 用"default.png"做为关键字也找不到结果, 走了不少弯路. 回到问题之初, 考虑, 这个default.png会不会在apk的包里被改名了呢? 解开apk, 果然, 这个文件会被复制成background.png. 于是, 根据这个线索我们在apk中的一个文件中找到了感兴趣的内容. 具体是在
res/values/theme.xml文件中. 文件 内容如下.
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="Theme.Titanium" parent="android:Theme">
<item name="android:windowBackground">@drawable/background</item>
</style>
</resources>
图2 theme.xml
看到这儿, 大概就明白, 原来是用theme来实现的. 这个可以通过生成的AndroidManifest.xml文件来证实(build目录下). 其片段如下.
<activity android:label="@string/appname" android:name=".YourActivity" android:theme="@style/Theme.Titanium">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
图3 AndroidManifest.xml 片段
其中YourActivity就是你的主Activity, 它会一直存在, 所以它的背景,那个占用不少空间的Bitmap会一直存在.
三 具体方案
了解了其实现, 方案就有很多了. 你可以自定义theme, 也可以使用其它theme. 以下用的方案是比较简单的一个. 修改主activity的theme.
3.1 去掉启动画面.
可以将theme直接改成系统自带的透明主题"@android:style/Theme.Translucent", 这样连自己定都不需要了. 你需要修改的是tiapp.xml. 在其<android>下的<
manifest>下的<application>下, 加上你的activity的说明. 修改其theme,如下.
<activity android:label="@string/appname" android:name=".YourActivity" android:theme="@android:style/Theme.Translucent">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
图4 tiapp.xml片段
能过上面的修改,你可去掉android的默认启动画面, 在app的内存中也不会留下任何启动画面bitmap的足迹了. 这里顺便说下, 简单地把default.png去掉, 你的启动画面还是存在的,Ti会给你一张默认的有Ti标志的图.
3.2 自定义启动画面的实现
接下来的事就简单了, 我们直接显示一张图, 然后把窗口close掉就行了. 这样一方面启动画面还是有的, 另外, 显示完以后就释放了空间, 没有多余的内存占用. 在alloy.js中(以alloy的实现为例, 如果用的classic的, 也差不多.)
var splashWin = Ti.UI.createWindow({
fullscreen : true,
navBarHidden : true,
tabBarHidden : true,
backgroundImage : "default.png"
});
splashWin.open();
setTimeout(function(){
splashWin.close();
splashWin = null;
}, 5000);
图5 alloy.js片段
以上的代码其实只是显示一个窗口,然后5秒后关掉. 这样还不能完全控制启动画面的显示时间 , 因为当你的index被创建时这个图片可能就看不到了. 为了让启动画面多显示一会,你可以让你的index延迟open. 一个setTimeout就可以了.
setTimeout(function(){
$.index.open();
}, 2500);
图6 index.js片段
这样, 我们就实现了自定义且节省内存版本的启动画面, 同时可以控制显示的时间 .
3.3 其它扩展
如果要实现一些动画效果fade in之类的, 只要在splashWin上加点代码就行了. 如果要显示多张图, 可以在窗口上放个ImageView, 通images来放. 其它扩展在这个基础上做起来就都很直观了.
四 小结
个人角度来看, 节省内存是我最关注的, 因为一个app能用的内存空间毕竟不多. Ti应该实现一个用户更可控的启动画面的方案,以节省那些不必要的消耗. 其它一些功能,在了解了theme的实现后, 都是很容易理解并优化的.
--EnD--