Android面试笔记一:三二一家具

2019-04-13 18:00 阅读 458 次 评论 0 条
版权声明:本文著作权归TeachCourse所有!
转载请注明出处:http://teachcourse.cn/2724.html ,谢谢支持!
  1. Service启动的两种方式及区别
  2. Service如何使用及使用的场景
  3. BroadcastReceiver注册的两种方式及广播使用的场景
  4. ContentProvider怎么使用
  5. 启动Activity的几种方式及使用的场景
  6. 堆和栈的区别及各自的作用
  7. 怎么兼容不同安卓版本系统
  8. 广播静态注册和广播动态注册有什么区别?
  9. 解除绑定后,服务会不会立即停止?
  10. 隐式启动action和category的匹配规则

问题一

  • bindService,服务的生命周期和Activity的生命周期绑定,Activity结束之前,需要注意解除绑定undindService(),防止内存泄露。绑定服务会执行:onCreate->onBind->onUnBind->onDestroy
  • startService,服务启动后,多次调用startService服务,onCreate方法只会执行一次,onStartCommand方法会被执行多次,停止服务需要开发者手动调用Context.stopServiceService.stopSelf方法。启动服务会执行:onCreate->onstartCommand->onDestroy

问题二

  • bindService,启动一个后台服务,监听蓝牙连接的状态并获取传输过来的数据,把数据封装后广播发送,在Activity通过bindService()启动服务,实现ServiceConnection接口,服务连接或服务连接断开后执行对应操作
  • startService,启动一个后台服务,更新APP,在子线程中执行下载的任务,Handler更新下载的进度,下载完成调用Context.stopServiceService.stopSelf方法停止服务

问题三

  • 动态注册的广播接收器不是常驻型的,会随着所注册的Activity的结束而结束,如果所在的Activity已经destroy了,那么该广播接收器也就不能再继续接收广播了。注意:在Activity结束前,要取消注册广播接收器,不然会导致内存泄露。应用场景:1、完成Activity和Service不同组件间的通信;2、实现不同进程间的通信
  • 静态注册的广播接收器是常驻型的,即使所在的APP被关闭了,也是可以接收到广播的。应用场景:1、网络状态不佳时,系统发送一条广播,应用注册静态接收器,提示用户“当前网络异常,请检查联网状态”;2、电量不足时,系统发送一条广播,应用静态注册接收器,提示用户“当前电量不足,注意保存游戏进度”

https://blog.csdn.net/csdn_aiyang/article/details/68947014
https://www.jianshu.com/p/5a983578418e

问题四

ContentProvider是一个抽象类,继承该类后,重写onCreatequerydeleteinsertupdategetType方法,作用实现跨进程数据共享,ContentProvider内部可以将数据写入sqlite或本地文件

应用使用ContentResolver来操作另一个应用内的ContentProvider,通过Uri来定位需要访问的数据,使用UriMather绑定Uri和整型值的关系,用户输入Uri,然后在ContentProvider内查询对应的整型值,存在该整型值返回对应的数据,否则查询失败

public class StudentContentProvider extends ContentProvider {

    //这里的AUTHORITY就是我们在AndroidManifest.xml中配置的authorities
    private static final String AUTHORITY = "com.jrmf360.studentProvider";

    //匹配成功后的匹配码
    private static final int MATCH_CODE = 100;

    private static UriMatcher uriMatcher;

    private StudentDao studentDao;

    //数据改变后指定通知的Uri
    private static final Uri NOTIFY_URI = Uri.parse("content://" + AUTHORITY + "/student");

    static {
        //匹配不成功返回NO_MATCH(-1)
        uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);

        //添加我们需要匹配的uri
        uriMatcher.addURI(AUTHORITY,"student", MATCH_CODE);
    }


    @Override
    public boolean onCreate() {
        studentDao = StudentDao.getInstance(getContext());
        return false;
    }

    @Nullable
    @Override
    public Cursor query(@NonNull Uri uri, @Nullable String[] projection, @Nullable String selection,
                        @Nullable String[] selectionArgs, @Nullable String sortOrder) {
        int match = uriMatcher.match(uri);
        if (match == MATCH_CODE){
            Cursor cursor = studentDao.queryStudent();
            return cursor;
        }
        return null;
    }

    @Nullable
    @Override
    public String getType(@NonNull Uri uri) {
        return null;
    }

    @Nullable
    @Override
    public Uri insert(@NonNull Uri uri, @Nullable ContentValues values) {
        if (uriMatcher.match(uri) == MATCH_CODE){
            studentDao.insertStudent(values);
            notifyChange();
        }
        return null;
    }

    @Override
    public int delete(@NonNull Uri uri, @Nullable String selection, @Nullable String[] selectionArgs) {
        if (uriMatcher.match(uri) == MATCH_CODE){
            int delCount = studentDao.deleteStudent();
            notifyChange();
            return delCount;
        }
        return 0;
    }

    @Override
    public int update(@NonNull Uri uri, @Nullable ContentValues values, @Nullable String selection,
                      @Nullable String[] selectionArgs) {
        return 0;
    }

    private void notifyChange(){
        getContext().getContentResolver().notifyChange(NOTIFY_URI,null);
    }
}

实现ContentProvider,在清单文件中配置。这里的authorities唯一标识该内容提供者,这样其它的应用才可以找到该内容提供者并操作它的数据;exported为true当前内容提供者可以被其它应用使用,默认为true。

<provider
        android:authorities="com.jrmf360.studentProvider"
        android:name=".StudentContentProvider"
        android:exported="true"/>

https://www.jianshu.com/p/5e13d1fec9c9

