如果您对AndroidStudio3.0上分析内存泄漏的原因和androidstudio内存泄露感兴趣,那么这篇文章一定是您不可错过的。我们将详细讲解AndroidStudio3.0上分析内存泄漏的原
如果您对Android Studio 3.0上分析内存泄漏的原因和android studio 内存泄露感兴趣,那么这篇文章一定是您不可错过的。我们将详细讲解Android Studio 3.0上分析内存泄漏的原因的各种细节,并对android studio 内存泄露进行深入的分析,此外还有关于Android Emulator未在Android Studio 3.0上运行、Android Handler 避免内存泄漏的用法总结、Android Studio+MAT实战内存泄漏、Android Studio使用Profiler来完成内存泄漏的定位的实用技巧。
本文目录一览:- Android Studio 3.0上分析内存泄漏的原因(android studio 内存泄露)
- Android Emulator未在Android Studio 3.0上运行
- Android Handler 避免内存泄漏的用法总结
- Android Studio+MAT实战内存泄漏
- Android Studio使用Profiler来完成内存泄漏的定位
Android Studio 3.0上分析内存泄漏的原因(android studio 内存泄露)
以前用eclipse的时候,我们采用的是DDMS和MAT,不仅使用步骤复杂繁琐,而且要手动排查内存泄漏的位置,操作起来比较麻烦。后来随着Android studio的潮流,我也抛弃了eclipse加入了AS。
Android Studio也开始支持自动进行内存泄漏检查,并且操作起来也比较方便。
封面
戳我下载 Android Studio 3.0
这个不用梯子我会告诉你吗
1.写在前面
Google在上周发布了Android Studio 3.0的正式版本,周四早晨在上班的地铁上就看到群里在沸沸扬扬的讨论关于3.0版本的各种坑,啊,不对,各种特性,到公司之后就迫不及待的更新了3.0版本,嗯,还算顺利,只遇到了一个坑,一切都在happy的进行着。
什么,你以为我想要写遇到的坑是什么,呵呵哒,我才不会告诉你,等等。。。手里的板砖先放下,一会说还不行吗,今天我们主要来聊聊如何在Android Studio 3.0上分析内存泄漏,文章的内容很简单,但是自己摸索还是需要一些时间的,所以就在这里记录下来分享给大家。
2.强大的Android Profiler
戳这里查看官方文档
在3.0版本中,android使用了新的性能分析工具Android Profiler来代替原有的Android Monitor,使用方式和原来类似,都可以分析cpu、内存和网络的使用情况,但是功能强大了很多。
开始使用
还记得我之前写过一篇文章《Android 使用RxLifecycle解决RxJava内存泄漏》,本文将以这篇文章里的Demo为例,使用Android Studio 3.0再次分析一下内存泄漏。
首先点击工具栏中的Profile按钮将待分析的App安装到设备上,也可以直接安装,在AS底部选择Android Profiler按钮:
将待分析的APP安装到设备上
可以看到有下面的提示,大概意思是不能在当前进程进行更高级的分析:
不能在当前进程进行更高级的分析
点击Run Configuration进去看看,发现不能勾选开关,提示gradle插件版本太低,需要2.4以上版本才可以,嗯,那就更新一下:
更新gradle插件版本
已经更新到3.0版本了,可以勾选开关了,点击确定:
dependencies { classpath 'com.android.tools.build:gradle:3.0.0' }
勾选开关
又来一个警告,大概意思是说,你的gradle版本已经升级到3.0了,需要和26.0.2版本的构建工具搭配才更好,好好好,听你的:
更新26.0.2版本的构建工具
更新完成之后,需要再次运行一下App,如果还提示更高级的分析,请重启Android Studio,重启还不好,没关系,反正今天也用不到它,不要打我,下面来看下正常的Android Profiler:
Android Profiler
点击MEMORY进入内存详情,在这里可以实时查看内存的占用情况:
内存详情
内存泄漏分析
我们先写个会发生内存泄漏的程序分析一下:
public class RxLifecycleComponentsActivity extends RxAppCompatActivity { @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_rxlifecycle); ButterKnife.bind(this); initData(); } private void initData() { // 每隔1s执行一次事件 Observable.interval(1,TimeUnit.SECONDS) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(new Observer<Long>() { @Override public void onSubscribe(@NonNull disposable d) { } @Override public void onNext(@NonNull Long aLong) { Log.i("接收数据",String.valueOf(aLong)); } @Override public void onError(@NonNull Throwable e) { } @Override public void onComplete() { } }); } }
很简单,每隔1s发送一条数据,因为关闭Activity之后没有取消订阅,RxJava还继续持有Activity的引用,所以在内存回收的时候,该Activity不会被回收,由此引发内存泄漏。
下面反复打开关闭页面5次,然后手动GC(点击左上角的垃圾桶图标),发现内存占用并没有减少:
内存泄漏分析
分析一下当前的内存堆栈情况(点击垃圾桶图标右侧的图标):
分析内存堆栈情况
选择按包名查找,找到当前测试的Activity,发现存在5个实例,由此可见,内存已经发生了泄漏:
内存泄漏
防止内存泄漏
修改一下上面的代码,在关闭Activity时取消订阅:
public class RxLifecycleComponentsActivity extends RxAppCompatActivity { @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_rxlifecycle); ButterKnife.bind(this); initData(); } private void initData() { // 每隔1s执行一次事件 Observable.interval(1,TimeUnit.SECONDS) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .compose(this.<Long>bindUntilEvent(ActivityEvent.DESTROY)) .subscribe(new Observer<Long>() { @Override public void onSubscribe(@NonNull disposable d) { } @Override public void onNext(@NonNull Long aLong) { Log.i("接收数据",String.valueOf(aLong)); } @Override public void onError(@NonNull Throwable e) { } @Override public void onComplete() { } }); } }
反复打开页面5次,手动GC,看下当前的堆栈情况,可以看到当前已经没有RxLifecycleComponentsActivity的实例存在了:
无内存泄漏
OK,到这里,在Android Studio 3.0上分析内存泄漏就学习完了,赶快去动手试试吧!
3.更新Android Studio遇到的问题
编译的时候报错:
发现是在gradle里打包输出apk的代码出的问题,原代码是这样的:
applicationVariants.all { variant -> variant.outputs.each { output -> def file = output.outputFile String apkName = "APK_NAME" + defaultConfig.versionName.replace(".","_") + ".apk" output.outputFile = new File(file.parent,apkName) } }
修改成这样就可以了:
applicationVariants.all { variant -> variant.outputs.all { outputFileName = "APK_NAME" + defaultConfig.versionName.replace(".","_") + ".apk" } }
4.写在最后
戳我下载 Android Studio 3.0
戳我下载本文使用的测试Demo
Android Emulator未在Android Studio 3.0上运行
在这里,您可以看到我创建了一台名为Nexus 5X的avd机器,我捕获了已创建机器的详细信息,在这里您可以看到:
Name: Nexus_5X_API_25 cpu/ABI: Google Apis Intel Atom (x86) Path: C:\Users\williams\.android\avd\Nexus_5X_API_25.avd Target: google_apis [Google Apis] (API level 25) Skin: nexus_5x SD Card: C:\Users\williams\.android\avd\Nexus_5X_API_25.avd\sdcard.img hw.dPad: no runtime.network.speed: full hw.accelerometer: yes hw.device.name: Nexus 5X vm.heapSize: 256 skin.dynamic: yes hw.device.manufacturer: Google hw.gps: yes hw.initialOrientation: Portrait image.androidVersion.api: 25 hw.audioInput: yes image.sysdir.1: system-images\android-25\google_apis\x86\ tag.id: google_apis showDeviceFrame: yes hw.camera.back: emulated hw.mainKeys: no AvdId: Nexus_5X_API_25 hw.camera.front: emulated hw.lcd.density: 420 avd.ini.displayname: Nexus 5X API 25 hw.gpu.mode: guest hw.device.hash2: MD5:1be89bc42ec9644d4b77968b23474980 hw.ramSize: 1536 hw.trackball: no PlayStore.enabled: false hw.battery: yes hw.cpu.ncore: 2 hw.sdCard: yes tag.display: Google Apis runtime.network.latency: none hw.keyboard: yes hw.sensors.proximity: yes disk.dataPartition.size: 800M hw.sensors.orientation: yes avd.ini.encoding: UTF-8 hw.gpu.enabled: yes
这是SDK工具快照:
好吧,当我运行这个模拟器时,我正面临一些挑战.当我点击这个模拟器的运行按钮时,它什么也没做.
以下是错误日志:
Emulator: Could not launch 'C:\Users\williams\AppData\Local\Android\Sdk\emulator/qemu/windows-x86_64/qemu-system-i386.exe': No such file or directory Emulator: [12360]:ERROR:./android/qt/qt_setup.cpp:28:Qt library not found at C:\Users\williams\AppData\Local\Android\Sdk\emulator\lib64\qt\lib Emulator: Process finished with exit code 2
有人能说出这个配置有什么问题吗?顺便说一句,我已经检查了这些Emulator in Android Studio doesn’t start但没有运气.
解决方法
Android Handler 避免内存泄漏的用法总结
Android开发经常会用到handler,但是我们发现每次使用Handler都会出现:This Handler class should be static or leaks might occur(null)这样的提示。Android lint就是为了提示我们,这样使用Handler会容易造成内存泄漏。但是你会发现其实改成static并没有什么用。因为这并没有解决这个问题的根本。
首先,我们得确认,为什么会有内存泄漏?因为Handler是基于消息的。每次new 出Handler,都会创建一个消息队列用于处理你使用handler发送的消息,形如:handler.send***Message。由于消息的发送总是会有先来后到的区别(如果只是这样都还好,毕竟再慢也不会太久,总归可以跑完,可能会延迟个几秒),但是如果你使用的是sendMessageDelayed(Message msg, long delayMillis)或postDelayed(Runnable r, long delayMillis)等发送延迟消息的时候,那基本内存泄漏发生的概率已经在90%以上了。
我举个通常的例子,就是我们在Activity中使用handler来更新UI控件,这是比较常见的。
public class DemoActivity extends Activity {
private Handler mHandler;
protected void onCreate(Bundle savedInstanceState) {
mHandler = new Handler();
mHandler.postDelayed(new Runnable() {
Log.i("wytings","-----------postDelayed-------");
view.setVisibility(View.GONE);
}, 50000);
...
}
...
}
如果我们疯狂的对这个Activity进行横屏和竖屏切换的话,那么Activity就会不断的被销毁和重建。理论上被关闭的Activity应该会再特定时候被回收,也就是我们的内存会在一定的范围内上下起伏,但是实际上,会发现消耗的内存会随着切换横屏的次数一直慢慢增加。这其实已经说明我们的内存泄漏了,如果你会查看内存,你会发现里面有成堆的DemoActivity实例没办法回收。
这是因为view中使用的Context就是当前的Activity,而这个runnable一旦被post,就会一直存在于队列里面,直到时间到了,被执行。意思是这个时间段内Activity即使已经被destroy了但是这个对象还是没办法回收,你会发现50秒后,会有一堆"-----------postDelayed-------"的log打印出来,虽然你已经把这个应用关闭了并且你以为即使打印也应该只打印一次……
那怎么样才可以避免这中问题呢,如果你网上一搜你会看到很多关于弱引用的文章。这确实是一个解决的办法。其原理就是让所有在handler里面使用的对象都变成弱引用,目的就是为了可以在Android回收内存的时候,可以直接回收掉。我真觉得如果只是写这种办法的人,绝对是属于拷贝党,因为这完全是就事论事。你想想就明白,我们写这个Handler是因为我们要使用它。怎么可以通过这种弱引用的办法去处理这类问题呢?让JVM想回收就回收?!如果这样,那我们还需要在使用Bitmap的时候,recycle()干嘛,还不如直接弄成软引用得了。
这里需要再插播一下关于Java里面引用的知识:
Java引用的知识
强引用(Strong Reference) 默认引用。如果一个对象具有强引用,垃圾回收器绝不会回收它。在内存空 间不足时,Java虚拟机宁愿抛出OutOfMemory的错误,使程序异常终止,也不会强引用的对象来解决内存不足问题。
软引用(SoftReference) 如果内存空间足够,垃圾回收器就不会回收它,如果内存空间不足了,就会回收这些对象的内存。
弱引用(WeakReference) 在垃圾回收器一旦发现了只具有弱引用的对象,不管当前内存空间足够与否,都会回收它的内存。
虚引用(Phantomreference) 如果一个对象仅持有虚引用,那么它就和没有任何引用一样,在任何时候都可能被垃圾回收。
如果你运气好,你会碰到一些除了写弱引用这个方法后,还有一个就是handler.removeCallbacksAndMessages(null);,就是移除所有的消息和回调,简单一句话就是清空了消息队列。注意,不要以为你post的是个Runnable或者只是sendEmptyMessage。你可以看一下源码,在handler里面都是会把这些转成正统的Message,放入消息队列里面,所以清空队列就意味着这个Handler直接被打成原型了,当然也就可以回收了。
所以,我觉得最好的办法就是你在使用Handler的时候,在外面的Activity或者Fragment中的关闭方法中,如onDestroy中调用一下**handler.removeCallbacksAndMessages(null);**就可以了,不应该改成软引用。
其次,要补充一下,自从Android内置LRU的支持后,Google已经明确表示,不推荐使用通常Java的弱引用和软引用来设计Android的缓存机制,原因是Google说它的虚拟机不擅长处理非强引用的对象,所以处理的时候,只有强和非强之分,所以就会出现要么回收过早(从而失去了缓存的意义),要么回收过晚(依然失去了缓存的意义)~
Android Studio+MAT实战内存泄漏
对于内存泄漏,在Android中如果不注意的话,还是很容易出现的,尤其是在Activity中,比较容易出现,下面我就说下自己是如何查找内存泄露的。
首先什么是内存泄漏?
内存泄漏就是一些已经不使用的对象还存在于内存之中且垃圾回收机制无法回收它们,导致它们常驻内存,会使内存消耗越来越大,最终导致程序性能变差。
其中在Android虚拟机中采用的是根节点搜索算法枚举根节点判断是否是垃圾,虚拟机会从GC Roots开始遍历,如果一个节点找不到一条到达GC Roots的路线,也就是没和GC Roots 相连,那么就证明该引用无效,可以被回收,内存泄漏就是存在一些不好的调用导致一些无用对象和GC Roots相连,无法被回收。
既然知道了什么是内存泄漏,自然就知道如何去避免了,就是我们在写代码的时候尽量注意产生对无用对象长时间的引用,说起来简单,但是需要足够的经验才能达到,所以内存泄漏还是比较容易出现的,既然不容易完全避免,那么我们就要能发现程序中出现的内存泄漏并修复它,
下面我就说说如何发现内存泄漏的吧。
查找内存泄漏:
比如说下面这个代码:
public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); String string = new String(); } public void click(View view){ Intent intent = new Intent(); intent.setClass(getApplicationContext(),SecondActivity.class); startActivity(intent); } }
public class SecondActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_second); Runnable runnable = new Runnable() { @Override public void run() { try { Thread.sleep(8000000L); } catch (InterruptedException e) { e.printstacktrace(); } } }; new Thread(runnable).start(); } }
每次跳转到这个Activity中时都会调用一个线程,然后这个线程会执行runnable的run方法 由于Runnable是一个匿名内部对象 所以握有SecondActivity的引用,因此很简单的两个Activity,可由MainActivity跳转到SecondActivity中,下面我们从MainActivity跳到SecondActivity 然后从SecondActivity返回MainActivity,连续这样5次 ,最终返回MainActivity,按照常理来说,我们从SecondActivity返回MainActivity之后 SecondActivity就该被销毁回收,可实际可能并不是这样。
这时候要判断发没发生内存溢出就要使用工具了!下面有两种方式
1.利用MAT工具查找
首先打开AS中的Android Device Monitor工具 具体位置如下图:
打开后会出现如下的界面
先选中你要检测的应用的包名,然后点击下图画圈的地方,会在程序包名后标记一个图标
接下来要做的就是操作我们的app 来回跳转5次。
之后点击下图的图标 就可导出hprof文件进行分析了
导出文件如下图所示:
得到了hprof文件 我们就可以利用MAT工具进行分析了,
打开MAT工具
如果没有 可以在下面网址下载
MAT工具下载地址
界面如下图所示:
打开我们先前导出的hprof文件 ,不出意外会报下面的错误
这是因为MAT是用来分析java程序的hprof文件的 与Android导出的hprof有一定的格式区别,因此我们需要把导出的hprof文件转换一下,sdk中提供给我们转换的工具 hprof-conv.exe 在下图的位置
接下来我们cd到这个路径下执行这个命令转换我们的hprof文件即可,如下图
其中 hprof-conv 命令 这样使用
hprof-conv 源文件 输出文件
比如 hprof-conv E:\aaa.hprof E:\output.hprof
就是 把aaa.hprof 转换为output.hprof输出 output.hprof就是我们转换之后的文件,图中 mat2.hprof就是我们转换完的文件。
接下来 我们用MAT工具打开转换之后的mat2.hprof文件即可 ,打开后不报错 如下图所示:
之后我们就可以查看当前内存中存在的对象了,由于我们内存泄漏一般发生在Activity中,因此只需要查找Activity即可。
点击下图中标记的QQL图标 输入 select * from instanceof android.app.Activity
类似于 sql语句 查找 Activity相关的信息 点击 红色叹号执行后 如下图所示:
接下来 我们就可以看到下面过滤到的Activity信息了
如上图所示, 其中内存中还存在 6个SecondActivity实例,但是我们是想要全部退出的,这表明出现了内存泄漏
其中 有 Shallow size 和 Retained Size两个属性
Shallow Size 对象自身占用的内存大小,不包括它引用的对象。针对非数组类型的对象,它的大小就是对象与它所有的成员变量大小的总和。 当然这里面还会包括一些java语言特性的数据存储单元。针对数组类型的对象,它的大小是数组元素对象的大小总和。 Retained Size Retained Size=当前对象大小+当前对象可直接或间接引用到的对象的大小总和。(间接引用的含义:A->B->C,C就是间接引用) 不过,释放的时候还要排除被GC Roots直接或间接引用的对象。他们暂时不会被被当做Garbage。
接下来 右击一个SecondActivity
选择 with all references
打开如下图所示的页面
查看下图的页面
看到 this0引用了这个Activity而this0是表示 内部类的意思,也就是一个内部类引用了Activity 而 this$0又被 target引用 target是一个线程,原因找到了,内存泄漏的原因 就是 Activity被 内部类引用 而内部类又被线程使用 因此无法释放,我们转到这个类的代码处查看
public class SecondActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_second); Runnable runnable = new Runnable() { @Override public void run() { try { Thread.sleep(8000000L); } catch (InterruptedException e) { e.printstacktrace(); } } }; new Thread(runnable).start(); } } 确实 在
确实 在 SecondActivity中 存在Runnable 内部类对象,然后又被线程 使用,而线程要执行8000秒 因此 SecondActivity对象被引用 无法释放,导致了内存溢出。
要解决这种的内存溢出,要及时在Activity退出时结束线程(不过不大好结束。。),或者良好的控制线程执行的时间即可。
这样我们就找出了这个程序中的内存溢出。
2.直接利用Android Studio的 Monitor Memory 查找内存溢出
还是利用上面那个程序,我就简单点说了。
首先 在手机上运行程序,打开AS的 Minotor 界面 查看Memory 图像
点击 小卡车图标(图中1位置图标) 可以触发一次 GC
点击 图中2位置图标可以查看hprof文件
左边是 内存中的对象,在里面找 Activity 看存不存在我们希望已经回收的Activity 如果 出现我们期望已经回收的Activity,单击 就会在右边显示它的总的个数,点击右边的某个,可以显示 它的GC Roots的树关系图 ,查看关系图就可以找出发生内存泄漏的位置(类似于第一种方式)
这样就完成了内存泄漏的查找。
其中内存泄漏产生的原因在Android中大致分为以下几种:
1.static变量引起的内存泄漏
因为static变量的生命周期是在类加载时开始 类卸载时结束,也就是说static变量是在程序进程死亡时才释放,如果在static变量中 引用了Activity 那么 这个Activity由于被引用,便会随static变量的生命周期一样,一直无法被释放,造成内存泄漏。
解决办法:
在Activity被静态变量引用时,使用 getApplicationContext 因为Application生命周期从程序开始到结束,和static变量的一样。
2.线程造成的内存泄漏
类似于上述例子中的情况,线程执行时间很长,及时Activity跳出还会执行,因为线程或者Runnable是Acticvity内部类,因此握有Activity的实例(因为创建内部类必须依靠外部类),因此造成Activity无法释放。
AsyncTask 有线程池,问题更严重
解决办法:
1.合理安排线程执行的时间,控制线程在Activity结束前结束。
2.将内部类改为静态内部类,并使用弱引用WeakReference来保存Activity实例 因为弱引用 只要GC发现了 就会回收它 ,因此可尽快回收
3.BitMap占用过多内存
bitmap的解析需要占用内存,但是内存只提供8M的空间给BitMap,如果图片过多,并且没有及时 recycle bitmap 那么就会造成内存溢出。
解决办法:
及时recycle 压缩图片之后加载图片
4.资源未被及时关闭造成的内存泄漏
比如一些Cursor 没有及时close 会保存有Activity的引用,导致内存泄漏
解决办法:
在onDestory方法中及时 close即可
5.Handler的使用造成的内存泄漏
由于在Handler的使用中,handler会发送message对象到 MessageQueue中 然后 Looper会轮询MessageQueue 然后取出Message执行,但是如果一个Message长时间没被取出执行,那么由于 Message中有 Handler的引用,而 Handler 一般来说也是内部类对象,Message引用 Handler ,Handler引用 Activity 这样 使得 Activity无法回收。
解决办法:
依旧使用 静态内部类+弱引用的方式 可解决
其中还有一些关于 集合对象没移除,注册的对象没反注册,代码压力的问题也可能产生内存泄漏,但是使用上述的几种解决办法一般都是可以解决的。
Android Studio使用Profiler来完成内存泄漏的定位
目标
使用Android Studio 4.1来完成内存泄漏的定位 目前网上大多数的文章都是在介绍Profile的使用,可以帮忙你检查出有内存泄漏,谁的内存泄漏.但是根据文章定位谁引起的这个泄漏,一直没有找到方法,通过几次努力,自己找到了比较容易的路径,希望对其他的朋友有帮助
引用
下面文章内使用的Demo在下面的地址 githubDemo 在页面内点击简单例子-> 内存泄漏-> 接着退回到上一个页面完成泄漏模拟
步骤
- 自己模拟一个内存泄漏
- 使用Profiler来完成内存泄漏的位置定位
模拟内存泄漏
在TestActivity类中定义context的静态变量,onCreate时把这个变量赋值为当前Activity的context.在回退到上一个页面时,因为静态变量的持有,导致这个TestActivity无法释放,产生内存泄漏
使用Profiler 来完成定位
首先完成Dump收集
首先我们吊起TestActivity,然后回退到上一个页面,此时内存中应该没有TestActivity,如果有,那么就说明出现了内存泄漏.然后根据下图来完成一次dump收集
点击3时进入下图
首先先点击1来完成gc内存回收 2选择产生dump文件
Profiler根据dump文件来分析内存泄漏,跳转到下图.
1.表示有几个内存泄漏
2.查看当前的内存泄漏对象,我们可以先关注自己的工程的内存泄漏.
3.是对象实例,可能这个对象有多个泄漏对象
4.代表引用
5.点击5以后,6就可以很容易定位到是什么变量导致的这个对象的内存泄漏.
从下图就可以很容易看到是因为我们定位的静态变量引用导致的问题.
以上就是Android Studio使用Profiler来完成内存泄漏的定位的详细内容,更多关于Android Studio用Profiler定位内存泄漏的资料请关注其它相关文章!
- Android Location服务之LocationManager案例详解
- Android LocationManager获取经度与纬度等地理信息
- Android 模拟地图定位功能的实现
- 一分钟快速定位Android启动耗时问题
- Android如何实现模拟定位
- 解决Android原生定位的坑
- Android原生定位服务LocationManager
关于Android Studio 3.0上分析内存泄漏的原因和android studio 内存泄露的介绍现已完结,谢谢您的耐心阅读,如果想了解更多关于Android Emulator未在Android Studio 3.0上运行、Android Handler 避免内存泄漏的用法总结、Android Studio+MAT实战内存泄漏、Android Studio使用Profiler来完成内存泄漏的定位的相关知识,请在本站寻找。
本文标签: