长期更新,有多少就记多少,预测3月中开始大量更新面试内容。这些内容暂时先放在这里,只有会有变动
ANRandroid 系统线程使用有数量限制内存泄露-内部类SharedPreferences apply 提交- ``
- ``
ANR
什么是ANR,你要是回答:主线程执行耗时任务那一准没戏
ANR是指指定时间内操作无响应,类型有:
InputDispatching Timeout:5秒内无法响应屏幕触摸事件或键盘输入事件BroadcastQueue Timeout:前台广播onReceive()函数10秒没有处理完成,后台为60秒Service Timeout:前台服务20秒内,后台服务在200秒内没有执行完毕ContentProvider Timeout:ContentProvider的publish在10s内没进行完
Acitivity 的5秒是我们最常见的ANR,但这不是其定义,了解了ANR定义,其他平台上的ANR一样就了解了,区别是具体时间考量不同
有个经典的问题:Activity sleep 20秒会ANR吗
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
findViewById(R.id.button).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Log.e("zengyu","before sleep");
try {
Thread.sleep(20000);
} catch (InterruptedException e) {
e.printStackTrace();
}
Log.e("zengyu","after sleep");
}
});
}
}
答案是不会,若是在这20秒内你点别的按钮的话就会ANR,对于第一个按钮来说,sleep就是我们要的操作,所以不算是无响应
android 系统线程使用有数量限制
android 里我们不能无限制 new thread,很多设备会给你 crash,当然部分手机不会,比如三星,但是国产机一般都会
像这样的操作那是万万不能的
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
for (int i = 0; i < 10000; i++) {
new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
}
}
}
该用线程池的时候不要吝啬,该用就用
内存泄露-内部类
这里只说内部类的问题
内部类天然就持有外部类的引用,就算你内部类不用外部类的任何数据和操作也会持有外部类,没有外部类的引用,是找不到内部类的
所以像这样的代码最好别写,要不外部类销毁时,内部类还在运行,那外部类就无法被GC标记
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
new Thread(new Runnable() {
@Override
public void run() {
//TODO
}
}).start();
}
}
静态内部类算是外部类,可以避免内部类持有外部类引用的问题,有时候有条件可以这么写:
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
new StaticThread().start();
}
private static class StaticThread extends Thread {
@Override
public void run() {
super.run();
//TODO
}
}
}
SharedPreferences apply 提交
SharedPreferences 写入数据时应该使用 Editor.apply 代替 Editor.commit
SharedPreferences 操作的是本地 xml 文件,SharedPreferences 读取数据时会优化以下,就是让 SharedPreferences 操作过的 xml 文件内容常驻内存,这样读取操作效率就上来了,就不再是IO耗时操作了
但是我们经常使用的 Editor.commit 是同步操作,是个IO操作,操作的是file文件,要是你写的数据量大,所在的 xml 文件大,那么没2位数ms的时间别想完成操作,但是大家想想16ms系统会刷新一帧,也许你不经意的使用的 commit 正是你百思不得其解的页面为什么会卡一下的元凶
而 Editor.apply 则会使用 xml 常驻在内存中的部分,你修改的内容先写入内存,然后 SharedPreferences 会有异步操作去同步到IO文件,这很像一些对象型数据库的思路
这个点大家要记住了,有人就是爱问这个,这个的确也是让 app 流畅起来的一个小法宝。这个世界上万事万物都是有因果关系的,app 卡也是,只是因为我们知识点不够深入,不了解罢了,一旦我们知道了,8成的卡顿都可以避免
弱引用使用场景
这个放些例子上来,大家体会
public class MainActivity extends AppCompatActivity {
private static class StaticHandler extends Handler {
private WeakReference<MainActivity> activityWeakReference;
public StaticHandler(MainActivity mainActivity) {
this.activityWeakReference = new WeakReference<>(mainActivity);
}
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
//TODO
//use activityWeakReference.get() to get view
}
}
private StaticHandler mStaticHandler = new StaticHandler(this);
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mStaticHandler.sendEmptyMessage(0);
}
}