如何abaqus查看节点总数Android App的方法总数

博客访问: 302528
博文数量: 67
博客积分: 1175
博客等级: 少尉
技术积分: 1200
注册时间:
IT168企业级官微
微信号:IT168qiye
系统架构师大会
微信号:SACC2013
分类: Android平台
使用android自动化测试工具monkeyrunner启动应用时,需要填写被测程序的包名和启动的Activity,以下有两种查看应用包名package和入口activity名称的方法:
方法一:使用aapt & &//aapt是sdk自带的一个工具,在sdk\builds-tools\目录下
1.以ES文件浏览器为例,命令行中切换到aapt.exe目录执行:aapt dump badging
E:\apk\es3.apk
2.运行后的结果中以下两行分别是应用包名package和入口activity名称
package: name=’com.estrongs.android.pop’
launchable-activity: name=’com.estrongs.android.pop.view.FileExplorerActivity’
注:在android sdk目录搜索可以找到aapt.exe,如果没有可以下载apktool。
方法二:查看AndroidManifest.xml
1.使用apktool反编译app:apktool.bat d es3.apk E:\apk\es
2.打开AndroidManifest.xml
manifest节点的package属性值是应用的包名:&manifest
package=”com.estrongs.android.pop”&
查找android.intent.action.MAIN和android.intent.category.LAUNCHER对应的activity,该activity对应的android:name属性既是入口activity名称,如下:
&activity android:theme=”@*android & &tyle/Theme.NoTitleBar”
android:label=”@string/app_name”
android:name=”com.estrongs.android.pop.view.FileExplorerActivity”&
&intent-filter&
&action android:name=”android.intent.action.MAIN” /&
&category android:name=”android.intent.category.LAUNCHER” /&
&/intent-filter&
&/activity&
android.intent.action.MAIN决定应用程序最先启动的Activity
android.intent.category.LAUNCHER决定应用程序是否显示在程序列表里
阅读(40336) | 评论(0) | 转发(1) |
相关热门文章
给主人留下些什么吧!~~
请登录后评论。4272人阅读
【Android学习】(35)
我 们知道,android程序内存一般限制在16M,当然也有24M的,而android程序内存被分为2部分:native和dalvik,dalvik 就是我们平常说的java堆,我们创建的对象是在这里面分配的,而bitmap是直接在native上分配的,对于内存的限制是&native+dalvik&不能超过最大限制。
1.单个app 内存限制大小
ActivityManager&activityManager&=&(ActivityManager)&context.getSystemService(Context.ACTIVITY_SERVICE);&&&&&&&&&&activityManager.getMemoryClass();&&
2.&/proc/meminfo& &系统内存信息文件【整个系统的内存情况】
3.ActivityManager.MemoryInfo【整个系统】
availMem & & & & 剩余内存
threshold & & & & 临界值 【超过次值就开始杀死后台服务和没有关联的进程】
lowMemory & & 低内存状态
4.android.os.Debug
getNativeHeapFreeSize()
getNativeHeapAllocatedSize()
getNativeHeapSize()
5.android.os.Debug.MemoryInfo【当前进程的内存情况】
totalMemory()
freeMemory()
maxMemory()
7.VMRuntime
getTargetHeapUtilization()
getMinimumHeapSize()
getExternalBytesAllocated() &&应该是外部分配的内存Native内存
系统GC释放的内存提示
一般在LOG里面显示如下:
09-28 17:16:37.543: DEBUG/dalvikvm(21466): GC_EXTERNAL_ALLOC freed 390 objects /
45656 bytes in 50ms
09-28 17:16:40.513: DEBUG/dalvikvm(3267): GC_EXPLICIT freed 4501 objects / 251624 bytes in 67ms
:Free的内存是VM中java使用的内存
即 heap mem
:Free的内存是VM中通过JNI的Native类中的malloc分配的内存
例如 Bitmap 和一些 Cursor
在Davilk中,给一个程序分配的内存根据机型厂商的不同,而不同,现在的大部分的是32M了,而在VM内部会把这些内存分成java使用的内存和 Native使用的内存,它们之间是不能共享的,就是说当你的Native内存用完了,现在Java又有空闲的内存,这时Native会重新像VM申请,而不是直接使用java的。
例如上边的例子
explicit K
external 2K
如果这时需要创建一个2M的
Native现有内存=k,因此他就会向Vm申请内存,虽然java空闲的内存是
52&2048,但这部分内存Native是不能使用。
但是你现在去申请2M的Native内存,VM会告诉你无法分配的,因为现在已使用的内存已经接近峰值了32M(23=32923 ),所以现在就会成force close 报OOM。
所以现在我们要检查我们的native内存的使用情况来避免OOM。
三、通过Android系统提供的Runtime类,执行adb 命令(top,procrank,ps...等命令)查询
内存耗用:VSS/RSS/PSS/USS
? VSS - Virtual Set Size 虚拟耗用内存(包含共享库占用的内存)
? RSS - Resident Set Size 实际使用物理内存(包含共享库占用的内存)
? PSS - Proportional Set Size 实际使用的物理内存(比例分配共享库占用的内存)
? USS - Unique Set Size 进程独自占用的物理内存(不包含共享库占用的内存)
一般来说内存占用大小有如下规律:VSS &= RSS &= PSS &= USS
查看每个进程及其内存状况
private void getRunningAppProcessInfo() {
mActivityManager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
// 获得系统里正在运行的所有进程
List&RunningAppProcessInfo& runningAppProcessesList = mActivityManager
.getRunningAppProcesses();
for (RunningAppProcessInfo runningAppProcessInfo : runningAppProcessesList) {
// 进程ID号
int pid = runningAppProcessInfo.
int uid = runningAppProcessInfo.
String processName = runningAppProcessInfo.processN
// 占用的内存
int[] pids = new int[] { pid };
Debug.MemoryInfo[] memoryInfo = mActivityManager
.getProcessMemoryInfo(pids);
int memorySize = memoryInfo[0].dalvikPrivateD
st = st + &processName=& + processName + &,pid=& + pid + &,uid=&
+ uid + &,memorySize=& + memorySize + &kb& + &\n&;
System.out.println(&processName=& + processName + &,pid=& + pid
+ &,uid=& + uid + &,memorySize=& + memorySize + &kb&);
}查看总内存:
public long getmem_TOLAL() {
// /proc/meminfo读出的内核信息进行解释
String path = &/proc/meminfo&;
String content =
BufferedReader br =
br = new BufferedReader(new FileReader(path), 8);
if ((line = br.readLine()) != null) {
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (br != null) {
br.close();
} catch (IOException e) {
e.printStackTrace();
// beginIndex
int begin = content.indexOf(':');
// endIndex
int end = content.indexOf('k');
// 截取字符串信息
content = content.substring(begin + 1, end).trim();
mTotal = Integer.parseInt(content);
查看内存信息(该api较新):
public long getmem_UNUSED(Context mContext) {
long MEM_UNUSED;
// 得到ActivityManager
ActivityManager am = (ActivityManager) mContext
.getSystemService(Context.ACTIVITY_SERVICE);
// 创建ActivityManager.MemoryInfo对象
ActivityManager.MemoryInfo mi = new ActivityManager.MemoryInfo();
am.getMemoryInfo(mi);
textView3.setText(&totalMen:& + mi.totalMem / 1024 + &\n&
+ &threshold:& + mi.threshold / 1024 + &\n& + &availMem:&
+ mi.availMem / 1024 + &\n&);
// 取得剩余的内存空间
MEM_UNUSED = mi.availMem / 1024;
return MEM_UNUSED;
查看app内存:
ActivityManager manager = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
int i=manager.getMemoryClass();
textView.setText(&\n&+&app:&+i);
像Linux这种现代操作系统的内存使用是很复杂的,因此很难准确的知道你的应用程序使用了好多内存。
查看内存使用的方式有很多种,但是各个方式查看到的结果可能会有微略不同。
方式一,Running
通过手机上Running services的Activity查看,可以通过Setting-&Applications-&Running services进。
关于Running services的详细内容请参考《》
方式二,使用ActivityManager的(&outInfo)
ActivityManager.getMemoryInfo()主要是用于得到当前系统剩余内存的及判断是否处于低内存运行。
&&&&private void displayBriefMemory() { &&&
&&&&&&&&final ActivityManager activityManager = (ActivityManager)
getSystemService(ACTIVITY_SERVICE); &&&
&&&&&&&&ActivityManager.MemoryInfo info = new ActivityManager.MemoryInfo(); &&
&&&&&&&&activityManager.getMemoryInfo(info); &&&
&&&&&&&&Log.i(tag,&系统剩余内存:&+(info.availMem&&&
10)+&k&); &&
&&&&&&&&Log.i(tag,&系统是否处于低内存运行:&+info.lowMemory);
&&&&&&&&Log.i(tag,&当系统剩余内存低于&+info.threshold+&时就看成低内存运行&);
ActivityManager.getMemoryInfo()是用ActivityManager.MemoryInfo返回结果,而不是Debug.MemoryInfo,他们不一样的。
ActivityManager.MemoryInfo只有三个Field:
availMem:表示系统剩余内存
lowMemory:它是boolean值,表示系统是否处于低内存运行
hreshold:它表示当系统剩余内存低于好多时就看成低内存运行
方式三,在代码中使用Debug的getMemoryInfo(Debug.MemoryInfo
memoryInfo)或ActivityManager的MemoryInfo[] getProcessMemoryInfo(int[]
该方式得到的MemoryInfo所描述的内存使用情况比较详细.数据的单位是KB.
MemoryInfo的Field如下
dalvikPrivateDirty:&The
private dirty pages used by dalvik。
dalvikPss&:The proportional
set size for dalvik.
dalvikSharedDirty&:The
shared dirty pages used by dalvik.
nativePrivateDirty&:The private dirty
pages used by the&native heap.
nativePss&:The proportional set size for
the native heap.
nativeSharedDirty&:The
shared dirty pages used by the&native heap.
otherPrivateDirty&:The private dirty pages
used by everything else.
otherPss&:The proportional
set size for everything else.
otherSharedDirty&:The
shared dirty pages used by everything else.
Android和Linux一样有大量内存在进程之间进程共享。某个进程准确的使用好多内存实际上是很难统计的。
因为有paging out to disk(换页),所以如果你把所有映射到进程的内存相加,它可能大于你的内存的实际物理大小。
dalvik:是指dalvik所使用的内存。
native:是被native堆使用的内存。应该指使用C\C++在堆上分配的内存。
other:是指除dalvik和native使用的内存。但是具体是指什么呢?至少包括在C\C++分配的非堆内存,比如分配在栈上的内存。puzlle!
private:是指私有的。非共享的。
share:是指共享的内存。
PSS:实际使用的物理内存(比例分配共享库占用的内存)
Pss:它是把共享内存根据一定比例分摊到共享它的各个进程来计算所得到进程使用内存。网上又说是比例分配共享库占用的内存,那么至于这里的共享是否只是库的共享,还是不清楚。
&PrivateDirty:它是指非共享的,又不能换页出去(can
not be paged to disk&)的内存的大小。比如Linux为了提高分配内存速度而缓冲的小对象,即使你的进程结束,该内存也不会释放掉,它只是又重新回到缓冲中而已。
SharedDirty:参照PrivateDirty我认为它应该是指共享的,又不能换页出去(can
not be paged to disk&)的内存的大小。比如Linux为了提高分配内存速度而缓冲的小对象,即使所有共享它的进程结束,该内存也不会释放掉,它只是又重新回到缓冲中而已。
具体代码请参考实例1
注意1:MemoryInfo所描述的内存使用情况都可以通过命令adb
shell&&dumpsys meminfo %curProcessName%&&得到。
注意2:如果想在代码中同时得到多个进程的内存使用或非本进程的内存使用情况请使用ActivityManager的MemoryInfo[]
getProcessMemoryInfo(int[] pids),
否则Debug的getMemoryInfo(Debug.MemoryInfo
memoryInfo)就可以了。
注意3:可以通过ActivityManager的&&a
href=&/reference/android/app/ActivityManager.RunningAppProcessInfo.html& rel=&nofollow& style=&color: rgb(207, 121, 28); text-decoration:&&ActivityManager.RunningAppProcessInfo&&()得到当前所有运行的进程信息。
中就有进程的id,名字以及该进程包括的所有apk包名列表等。
注意4:数据的单位是KB.
方式4、使用Debug的getNativeHeapSize
(),getNativeHeapAllocatedSize (),getNativeHeapFreeSize ()方法。
该方式只能得到Native堆的内存大概情况,数据单位为字节。
Returns the amount
of allocated memory in the native heap.
返回的是当前进程navtive堆中已使用的内存大小
static long&()
Returns the amount of free memory in the native heap.
返回的是当前进程navtive堆中已经剩余的内存大小
static long&()
Returns the size of the native heap.
返回的是当前进程navtive堆本身总的内存大小
示例代码:
&&&&&&&&&&Log.i(tag,&NativeHeapSizeTotal:&+(Debug.getNativeHeapSize()&&10));
&&&&&&&&&&Log.i(tag,&NativeAllocatedHeapSize:&+(Debug.getNativeHeapAllocatedSize()&&10));
&&&&&&&&&&Log.i(tag,&NativeAllocatedFree:&+(Debug.getNativeHeapFreeSize()&&10));
注意:DEBUG中居然没有与上面相对应的关于dalvik的函数。
方式五、使用dumpsys
meminfo命令。
我们可以在adb shell 中运行dumpsys
meminfo命令来得到进程的内存信息。在该命令的后面要加上进程的名字,以确定是哪个进程。
shell dumpsys meminfo&com.teleca.robin.test&&将得到com.teleca.robin.test进程使用的内存的信息:&
Applications Memory Usage (kB):
** MEMINFO in pid 3407 [com.teleca.robin.test] **
&&&&&&&&&&&&&&&&&&&&native &&dalvik &&&other &&&total
&&&&&&&&&&&&size:
&&&&3456 &&&&3139 &&&&&N/A &&&&6595
&&&&&&&allocated:
&&&&3432 &&&&2823 &&&&&N/A &&&&6255
&&&&&&&&&&&&free:
&&&&&&23 &&&&&316 &&&&&N/A &&&&&339
&&&&&&&&&&&(Pss):
&&&&&724 &&&&1101 &&&&1070 &&&&2895
&&(shared dirty):
&&&&1584 &&&&4540 &&&&1668 &&&&7792
&&&&(priv dirty):
&&&&&644 &&&&&608 &&&&&688 &&&&1940
&&&&&&&&&&&Views: &&&&&&&0 &&&&&&&ViewRoots: &&&&&&&0
&&&&&AppContexts: &&&&&&&0 &&&&&&Activities: &&&&&&&0
&&&&&&&&&&Assets: &&&&&&&3 &&&AssetManagers: &&&&&&&3
&&&Local Binders: &&&&&&&5 &&&Proxy Binders: &&&&&&11
Death Recipients: &&&&&&&0
&OpenSSL Sockets: &&&&&&&0
&&&&&&&&&&&&heap: &&&&&&&0 &&&&&&memoryUsed: &&&&&&&0
pageCacheOverflo: &&&&&&&0 &largestMemAlloc: &&&&&&&0
&Asset Allocations
&&&&zip:/data/app/com.teleca.robin.test-1.apk:/resources.arsc: 1K
&&size& 表示的是总内存大小(kb)。, &allocated& 表示的是已使用了的内存大小(kb),, &free&表示的是剩余的内存大小(kb), 更多的可以参照方式三和方式四中的描述
现在已经有了自动提取汇总dumpsys
meminfo信息的工具,具体请参照《》及其系列文章。
方式六、使用&&adb
shell procrank&命令
如果你想查看所有进程的内存使用情况,可以使用&adb
shell procrank&命令。命令返回将如下:
&&PID &&&&&Vss &&&&&Rss &&&&&Pss &&&&&Uss &cmdline
&&188 &&75832K &&51628K &&24824K &&19028K &system_server
&&308 &&50676K &&26476K &&&9839K &&&6844K &system_server
&2834 &&35896K &&31892K &&&9201K &&&6740K &com.sec.android.app.twlauncher
&&265 &&28536K &&28532K &&&7985K &&&5824K &com.android.phone
&&100 &&29052K &&29048K &&&7299K &&&4984K &zygote
&&258 &&27128K &&27124K &&&7067K &&&5248K &com.swype.android.inputmethod
&&270 &&25820K &&25816K &&&6752K &&&5420K &com.android.kineto
&1253 &&27004K &&27000K &&&6489K &&&4880K &com.google.android.voicesearch
&2898 &&26620K &&26616K &&&6204K &&&3408K &com.google.android.apps.maps:FriendService
&&297 &&26180K &&26176K &&&5886K &&&4548K &com.google.process.gapps
&3157 &&24140K &&24136K &&&5191K &&&4272K &android.process.acore
&2854 &&23304K &&23300K &&&4067K &&&2788K &com.android.vending
&3604 &&22844K &&22840K &&&4036K &&&3060K &com.wssyncmldm
&&592 &&23372K &&23368K &&&3987K &&&2812K &com.google.android.googlequicksearchbox
&3000 &&22768K &&22764K &&&3844K &&&2724K &com.tmobile.selfhelp
&&101 &&&8128K &&&8124K &&&3649K &&&2996K &/system/bin/mediaserver
&3473 &&21792K &&21784K &&&3103K &&&2164K &com.android.providers.calendar
&3407 &&22092K &&22088K &&&2982K &&&1980K &com.teleca.robin.test
&2840 &&21380K &&21376K &&&2953K &&&1996K &com.sec.android.app.controlpanel
......................................................................................................................
关于VSS,RSS,PSS,USS的意义请参考《》
注意1:这里的PSS和方式四PSS的total并不一致,有细微的差别。为什么呢?这是因为procrank
命令和meminfo命令使用的内核机制不太一样,所以结果会有细微差别
注意2:这里的Uss&和方式四的Priv
Dirtyd的total几乎相等.他们似乎表示的是同一个意义。但是现在得到的关于它们的意义的解释却不太相同。难道这里Private的都是dirty(这里指不能换页)?&Puzzle!
方式七、使用&adb
shell cat /proc/meminfo& 命令。
该方式只能得出系统整个内存的大概使用情况。
MemTotal: &&&&&&&&395144 kB&
MemFree: &&&&&&&&&184936 kB&
Buffers: &&&&&&&&&&&&880 kB&
Cached: &&&&&&&&&&&84104 kB&
SwapCached: &&&&&&&&&&&0 kB&
................................................................................................
MemTotal&:可供系统和用户使用的总内存大小&(它比实际的物理内存要小,因为还有些内存要用于radio,
DMA buffers, 等).&
MemFree:剩余的可用内存大小。这里该值比较大,实际上一般Android
system 的该值通常都很小,因为我们尽量让进程都保持运行,这样会耗掉大量内存。
Cached:&这个是系统用于文件缓冲等的内存.
通常systems需要20MB 以避免。当内存紧张时,the Android out of memory killer将杀死一些background进程,以避免他们消耗过多的cached
RAM ,当然如果下次再用到他们,就需要paging. 那么是说background进程的内存包含在该项中吗?
方式八,使用“adb shell ps -x”命令
该方式主要得到的是内存信息是VSIZE 和RSS。
USER &&&&PID &&PPID &VSIZE &RSS &&&&WCHAN &&&PC
&&&&&&&&NAME
.........................省略.................................
app_70 &&&3407 &100 &&56 ffffffff afd0eb18 S com.teleca.robin.test
(u:55, s:12)
app_7 &&&&3473 &100 &&84 ffffffff afd0eb18 S com.android.providers.calendar (u:16, s:8)
radio &&&&3487 &100 &&40 ffffffff afd0eb18 S com.osp.app.signin (u:11, s:12)
system &&&3511 &100 &&24 ffffffff afd0eb18 S com.android.settings (u:11, s:4)
app_15 &&&3546 &100 &&00 ffffffff afd0eb18 S com.sec.android.providers.drm (u:15, s:6)
app_59 &&&3604 &100 &&56 ffffffff afd0eb18 S com.wssyncmldm (u:231, s:54)
root &&&&&4528 &2 &&&&0 &&&&&0 &&&&c000000 S flush-138:13
(u:0, s:0)
root &&&&&4701 &152 &&676 &&&336 &&c00a68c8 afd0e7cc S /system/bin/sh (u:0,
root &&&&&4702 &4701 &820 &&&340 && afd0d8bc R ps (u:0, s:5)
VSZIE:意义暂时不明。
VSS:请参考《》
注意1:由于RSS的价值不是很大,所以一般不用。
注意2:通过该命令提取RSS,已经有了工具,具体参照《》及其系列。
&&&&int cnt=0;
&&&&final static int kBufferMinSize=1000;
&&&&final static int kBufferMaxSize=2000;
&&&&StringBuffer strBuffer=new StringBuffer(kBufferMinSize);
&&&&StringBuffer strBuffer2=new StringBuffer(kBufferMinSize);
&&&&StringBuffer strBuffer3=new StringBuffer(kBufferMinSize);
&&&&StringBuffer strBufferNativePss=new StringBuffer(kBufferMinSize);
&&&&StringBuffer strBufferDalvikPss=new StringBuffer(kBufferMinSize);
&&&&StringBuffer strBufferOtherPss=new StringBuffer(kBufferMinSize);
&&&&Debug.MemoryInfo memoryInfo=new Debug.MemoryInfo();
&&&&final static String tag=&robin&;
&&&&void printMemory()
&&&&long totalMemory=Runtime.getRuntime().totalMemory();
&&&&&&&&&&long freeMemory=Runtime.getRuntime().freeMemory();
&&&&&&&&&&long usedMemory=(totalMemory-freeMemory)&&10;
&&&&&&&&&&totalMemory=totalMemory&&10;
&&&&&&&&&&freeMemory=freeMemory&&10;
&&&&&&&&&&if(strBuffer.length()&kBufferMaxSize)
&&&&&&&&&&{
&&&&&&&&&&&&&&&&strBuffer.delete(0,strBuffer.length());
&&&&&&&&&&&&&&&&strBuffer2.delete(0,strBuffer2.length());
&&&&&&&&&&&&&&&&strBuffer3.delete(0,strBuffer3.length());
&&&&&&&&&&&&&&&&strBufferNativePss.delete(0,strBufferNativePss.length());
&&&&&&&&&&&&&&&&strBufferDalvikPss.delete(0,strBufferDalvikPss.length());
&&&&&&&&&&}
&&&&&&&&&&strBuffer.append(usedMemory+&,&);
&&&&&&&&&&strBuffer2.append(totalMemory+&,&);
&&&&&&&&&&strBuffer3.append((Debug.getNativeHeapSize()&&10)+&,&);
&&&&&&&&&&Debug.getMemoryInfo(memoryInfo);
&&&&&&&&&&strBufferNativePss.append((memoryInfo.nativePss)+&,&);
&&&&&&&&&&strBufferDalvikPss.append((memoryInfo.dalvikPss)+&,&);
&&&&&&&&&&if(cnt++==0)
&&&&&&&&&&{
&&&&&&&&&&&&&&&&Log.i(tag,&usedMemory:&+strBuffer.toString());
&&&&&&&&&&&&&&&&Log.i(tag,&totalMemory:&+strBuffer2.toString());
&&&&&&&&&&&&&&&&Log.i(tag,&NativeHeapSize:&+strBuffer3.toString());
&&&&&&&&&&&&&&&&Log.i(tag,&Native PSS:&+strBufferNativePss.toString());
&&&&&&&&&&&&&&&&Log.i(tag,&Dalvik PSS:&+strBufferDalvikPss.toString());
&&&&&&&&&&} &&&
注意,对于输出的内存信息日志,我们稍作编辑就可以用于在excel产中图表,比便更直观的进行分析。
&&相关文章推荐
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:90950次
积分:1822
积分:1822
排名:千里之外
原创:81篇
评论:23条
(1)(1)(1)(3)(6)(4)(1)(1)(3)(1)(2)(1)(4)(5)(1)(2)(3)(4)(9)(2)(4)(4)(7)(7)(3)(1)(1)匿名用户不能发表回复!|
每天回帖即可获得10分可用分!小技巧:
你还可以输入10000个字符
(Ctrl+Enter)
请遵守CSDN,不得违反国家法律法规。
转载文章请注明出自“CSDN(www.csdn.net)”。如是商业用途请联系原作者。Building Apps with Over 65K Methods(解决APP引用方法总数超过65536)
来源:博客园
本文翻译自/intl/zh-cn/tools/building/multidex.html#about。主要介绍当我们Android App中函数超过65536时构建失败的原因及解决办法!
-------------------------分割线--------------------------------------------------
随着android platform的持续增长,android apps的大小也在增长。当你的应用程序包括其所引用的库达到一定的规模,你将遇到构建错误,这表明你的程序已经达到到了android 应用框架的限制。在早期的构建系统会报告如下错误信息:

Conversion to Dalvik format failed:
Unable to execute dex: method ID not in [0, 0xffff]: 65536

最近版本的构建系统会显示不同的错误,这是同一个问题的提示信息:

trouble writing output:
Too many field references: 131000; max is 65536.
You may try using --multi-dex option.

这两种错误情况显示了一个共同的数字:65536。这个数字代表的是单个Dalvik可执行的(DEX)字节码文件的可以调用方法总数。如果你已经创建了android应用,并且收到了这个错误,那么恭喜你,你的代码太多了!本文档将介绍如何突破这个限制,继续构建你的app。
 About the 65K Reference Limit
APK文件包含用于运行你的应用程序编译代码形式的可执行字节码文件( Executable DEX)。Dalvik可执行的规范限制了在一个单一的DEX文件中引用到包括Android框架方法,库方法等方法的总数为65,536。想要突破此限制,您需要配置您的应用程序的构建过程,生成多个DEX文件,被称为multidex配置。
 Multidex support prior to Android 5.0
Android5.0之前的版本使用的Dalvik运行时执行应用程序代码。默认情况下,Dalvik的限制的应用程序,每APK一个classes.dex字节码文件。为了解决这个限制,可以使用,成为您的应用程序的主DEX文件的一部分,然后设法获得了额外的DEX文件和它们所包含的代码。
 Multidex support for Android 5.0 and higher
Android5.0以及更高版本使用的是ART runtime,可以支持原生从APK文件中加载多个dex文件。ART进行预编译的应用程序安装时它会扫描类(.. N).dex文件,并通过Android设备编译成一个单一的.oat文件执行。对于在Android5.0运行时的详细信息,请参考 。
 Avoiding the 65K Limit
在配置您的应用程序能够使用65K+方法个数之前,您应该采取措施来减少您的应用程序代码调用引用的总数,包括您的应用程序代码中的方法和库定义的方法。以下策略可以帮助您避免超过DEX参考限值:
看您的应用程序的直接和间接性依赖:确保在你的app中包含的library的用途要和其代码量匹配。一个比较常见的反例就是包含巨大的代码量,用途却很小。减少你的app的library依赖往往可以帮你避免dex reference限制。
删除未使用的代码混淆(code with ProGuard):配置可以运行你的app的ProGuard并确保可以在正式构建程序的时候为你的程序瘦身。 
使用这些技术可以帮助你避免更改程序构建配置时需要启用更多的方法引用。对于宽带成本很高的市场来说,这些步骤很重要。
 Configuring Your App for Multidex with Gradle
Android插件Gradle 可Android SDK Build Tools 21.1和更高版本中支持multidex作为构建配置的一部分。在为你app配置multidex之前,请先使用SDK Manager将Android SDKBuild Tools 和Android Support Repository更新到最新版本。
在你的app中使用multidex配置之前,需要对你的程序开发做一些相应修改。你需要执行以下步骤:
1.修改你的 Gradle构建配置以启用multidex
2.修改你的AndroidManifest 去引用 class。
修改build.gradle配置去引用support library和启用multidex输出,如以下所示build.gradle片段
 

android {
compileSdkVersion 21
buildToolsVersion "21.1.0"

defaultConfig {
minSdkVersion 14
targetSdkVersion 21
...

// Enabling multidex support.
multiDexEnabled true
...
}

dependencies {
compile 'com.android.support:multidex:1.0.0'
}

 
Note:你可以在build.gradle文件的defaultConfig,buildType,或者productFlavor中设置multiDexEnable。
在你的AndroidManifest的application元素中添加 class:

&?xml version="1.0" encoding="utf-8"?&
&manifest xmlns:android="/apk/res/android"
package="com.example.android.multidex.myapplication"&
&application
android:name="android.support.multidex.MultiDexApplication"&
&/application&
&/manifest&

当这些配置添加到一个应用程序中,Android构建工具会构建一个dex(classes.dex),根据需要会继续构建(classes2.dex, classes3.dex)。然后构建系统将他们打包进同一个apk中。
Note: 如果你的app使用了自己定义的Application class,你可以重写attachBaseContext()方法并在其中调用MultiDex.install(this)去实现multidex。更多信息请参考 
 Limitations of the multidex support library
你应该意识到multidex support library有一些已知的限制,所以当你在将他合并到你的应用程序中时需要测试一下:
1..dex文件的安装在启动设备的数据分区很复杂,如果二级dex文件太大可能导致程序没有响应(ANR)。在这种情况下,您应与混淆器(ProGuard)应用代码缩减技术,减少.dex文件的大小和删除未使用的部分代码。
2.程序不能在在早已Android4.0(API level 14)之前的版本上使用multidex由于a Dalvik linearAlloc bug(Issue )(/22586)如果你使用API Level 14之前的版本,确保执行您的应用程序在启动时或者装载特定的类时,测试你的程序是否会出现问题。代码缩减可以消除这些潜在问题。
3.应用程序使用multidex配置会发出非常大的内存分配请求,这可能会导致运行时崩溃,由于a Dalvik linearAlloc bug(Issue )(/78035)。
4.Dalvik runtime执行时the primary dex文件可能需要复杂的请求。Android build tooling 更新处理Android需求,但是其他included libraries可能有额外的依赖需要,包括调用本地的java代码。一些library可能无法使用,直到multidex build tools更新后允许您指定必须包含在主dex文件的类。 
 Optimizing Multidex Development Builds
multidex配置需要显著增加构建处理时间,因为构建系统必须做出复杂决定,来确定哪些类必须包含在主dex文件以及哪些类可以包含在第二级dex文件中。这意味着常规构建执行与multidex作为开发过程的一部分,通常需要更长的时间,这可能减缓你的程序开发进度。
为了减少multidex输出构建时间,你应该创建两个变量来使用Android构建输出插件Gradle productFlavors: a development flavor and a production flavor。
a development flavor,设定一个最低21的SDK版本。这个设置生成multidex输出比使用ART-supported格式要快得多。the release flavor,设定一个最低SDK版本匹配你的项目最低支持版本。这个设置生成一个multidex APK,与更多的设备兼容,但需要更长的时间来构建。
以下构建配置示例演示了如何在Gradle构建文件设置这些 flavors :

android {
productFlavors {
// Define separate dev and prod product flavors.
dev {
// dev utilizes minSDKVersion = 21 to allow the Android gradle plugin
// to pre-dex each module and produce an APK that can be tested on
// Android Lollipop without time consuming dex merging processes.
minSdkVersion 21
prod {
// The actual minSdkVersion for the application.
minSdkVersion 14
buildTypes {
release {
runProguard true
proguardFiles getDefaultProguardFile('proguard-android.txt'),
'proguard-rules.pro'
}
}
dependencies {
compile 'com.android.support:multidex:1.0.0'
}

View Code
完成了这个配置更改后,您可以使用与app的devDebug变量相结合的属性dev productFlavor和debug buildType。利用这个去创建一个minSdkVersion为Android API Level 21不使用proguard,启用multidex的debug app 。这些设置使Android gradle插件执行以下操作:
1.构建应用程序的每个模块(包括依赖库)作为单独的dex文件。这通常被称为pre-dexing。
2.包括每个dex文件没有修改APK文件
3.最重要的是,dex的模块文件不会被结合,所以可以避免来确定主dex文件内容的长时间运行的计算。
这些设置导致快速、增量构建,因为只有dex文件修改模块的会重新计算,重新包装成APK文件。这些设置构建APK只能用于测试Android 5.0及以上设备。然而,通过实现配置的flavors,你能够执行正常构建release-appropriate最低SDK和proguard设置
还可以建立其他变量,包括构建prodDebug变量,这需要更长的时间来构建,但可以用于测试外的开发。如果你从命令行执行gradle任务,您可以使用标准命令在结束的位置附加DevDebug(如./ gradlew installDevDebug)。 
关于使用flavors与Gradle任务的更多信息,参考(/tech-docs/new-build-system/user-guide)
Tip:您也可以提供一个自定义清单,或者为每个flavor自定义一个应用程序类,允许你在变量需要的时候使用MultiDexApplication应用程序类库或者调用 MultiDex.install()。

 Using Build Variants in Android Studio
Build variants对管理multidex构建过程是非常有用的,Android Studio可以使用可视化操作来选择这些变量。
1.打开位于 left-sidebar的Build Variants 窗口(一般是在Android studio的左下)
2.点击Build Variants的名称来选择不同的变量,,如图1所示

 
 
 
 
 
 
 
 
 
 Testing Multidex Apps
当multidex应用程序中使用instrumentation tests时,需要进行额外的配置。因为代码在multidex应用程序中不是位于单一DEX文件。所以instrumentation tests不能正常运行,除非程序为multidex配置。
为了使用instrumentation tests测试multidex app,需要配置MultiDexTestRunner。
下面build.gradle文件演示了如何配置来使用这个测试运行器: 

android {
defaultConfig {
testInstrumentationRunner "com.android.test.runner.MultiDexTestRunner"
}
}

Note: With Android Plugin for Gradle versions lower than 1.1, you need to add the following dependency for multidex-instrumentation:

dependencies {
androidTestCompile('com.android.support:multidex-instrumentation:1.0.1') {
exclude group: 'com.android.support', module: 'multidex'

}

你可以用instrumentation tests runner class直接或扩展它来适应您的测试需求。或者,您可以在现有的instrumentation中覆盖onCreate:

public void onCreate(Bundle arguments) {
MultiDex.install(getTargetContext());
super.onCreate(arguments);
...
}

Note: Use of multidex for creating a test APK is not currently supported.
免责声明:本站部分内容、图片、文字、视频等来自于互联网,仅供大家学习与交流。相关内容如涉嫌侵犯您的知识产权或其他合法权益,请向本站发送有效通知,我们会及时处理。反馈邮箱&&&&。
学生服务号
在线咨询,奖学金返现,名师点评,等你来互动}

我要回帖

更多关于 linux 查看内存总数 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信