Android应用里有几种Context对象,
Context类图如下所示:
可以发现Context是个抽象类,它的具体实现类是ContextImpl,ContextWrapper是个包装类,内部的成员变量mBase指向的也是个ContextImpl对象,ContextImpl完成了
实际的功能,Activity、Service与Application都直接或者间接的继承ContextWrapper。
2、Android哪些情况会导致内存泄漏,如何分析内存泄漏?
常见的产生内存泄漏的情况如下所示:
- 持有静态的Context(Activity)引用。
- 持有静态的View引用,
- 内部类&匿名内部类实例无法释放(有延迟时间等等),而内部类又持有外部类的强引用,导致外部类无法释放,这种匿名内部类常见于监听器、Handler、Thread、TimerTask
- 资源使用完成后没有关闭,例如:BraodcastReceiver,ContentObserver,File,Cursor,Stream,Bitmap。
- 不正确的单例模式,比如单例持有Activity。
- 集合类内存泄漏,如果一个集合类是静态的(缓存HashMap),只有添加方法,没有对应的删除方法,会导致引用无法被释放,引发内存泄漏。
- 错误的覆写了finalize()方法,finalize()方法执行执行不确定,可能会导致引用无法被释放。
查找内存泄漏可以使用Android Profiler工具或者利用LeakCanary工具。
3、SharePreference性能优化
在Android中, SharePreferences是一个轻量级的存储类,特别适合用于保存软件配置参数。使用SharedPreferences保存数据,其背后是用xml文件存放数据,文件
存放在/data/data/ < package name > /shared_prefs目录下.
之所以说SharedPreference是一种轻量级的存储方式,是因为它在创建的时候会把整个文件全部加载进内存,如果SharedPreference文件比较大,会带来以下问题:
- 第一次从sp中获取值的时候,有可能阻塞主线程,使界面卡顿、掉帧。
- 解析sp的时候会产生大量的临时对象,导致频繁GC,引起界面卡顿。
- 这些key和value会永远存在于内存之中,占用大量内存。
优化建议
- 不要存放大的key和value,会引起界面卡、频繁GC、占用内存等等。
- 毫不相关的配置项就不要放一起,文件越大读取越慢。
- 读取频繁的key和不易变动的key尽量不要放在一起,影响速度,如果整个文件很小,那么忽略吧,为了这点性能添加维护成本得不偿失。
- 不要乱edit和apply,尽量批量修改一次提交,多次apply会阻塞主线程。
- 尽量不要存放JSON和HTML,这种场景请直接使用JSON。
- SharedPreference无法进行跨进程通信,MODE_MULTI_PROCESS只是保证了在API 11以前的系统上,如果sp已经被读取进内存,再次获取这个SharedPreference的时候,如果有这个flag,会重新读一遍文件,仅此而已。
4、理解序列化吗,Android为什么引入Parcelable?
所谓序列化就是将对象变成二进制流,便于存储和传输。
- Serializable是java实现的一套序列化方式,可能会触发频繁的IO操作,效率比较低,适合将对象存储到磁盘上的情况。
- Parcelable是Android提供一套序列化机制,它将序列化后的字节流写入到一个共性内存中,其他对象可以从这块共享内存中读出字节流,并反序列化成对象。因此效率比较高,适合在对象间或者进程间传递信息。
package com.tutor.objecttran;
import java.io.Serializable;
public class Person implements Serializable {
private static final long serialVersionUID = -7060210544600464481L;
private String name;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
package com.tutor.objecttran;
import android.os.Parcel;
import android.os.Parcelable;
public class Book implements Parcelable {
private String bookName;
private String author;
private int publishTime;
public String getBookName() {
return bookName;
}
public void setBookName(String bookName) {
this.bookName = bookName;
}
public String getAuthor() {
return author;
}
public void setAuthor(String author) {
this.author = author;
}
public int getPublishTime() {
return publishTime;
}
public void setPublishTime(int publishTime) {
this.publishTime = publishTime;
}
public static final Parcelable.Creator<Book> CREATOR = new Creator<Book>() {
public Book createFromParcel(Parcel source) {
Book mBook = new Book();
mBook.bookName = source.readString();
mBook.author = source.readString();
mBook.publishTime = source.readInt();
return mBook;
}
public Book[] newArray(int size) {
return new Book[size];
}
};
public int describeContents() {
return 0;
}
public void writeToParcel(Parcel parcel, int flags) {
parcel.writeString(bookName);
parcel.writeString(author);
parcel.writeInt(publishTime);
}
}
//Serializeable传递对象的方法
public void SerializeMethod(){
Person mPerson = new Person();
mPerson.setName("frankie");
mPerson.setAge(25);
Intent mIntent = new Intent(this,ObjectTranDemo1.class);
Bundle mBundle = new Bundle();
mBundle.putSerializable(SER_KEY,mPerson);
mIntent.putExtras(mBundle);
startActivity(mIntent);
}
Person mPerson = (Person)getIntent().getSerializableExtra(ObjectTranDemo.SER_KEY);
//Pacelable传递对象方法
public void PacelableMethod(){
Book mBook = new Book();
mBook.setBookName("Android Tutor");
mBook.setAuthor("Frankie");
mBook.setPublishTime(2010);
Intent mIntent = new Intent(this,ObjectTranDemo2.class);
Bundle mBundle = new Bundle();
mBundle.putParcelable(PAR_KEY, mBook);
mIntent.putExtras(mBundle);
startActivity(mIntent);
}
Book mBook = (Book)getIntent().getParcelableExtra(ObjectTranDemo.PAR_KEY);
5、PathClassLoader与DexClassLoader有什么区别?
- PathClassLoader:只能加载已经安装到Android系统的APK文件,即/data/app目录,Android默认的类加载器。
- DexClassLoader:可以加载任意目录下的dex、jar、apk、zip文件。
6、如果防止过度绘制,如何做布局优化?
- 使用include复用布局文件。引入布局
- 使用merge标签避免嵌套布局。用include标签的时候根布局用merge减少层级
- 使用stub标签仅在需要的时候在展示出来。用到时在加载布局