问题五

  1. standard。每次创建一个Activity实例,应用最广的启动模式,需要注意在网络不佳的情况下有可能重复创建多个Activity实例,白白浪费过多的内存
  2. singleTop,检查栈顶是否存在当前Activity实例,存在栈顶的实例会被重用,否则重新创建实例并入栈。应用场景:点击通知栏的推送消息进入详情界面,详情界面使用到singleTop,当前详情界面位于栈顶会被重用该Activity,不会回调onCreate()onStart()方法而会回调onNewIntent()方法接收传递过来的信息;
  3. singleTask,检查栈内是否存在当前Activity实例,栈内存在该实例则重用,并将位于当前实例之上的Activity出栈。应用场景:H5调起原生APP打开,点击【返回】按钮,回到了APP主界面,这里涉及隐式启动Activity的问题
  4. singleInstance,Android系统中只会存在一个Activity实例,并且该实例独自处于一个任务栈中,使用情况比较罕见,在launcher可能使用

问题六

Java虚拟机将内存划分为方法区、堆、Java栈、程序计数器和本地方法栈

在运行时创建的类实例和数组放在同一个堆上,所有的线程共享同一块堆,堆的大小是有限的,内存不足可能会造成OOM,垃圾收集器需要不断地回收不被引用的对象

每个线程都独享一个Java栈,Java栈有栈帧组成,栈帧保存了方法调用的状态(包括局部变量和操作数栈)。线程调用方法,虚拟机会把栈帧压入Java栈,当方法返回时,栈帧从Java栈中出栈并抛弃

问题七

每个Android版本添加新的特性和相关的API,高版本的API在低版本系统中没法找到对应的方法,容易造成Crash,了解每个版本的差异性,有助于我们在代码中提供判断兼容不同系统,使用到的相关类Builder

系统版本 新增特性 描述
Android 9.0 利用Wifi RTT 实现室内定位 Pie
Android 8.0 findViewById()签名变更 Oreo
Android 7.0 多窗口支持 Nougat
Android 6.0 新增动态申请权限功能 Marshmallow
Android 5.0 ART运行时代替Dalvik成为平台默认配置 Lollipop
Android 4.0 优化内存,提高应用运行速度 KitKat

问题八

静态注册,在清单文件中注册,静态注册的广播在应用程序没有启动,依然可以监听来自系统或其他应用程序发送的广播,常用的场景包括:多进程之间的通信,监听通知消息

动态注册,在代码中设置,组件的生命周期结束,广播停止,防止内存泄露,在组件退出时解注册广播,常用的场景包括:组件内实现消息互传(Activity和Fragment消息传递)

使用广播需要注意几个问题:

  1. onReceive(Context,Intent)方法内避免执行耗时操作,超过10s的耗时操作会出现ANR
  2. onReceive(Context,Intent)使用Context时需要注意,静态注册Context代表ReceiverRestrictedContext类的实例,启动Activity要给Intent设置标记:Intent.FLAG_ACTIVITY_NEW_TASK;动态注册Context代表Activity或Service的实例
  3. 监听系统广播,除了需要申请对应的权限外,在高版本系统中,需要做兼容性的处理,比如:开机启动、电量变化、网络连接等
  4. 普通广播是并行无序执行,有序广播是按优先级串行有序执行

问题九

解除绑定后,服务不会立即停止。原因是ServiceConnection和Context解除绑定后,如果服务还在运行,服务不会回调Service.onDestroy()方法

startService()启动服务后,手动调用Context.stopService()Service.stopSelf()才会停止服务;bindService()启动服务后,和Activity的生命周期绑定,Activity退出后服务停止,应用与前台数据的交互

服务应用于不需要与用户交互且长时间运行的任务,同时Service运行在UI线程,不适合执行耗时的操作

执行耗时的操作可以考虑使用IntentService,重写onHandleIntent()方法,在方法内执行耗时的操作

服务分为前台服务后台服务,后台服务的优先级比较低,在内存不足的时候可能会被回收。前台服务弥补了后台服务的缺点,一直保持运行状态而不被系统回收。

常用的系统服务包括:WifiManagerAudioManagerConnectivityManager

https://www.cnblogs.com/huolongluo/p/6340743.html

问题十

应用启动分为隐式启动和显示启动,隐式启动需要给Intent设置actioncategorydata,重点介绍隐式启动的规则:

  • action,一对多,Intent必须设置ACTION,清单文件可以设置多个ACTION。只要Intent设置的ACTION在清单文件中被找到,配置成功
  • category,多对多或0对多,Intent可以设置多个CATEGORY或不设置,清单文件也可以设置多个CATEGORY或者设置android.intent.category.DEFAULT。只要Intent设置的多个CATEGORY在清单文件中被找到,配置成功。
  • data,一对多,Intent设置DATA的内容包括:Uri、mimeType,Uri的结构为scheme://host/port/pathPrefix?params=value
关注公众号 扫一扫二维码,加我QQ

如果文章对你有帮助,欢迎点击上方按钮关注作者

来源:TeachCourse每周一次,深入学习Android教程,关注(QQ1589359239或公众号TeachCourse)
转载请注明出处:http://teachcourse.cn/2724.html ,谢谢支持!
分类:面试题汇 标签:
调试微信官方Demo闪退的几个问题 调试微信官方Demo闪退的几个问题
LinkedHashMap方法解析 LinkedHashMap方法解析
浅谈事件监听器接口的实现方法 浅谈事件监听器接口的实现方法
PopupWindow实现微信绑定开户行弹窗效果 PopupWindow实现微信绑定开户行

发表评论

呲牙 憨笑 坏笑 偷笑 色 微笑 抓狂 睡觉 酷 流汗 鼓掌 大哭 可怜 疑问 晕 惊讶 得意 尴尬 发怒 奋斗 衰 骷髅 啤酒 吃饭 礼物 强 弱 握手 OK NO 勾引 拳头 差劲 爱你

表情