android 面试琐碎知识点(一)

471 阅读4分钟

长期更新,有多少就记多少,预测3月中开始大量更新面试内容。这些内容暂时先放在这里,只有会有变动

  • ANR
  • android 系统线程使用有数量限制
  • 内存泄露-内部类
  • 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);
    }
}