探讨Android中如何实施网速限制,以模拟低速网络状态
在研究如何在Android系统中实施网速限制以实现模拟低速网络效果的过程中,尽管目前尚不确定谷歌是否提供了专门的API来满足这一需求,但确实存在一种较为可行的替代方案。具体而言,可以在后台启动一个下载线程,以此间接实现这一目标。
此方法的核心在于通过模拟下载行为,来控制实际的网络传输速率。例如,可以设定下载任务的速率上限,或者通过在代码中引入延时来模拟下载过程,从而人为降低数据传输速度。这种技术在开发过程中,常被用于模拟不同网络环境下的应用性能,帮助开发者更好地测试和调整应用的网络性能。
实现这一功能的步骤具体包括:首先,在AndroidManifest.xml文件中为应用添加必要的权限,以确保应用能够访问网络相关设置。接着,在应用的后台服务或线程中,启动一个下载任务。在此任务中,可以通过设定下载速率、引入延迟等方式来控制网络传输速度。
值得注意的是,尽管这种方法可以实现限制网速的效果,但其效果和精确度可能会受到多种因素的影响,如网络环境、设备性能等。因此,在实际应用中,开发者需要根据具体需求和测试环境进行调整和优化。
此外,通过这种方式实现的低速网络效果,在用户体验上可能会有所影响。因此,在设计和实现时,需要综合考虑用户体验和功能需求之间的平衡。同时,开发者也可以探索更多其他的方法,如使用第三方库或服务,以更高效地实现这一功能。
总的来说,尽管直接限制网速的API可能不常见,但通过后台下载任务的策略,开发者可以实现类似的效果,为应用在不同网络环境下的表现提供有力支持。
在Android开发中,有哪些有效的内存优化策略
内存优化
编码
位图
列表视图
软引用和弱引用
用户界面
2.1 编码
提示1:使用经过优化的数据容器。
例如,使用SparseArray、SparseBooleanArray、LongSparseArray来替代HashMap
前提:键为整数类型
原因:
HashMap内存效率低下,因为每个映射都需要单独的条目(如下图)。
每个元素多占用8字节内存(多了next和hash两个成员变量)。自动装箱【int转Integer,导致产生另一个对象】也会额外加4字节。条目对象本身至少16字节。
SparseArray可以避免自动装箱,查找方法为二分查找,效率比HashMap低一些,但百量级以内性能差距不大。
HashMap hashMap = new HashMap();
替换为
SparseArray sparseArray = new SparseArray();
提示2:使用IntentService替代Service。
IntentService优势:
- 新开线程;
- 顺序处理Intent;
- 执行完自动退出。
说明:
Service是一个没有界面的服务,但实际上它不是后台的,所有的代码默认在UI线程执行。若要执行耗时操作,需要新开线程或者使用AsyncTask。
IntentService继承自Service,所以它也是一个服务。
IntentService使用队列的方式将请求的Intent加入队列,然后开启一个worker thread(线程)来处理队列中的Intent,对于异步的startService请求,IntentService会处理完成一个之后再处理第二个,每一个请求都会在一个单独的worker thread中处理,不会阻塞应用程序的主线程。
IntentService与Service区别:
1、Service默认在UI线程执行;而IntentService的onHandleIntent方法在后台执行。
2、Service在启动后,如果没有手动stop会一直存在;而IntentService在执行完后自动退出。
提示3:尽量避免使用Enum。
枚举相对于静态常量来说,需要两倍甚至更多的内存。如下是Enum的类型定义:
提示4:使用混淆器移除不必要的代码。
ProGuard工具通过移除无用代码,使用语意模糊来保留类、字段和方法来压缩、优化和混淆代码。可以使你的代码更加完整,更少的RAM映射页。
提示5:尽量不要因一两个特性而使用大体积类库。
提示6:频繁修改时使用StringBuffer(线程安全)或StringBuilder(线程不安全)。
使用String修改字符串时,若修改后字符串在字符串常量区不存在,便会新生成一个String对象。
提示7:对于常量,请尽量使用static final。
如果使用final定义常量之后,会减少编译器在类生成时初始化方法调用时对常量的存储,对于int型常量,将会直接使用其数值来进行替换,而对于String对象将会使用相对廉价的“string constant”指令来替换字段查找表。虽然这个方法并不完全对所有类型都有效,但是,将常量声明为static final绝对是一个好的做法。
提示8:对象不用时最好显式置为Null。
对象不用时最好显式置为Null可以减少GC开销。
警惕:静态变量引起内存泄漏
这段代码中有一个静态的Resources对象。代码片段mResources = this.getResources()对Resources对象进行了初始化。这时Resources对象拥有了当前Activity对象的引用,Activity又引用了整个页面中所有的对象。
如果当前的Activity被重新创建(比如横竖屏切换,默认情况下整个Activity会被重新创建),由于Resources引用了第一次创建的Activity,就会导致第一次创建的Activity不能被垃圾回收器回收,从而导致第一次创建的Activity中的所有对象都不能被回收。这个时候,一部分内存就浪费掉了。
警惕:使用Activity Context引起内存泄漏。
应该尽量使用Application Context。
应尽可能运用Application Context。
在Android系统里,Application Context的生存周期与应用的生存周期保持一致,而非依赖某个Activity的生存周期。若需保持一个持久存在的对象,且该对象需要Context支持,则可使用Application对象。
检查使用周期是否在activity周期内,若超出,则必须使用application;常见场景包括:AsyncTask,Thread,第三方库初始化等。
而某些情况下,只能使用activity:例如,对话框,各种View,以及需要startActivity的等。总之,应尽可能使用Application。
上述由于静态变量引发的内存泄漏问题,可修改如下:
2.2 Bitmap
提示:捕获异常
由于Bitmap是内存消耗大户,为了避免应用在分配Bitmap内存时出现OutOfMemory异常而崩溃,需特别注意实例化Bitmap的代码。通常,在实例化Bitmap的代码中,必须捕获OutOfMemory异常。
OutOfMemoryError是一种错误,而非异常。
提示:缓存通用图像【该方法测试无效】
应用场景:默认头像。有时,可能需要在Activity中多次使用同一张图片。例如,一个Activity会展示用户头像列表,若用户未设置头像,则会显示默认头像,该头像位于应用程序的资源文件中。
此方法无效!因为:
因为Android自带资源文件缓存机制:
在Resource.java类中有LongSparseArray<WeakReference\> mDrawableCache
每次会new一个Drawable,但内部bitmap还是指向cache中的。
提示:压缩图片
BitmapFactory.Options options= new BitmapFactory.Options();
options.inSampleSize= 2;
若图片像素过大,使用BitmapFactory类的方法实例化Bitmap时,就会发生OutOfMemory异常。
使用BitmapFactory.Options设置inSampleSize可以缩小图片。属性值inSampleSize表示缩略图大小为原始图片大小的几分之一。即如果这个值为2,则取出的缩略图的宽和高都是原始图片的1/2,图片的大小就为原始大小的1/4。
若知道图片像素过大,可对其进行缩小。那么如何判断图片是否过大呢?
使用BitmapFactory.Options设置inJustDecodeBounds为true后,再使用decodeFile()等方法,并不会真正分配空间,即解码出来的Bitmap为null,但可计算出原始图片的宽度和高度,即options.outWidth和options.outHeight。通过这两个值,就可以判断图片是否过大了。
先获取图片真实的宽度和高度,然后判断是否需要缩小。若不需要缩小,设置inSampleSize的值为1。若需要缩小,则动态计算并设置inSampleSize的值,对图片进行缩小。
提示:及时回收Bitmap的内存(≤Android 2.3.3,API10)
Bitmap类的构造方法都是私有的,因此开发者不能直接new出一个Bitmap对象,只能通过BitmapFactory类的各种静态方法来实例化一个Bitmap。
仔细查看BitmapFactory的源代码可以看到,生成Bitmap对象最终都是通过JNI调用方式实现的。所以,加载Bitmap到内存后,包含两部分内存区域。简单来说,一部分是Java部分的,一部分是C部分的。这个Bitmap对象是由Java部分分配的,不用时系统会自动回收,但对应的C可用内存区域,虚拟机无法直接回收,这只能调用底层的功能释放。因此需要调用recycle()方法来释放C部分的内存。从Bitmap类的源代码也可以看到,recycle()方法确实调用了JNI方法。
2.3 ListView
提示:从ContentView获取缓存的view
如果不使用缓存convertView,调用getView时每次都会重新创建View,这样之前的View可能还没有销毁,加之不断的新建View势必会造成内存泄漏。
提示:使用ViewHolder模式来避免不必要的findViewById()调用
ViewHolder模式通过getView()方法返回的视图的标签(Tag)中存储一个数据结构,这个数据结构包含了指向我们要绑定数据的视图的引用,从而避免每次调用getView()时调用findViewById()。
2.4 SoftReference& WeakReference
软引用
只有当内存空间不足时,才会回收这些对象的内存。
软引用可用于实现内存敏感的高速缓存。
Map<String, SoftReference\> imageCache= new HashMap<String, SoftReference\>();
弱引用
被垃圾回收器扫描到后即被回收。
Map<String,WeakReference\> cacheMap= new HashMap<String, WeakReference\>();
只具有弱引用的对象拥有更短暂的生命周期。在垃圾回收器线程扫描其管辖的内存区域的过程中,一旦发现了只具有弱引用的对象,不管当前内存空间是否足够,都会回收它的内存。不过,由于垃圾回收器是一个优先级很低的线程,因此不一定会很快发现那些只具有弱引用的对象。
案例:异步加载网络图片
详见:
2.5 UI
提示1:利用系统资源
系统定义的id:如android:id/list
系统的图片资源:如*android:drawable/ic_menu_attachment
系统的文字串资源:如android:string/yes
系统的Style:如android:textAppearance="?android:attr/textAppearanceMedium“
系统的颜色定义:如android:background="android:color/transparent"
说明:
Android系统本身拥有许多资源,包括各种字符串、图片、动画、样式和布局等,这些都可以在应用程序中直接使用。这样做的好处很多,既可以减少内存使用,又可以减少部分工作量,还可以缩减程序安装包的大小。
Android操作系统蕴含了丰富的资源,涵盖各式各样的文字、图像、动画、样式及布局等,这些资源均可在应用软件中直接调用。这种做法的优势显而易见,既能降低内存消耗,又能减轻开发负担,同时还能缩小应用安装包的体积。
在Android系统中,不存在公开的资源,若在xml文件中直接引用,将会出现错误提示。除了将资源文件拷贝至应用目录下使用之外,我们还可以将“android”引用更改为“*android”以解决问题。
提示2:通用模块提取
背景
顶部标题栏
底部导航栏
列表视图
提示3:视图占位符
视图占位符是一种隐藏的、不占用内存空间的视图对象,它能够在运行时延迟加载布局资源文件。