android高级
1. 给定User表,字段有Name...,写对增删改查的Sql语句(5分钟)
创建表:create table user(id int(11) primary key auto_increment,name varchar(20),age int(4),sex varchar(10),);
增:insert into user(name,age,sex) values(?,?,?);
删:delete from user where name=?;
改:update user set age=?,sex=? where name=?;
查询所有:select * from user;
根据名称查找:select * from user where name=?;
2. Fragment与Activity和Fragment与Fragment之间的相互通信(8分钟)
从Activity到Fragment
1.在创建Fragment的时候调用setArguments()传入一个Bundle对象传入数据
2.Fragment的构造中添加需要参数的构造
3.在Fragment中创建一个方法,调用方法传入数据
从Fragment到Activity
1.Fragment中调用getActivity()得到activity,把Activity强转成具体的Activity,然后调用方法直接传值
2.在Fragment中创建接口,由Activity实现这个接口,然后Fragment回调Activity
从Fragment到Fragment
1.用getActivity()获取Activity,强转成具体的Activity,然后通过Activity找到想要的Fragment进行使用
2.静态使用Fragment时,用FragmentManager调用findFragmentById("ID"),或者ByTag()得到对应的fragment,然后使用
3.用FragmentManeage通过方法getFragments()得到Fragment的集合遍历集合,通过判断得到需要的Fragment然后使用(不推荐)
3. Activity常用生命周期以及对应的作用(10分钟)
Activity
onCreate() 不可见状态
Activity被创建时回调,做一些初始化的操作,如设置系统布局,加载toolbar,初始化所需要的组件信息
onStart() 可见状态
表示Activity正在启动,界面还不会被用户看见,无法交互。
onRestart() 由不可见变为可见
在ACtivity跳转到其他页面,又返回到这个Activity时调用该方法
onResume() 可见状态,
Activity已在在屏幕上显示UI并允许用户操作了,重新回到前台时也会调用此方法。此方法中做初始化资源,或启动动画等操作
onPause() 不可见状态
界面处于短暂,暂停状态,当Activity跳转时会调用该方法;跳转的页面是弹出框时,回到本页面会直接调用onResume,不调用onStop,此方法可以做数据存储、动画停止、资源回收等操作,不要做耗时操以免影响下个页面的及时显示
onSaveInstanceState()
用于保存activity的状态,当应用遇到(内存不足,用户直接按home键)由系统直接销毁一个Activity时调用,
onRestoreInstanceState()
当Activity在之前被破坏后重新创建时,调用此方法,可以获取onSaveInstanceState ()中Bundle保存的信息,达到共享上个意外销毁的实例的信息
onStop() 不可见状态
Activity即将停止或者完全被覆盖,仅在后台运行,可以做资源释放的操作,不能太耗时
onDestroy() 销毁状态
正在被销毁时调用,做一些回收工作和最终的资源释放。
单独做为一道题:Fragment常用生命周期以及对应的作用
Fragment
onAttach()
activity绑定到了Fragmeng上
onCreate()
Fragment对象创建完成
onCreateView()
用于创建Fragment的视图View,可以在这里做一些初始化操作
onActivityCreated()
Activity准备完成 ,可以显示Fragment了
onViewCreated()
被调用时说明Fragment的View创建完成 可以在这里进行初始化各种数据了
onStart()
Fragment启动显示,但是无法操作
onResume()
完全显示,可以允许用户操作
onPause()
Fragment暂停,一般会跟随调用onStop()
onStop()
调用时Fragment停止
onDestroyView() 销毁View
Fragment的view被销毁,如果使用viewpager显示Fragment ,adapter使用的是FragmentPagerAdapter则离开此fragment不会导致onDestroyView ()
onDestroy() 销毁状态
调用时Fragment被销毁,如果使用了FragmentSteatePagerAdapter就会调用这个方法
onDetach()
Activity与Fragment解除依附状态
4. 说一下Okhttp原理(8分钟)
OkHttp是一个精巧的网络请求库,支持http2,所有请求共享同一个socket,内置连接池,支持连接复用,减少延迟,支持透明的gzip压缩响应体。通过缓存避免重复的请求,请求失败时自动重试主机的其他ip,自动重定向,使用方便。
OkHttp3最底层是Socket,通过Platform的Class.forName()反射获得当前使用的socket。在connection接口中封装创建socket对象,通过RealConnection来实现。数据的输入输出流操作通过stream接口来实现,根据不同的网络协议,有Http1xStream和Http2xStream两个实现类
由于创建网络连接的时间较久(如果是HTTP的话,需要进行三次握手),而请求经常是频繁的碎片化的,为了提高网络连接的效率,实现了网络连接复用。
okhttp中用到的设计模式
单例模式:OkHttpClient拥有自己独有的线程池和连接池。一个对象即可, 多个容易导致内存爆掉
外观模式:OKHttpClient 里面组合了很多的类对象。此模式是将OKHttp的很多功能模块,全部包装进这个类中,让这个类单独提供对外的API
Builder模式:使用多个简单的对象一步一步构建成一个复杂的对象
工厂模式:Call接口提供了内部接口Factory,将对象的创建放到到该工厂类的子类中进行,从而实现动态的配置。
工厂方法模式。在创建对象时不会暴露创建逻辑,通过使用一个共同的接口来指向新创建的对象
享元模式:在Dispatcher的线程池中,所用到了享元模式,一个不限容量的线程池 , 线程空闲时存活时间为 60 秒。(帮助理解,可以不写:线程池实现了对象复用,降低线程创建开销,从设计模式上来讲,使用了享元模式。享元模式:尝试重用现有的同类对象,如果未找到匹配的对象,则创建新对象,主要用于减少创建对象的数量,以减少内存占用和提高性能)
责任链模式:在okhttp中的拦截器模块,执行过程用到。(帮助理解,可以不写: OkHttp3 的拦截器链中, 内置了5个默认的拦截器,分别用于重试、请求对象转换、缓存、链接、网络读写(责任链模式为请求创建了一个接收者对象的链。这种模式给予请求的类型,对请求的发送者和接收者进行解耦。这种类型的设计模式属于行为型模式。在这种模式中,通常每个接收者都包含对另一个接收者的引用。如果一个对象不能处理该请求,那么它会把相同的请求传给下一个接收者,依此类推。)
策略模式 :CacheInterceptor 实现了数据的选择策略, 来自网络还是来自本地。(帮助理解,可以不写: 这个场景也是比较契合策略模式场景, CacheInterceptor 需要一个策略提供者提供它一个策略, CacheInterceptor 根据这个策略去选择走网络数据还是本地缓存。(策略模式一个类的行为或其算法可以在运行时更改。这种类型的设计模式属于行为型模式。策略模式中,我们创建表示各种策略的对象和一个行为随着策略对象改变而改变的 context 对象。策略对象改变 context 对象的执行算法。)
5. 列举一下Ok中的拦截器以及作用(不写方法不得分)(5分钟)
okhttp中用到的拦截器时顺序运行的
1.RetryAndFollowUpInterceptor (重定向拦截器)
发起网络请求,如果网络请求出现异常会根据响应码进行重定向和重试,重定向时如果地址不一致会释放连接。如果没有异常则调起下一个拦截器chain.proceed(request)
2.BridgeInterceptor (桥接拦截器)
职责1:将构建的 Request 请求转换为能够进行网络访问的请求,添加用于网络请求的请求头信息
职责2:根据响应是否需要对Response 进行 gzip 压缩,具体是用 Okio 的库对 Response 进行压缩,并返回 Response
3.CacheInterceptor (缓存拦截器)
1.根据request来判断cache中是否有缓存的response,如果有,得到response,然后进行判断response是否有效,没有将cacheCandate赋值为空。
2.根据request判断缓存的策略,是否要使用了网络,缓存,或两者都使用调用下一个拦截器,决定从网络上来得到response,如果本地已经存在cacheResponse,那么让它和网络得到的networkResponse做比较,决定是否来更新缓存的cacheResponse,缓存未经缓存过的response。
4.ConnectInterceptor (连接拦截器)
TCP每次请求都建立连接会极大地影响效率。连接拦截器内部维护了可以重复使用的 Socket 连接池,减少握手次数,加快请求响应。
5.网络拦截器(NetworkInterceptor)
在请求发起之前,可以添加自定义拦截器
6.CallServerInterceptor(读写拦截器)
负责实现网络IO,所有拦截器都要依赖它才能拿到响应数据。
6. GreenDao如何进行数据库升级(4分钟)
1).建立一个临时表(数据格式与原表一样)
2).在表实体中,调整其中的变量(表字段),一般就是新增/删除/修改字段。
3).将表实体中的自动生成的构造方法以及getter/setter方法删除,重新Build—>Make Project进行生成。
4).修改Module下build.gradle中数据库的版本号schemaVersion ,递增加1,最后运行app
7. 如何实现Fragment的懒加载(4分钟)
Fragment 有一个setUserVisibleHint()回调方法,Fragment结合 ViewPager使用时会起作用,滑动ViewPage则setUserVisibleHint方法会被调用,参数isVisibleToUser为true代表当前 Fragment 对用户可见,否则不可见。
在 Fragment 创建期间setUserVisibleHint()方法是在onCreateView()之前被调用,为了避免异常,在加载请求数据前做一个判断 1. UI 界面已经创建完2 .Fragment 对用户可见3.没请求过数据。条件都满足,再加载数据。
以下大概代码:
首先定义三个变量(变量名可以自定义):
中进行判断:
image.png8. RecycleView与ListView的区别?(5分钟)
- 层级不同
ListView两级缓存,RecyclerView四级缓存 - 缓存不同
RecyclerView缓存RecyclerView.ViewHolder,ListView缓存View - 刷新不同
RecyclerView提供了局部刷新的接口,能避免调用许多无用的bindView。 - 数据源改变时的缓存的处理逻辑:ListView是"一锅端",将所有的mActiveViews都移入了二级缓存mScrapViews,而RecyclerView则是更加灵活地对每个View修改标志位,区分是否重新bindView。
- recyclerView 需要设置布局管理器,可以实现多种布局样式的管理,listview只能是列表样式。
- recyclerView没有自己的点击监听器,Listview 有多种监听器。
9. 说一下Android中数据存储的几种方式(5分钟)
5种分别为:文件存储、SQLite数据库、SharedPreferences、ContentProvider、网络。特点如下:
1)文件存储
Android中读取/写入文件的方法,与Java的I/O一样,提供openFileInput()和openFileOutput()方法来读取设备上的文件。
2)SQLite数据库
Android集成的一个轻量级的嵌入式数据库,支持Andorid API操作,也支持SQL语句进行增删改查等操作。
3)SharedPreferences
Android提供的用于存储一些简单配置信息的一种机制,采用了XML格式将数据存储到设备中。可以在同一个APP下使用,还可以访问其他应用程序的数据,但是很少用
4)ContentProvider
主要用于不同应用程序之间共享数据,统一接口,使不同应用共享数据更规范和安全。
5)网络存储数据
通过网络上提供的存储空间来上传(存储)或下载(获取)数据
10. 线程同步和异步的理解和区别?(5分钟)
1.同步时主线程会阻塞,直到子线程通知主线程为止(先不考虑ANR);就是程序会呆板地从头执行到尾,耗时间的东西不执行完,程序不会继续往下走,等待时间长的话,会造成失去响应。
2.异步时主线程可以继续干其它的事情,当子线程完成任务通知一下主线程就可以了,类似于接口回调或消息队列的思想
3.异步的好处:把耗时间的东西扔到后台去运行(doInBackground),主程序可以继续做自己的事情,防止程序卡死。所以我一般在进行耗时操作的时候都会用异步操作
11. 11. 说一下网络协议的模型的分层以及Http、https和TCP、Socket在那一层
注:答题时不需要画图,可以简化答题
最早是OSI七层,分为应用层、表示层、会话层、传输层、网络层、数据链路层、物理层,
</u>
后来分为TCP/IP 五层 模型,分为应用层,传输层、网络层、数据链路层、物理层
<u> image.png应用层:主要向用户传送数据的层。包含 HTTP,SMTP(邮件协议), FTP(文件传输)、FSP,TFTP和NFS(用于文件访问的协议
传输层:确保各包已发送的顺序接收,保证没有数据丢失或破坏。如果丢包,传输层会请求发送方重发包。主要有两个协议:UDP和TCP
网络层:定义了数据位和字节如何组织为更大的分组,称为包;定义了寻址机制。有两个协议:IPv4 和 IPv6。在 IPv4 和 IPv6 中
数据链路层:规定一套协议,专门的给数据进行分组,以及规定不同的组代表什么意思,使双方计算机都能够进行识别,简称以太网协议
物理层:计算机之间的物理连线,光纤、宽带、网线,把计算机连接起来
Http协议和Https协议
1.Http是超文本传输协议,是明文传输,容易被钓鱼网站套取用户信息,不安全。
2.Https通过SSL+HTTP协议构建的可进行加密传输、身份认证的网络协议,实现服务器和客户端双向验证以确认对方身份,更安全。https协议需要到ca申请证书
3.http和https使用的是不同的连接方式,前者端口是80,后者是443。
4.https通信的两端都是Socket,发起通信的属客户端,等待通信请求的为服务端,数据在两个Socket 间通过IO传输。
5.Socket是应用层与TCP/IP协议族通信的中间软件抽象层,它是一组接口,属于门面模式,把TCP/IP协议族隐藏在Socket接口后面,让Socket去组织数据,以符合指定的协议。
12. 线程安全的sychronized 方式
1.并发(concurrency),就是cpu在同一时刻执行多个任务。Java并发则由多线程实现。多线程会出现死锁和脏数据这种线程安全问题。
2.线程安全: 在多线程中,永远保证程序的正确性。只有存在共享数据时才需要考虑线程安全问题
3.解决机制
a) synchronized关键字,是实现线程同步的基本手段,被synchronized修饰的区域每次只有一个线程可以访问,达到线程安全的目的,底层实现是通过锁机制来保证,如下:
sychronized method(){}
sychronized (object Reference) {}
static synchronized method(){}
sychronized(classname.class)
前两者是该对象锁,后两者是类锁。
b) 定义常量。final static等
c) 使用ReentrantLock可重入锁
13. 说一下Java中提供的几种线程池,各自特点
当线程特别多的时候,可能会超出系统承载能力。而线程的创建和销毁非常耗费资源。如果在系统启动时就维持几个固定的线程,后面有新的任务到来就分配这些线程来执行操作,操作完成后继续等待新的任务,这些线程就组成了一个线程池。
通常利用Executors去创建不同配置的线程池, Executors提供了五种不同的线程池创建配置
① newCachedThreaPool(),用来处理大量短时间工作任务的线程池,它会试图缓存线程并重用,当无缓存线程可用时,会创建新的线程;当线程闲置的时间超过60秒,则被终止并移出缓存
② newFixedThreadPool(), 拥有固定线程数的线程池,线程池的大小,可以随意设置,也可以和cpu的核数量保持一致,
③ newSingleThreadExecutor(),线程数目为1,因此所有的任务是顺序执行
④ newSingleThreadScheduledExcutor()和newScheduleThreadPool(),可以定时或者周期性的工作调度,前者是单一工作线程,后者是多个工作线程
⑤ newWorkStealingPool(),Java8新特性,内部构建ForkJoinPool,利用Work-Stealing算法,并行的处理任务,不保证处理顺序
14. 说一下Android中的常见几种进程间通信方式
1、用Bundle的方式
在Android中三大组件(Activity,Service,Receiver)都支持在Intent中传递Bundle数据,Bundle实现了Parcelable序列化接口,可以很方便的在不同的进程之间进行传输。
2、使用文件共享的方式
将对象序列化之后保存到文件中,在通过反序列,将对象从文件中读取出来。
3、Content Provider
四大组件之一,底层是Binder,为其他APP提供数据。继承ContentProvider实现6个方法,onCreate是主线程回调,其他方法运行在Binder之中。注册时提供authorities属性,访问时通过Uri.parse("content://authorities")。有query,delete,insert等方法,用数据库作为数据源,也可用文件,内存数据
4、AIDL 可以简单分为服务端和客户端,类似于Socket ,实现通信
15. 手写一个选择排序
public static void selectSort(int[] arr) {
for (int i = 0; i < arr.length - 1; i++) {
for (int j = i + 1; j < arr.length; j++) {
//比较元素如果标号大的元素比标号小的大则交换两个元素的位置
if (arr[j] < arr[i]) {
int temp = arr[i]; //交换两个元素的位置
arr[i] = arr[j];
arr[j] = temp;
}
}
}
}
16. 聊一下Android中的6789新特性对开发的影响
6.0部分新特性
运行时权限 6.0(API 级别 23)版本以后,在运行时要检查和请求危险权限。检测用checkSelfPermission(),申请用requestPermissions()。
取消支持Apache HTTP客户端,改用 HttpURLConnection
2、7.0部分新特性
禁止在应用外部公开 file:// URI。如果包含文件 URI 的 intent 离开本应用,会出现故障,并出现 FileUriExposedException 异常。通过FileProvider 类发送一项 content:// URI,授予 URI 临时访问权限来解决
3、8.0部分新特性
通知适配
安卓8.0,新增通知渠道NotificationChannel,屏蔽一些不想要的通知
安装APK
首先在AndroidManifest中添加安装未知来源应用的权限:系统会自动询问用户完成授权。保险起见再用 canRequestPackageInstalls()查询是否有此权限,如果没有要求用户授权。
静态广播无法正常接收 建议使用动态广播
4、9.0部分新特性
禁止http请求,只能用https ,通过在AndroidManifest中添加android:usesCleartextTraffic="true",继续使用http
17. 说RxJava原理?
Rxjava是一个基于事件流、实现异步操作的库,类似于Android中的AsyncTask,Handler的作用。Rxjava是一种扩展的观察者模式,整个模式中有4个角色:
1.被观察者(Observable),用来产生事件。观察者(Observer),用来接收事件,并给出响应动作。订阅(Subscribe),用来连接被观察者和观察者。事件(Event),作为被观察者和观察者沟通的载体。
2.Rxjava的执行流程:被观察者(Observable)通过订阅(Subscribe)按顺序发送事件给观察者(Observer),观察者(Observer)按顺序接收事件和作出对应的响应。
3.Rxjava的基本实现:
1. 创建Observable,它决定什么时候触发事件以及触发怎样的事件。
2. 创建Observer,Observer,它决定事件触发的时候将有怎样的行为。还可以用Subscriber代替。
3.Subscribe,用 subscribe() 方法将被观察者和观察者连接
4.线程调度-scheduler
RxJava 通过它来指定被观察者和观察者所在的线程。包括:
Schedulers.immediate(): 直接在当前线程运行,默认
Schedulers.newThread(): 启用新线程执行操作。
Schedulers.io(): I/O 操作(读写文件、读写数据库、网络信息交互等)
Schedulers.computation(): 计算所使用的 Scheduler。
AndroidSchedulers.mainThread(),在 Android 主线程运行。
使用 subscribeOn()指定被观察者所在线程,observeOn() 指定观察者所在线程
5.变换
RxJava 支持将事件序列中的对象或整个序列进行加工处理,转换成不同的事件或事件序列。
18. 说一下RxJava几个常用操作符用法以及应用场景
concat操作符
Concat先读取缓存数据并展示UI再获取网络数据刷新UI。
1、concat 实现不交错的发射两个甚至多个Observable
2、只有前一个 Observable 终止(onComplete)才会订阅下一个 Observable,
3、多个Observable的泛型应当保持一致
map操作符
可以将Observable操作的数据类型进行转换,传入的参数为Function类型。
1.map回调中,拿到传进来的数据,进行随意转换后继续发射给下一级。
2.Function泛型第一个是传进来的参数,第二个是返回值的类型
flatMap操作符
类似map。FlatMap将一个Observable变换成多个Observable,将它们合并发射。不保证事件的顺序。
使用场景:多个网络请求依次依赖
1、注册用户前先通过接口A获取当前用户是否已注册,再通过接口B注册;
2、注册后自动登录,先通过注册接口注册用户信息,注册成功后马上调用登录接口进行自动登录。
concatMap操作符
concatMap和flatMap几乎一样,它能保证事件的顺序。
Flowable背压
Flowable返回值为Publisher或其实现类。Flowable是publisher的实现类,少写一个for循环,用了forArray()方法。解决背压问题
19. 写出Retrofit常用注解至少6个,注解写法以及中文解释
@Query
用于拼接Url路径后面的查询参数,一个@Query相当于拼接一个参数,多个参数中间用,隔开。
@QueryMap
主要的效果等同于多个@Query参数拼接,参数以map的形式传入,以Map的键值对为参数传入,只用于GET请求(@Query, @QueryMap)
@Field 用法类似于@Query 但只用于POST请求
@FieldMap
和QueryMap用法一样以Map形式传入键值对拼接请求参数
只用于POST请求,必须添加@FormUrlEncoded要不然会报异常(@Field, @FieldMap)
@FormUrlEncoded
表示这个请求为表单请求,如果在使用POST请求时不添加这行会报异常
Java.lang.IllegalArgumentException: @Field parameters can only be used with form encoding.
@Path
用于替换Url路径中的变量字符。可以使用在Url里添加{page} 然后在参数里@Path("page") 类型 参数名 声明这个page是一个拼接参数,注意使用@Path时,path对应的路径不能包含”/”,不然每个加到host Url后面的东西都会被省略掉
@Url
@Url是动态的Url请求数据的注解
@Multipart
标记这个请求用于文件传输,可以用@Part("字段名") Multipart.Part 参数名 来传入文件参数,也可以用 RequestBody来传文件
@Streaming
标记说明要把请求的返回数据转换为IO数据流 在文件下载时使用
@Headers/Header
@Headers传入多个头信息以{}来括住头信息 以,号隔开
@Header 传入单个头信息 以"键:值"的形式传入
20. MVP和MVC区别
MVC虽然将界面和逻辑分离,但并没有完全起到想要的作用。View对应的XML文件做的事情很少,主要由Controllor对应的Activity做, Activity变成View和Controllor的合体。小型项目,MVC没任何问题。Activity臃肿点没关系。逻辑比较复杂的大项目,一个Activity几千行代码就不行了
MVP适用于大项目。Activity直接当做View使用,P-Presenter代替MVC中C。View和Model不直接通信,所有交互都通过Presenter来解决。为了复用和可拓展,MVP基于接口设计。优点:提高代码复用性、增加可拓展性、降低耦合度、代码逻辑更加清晰。缺点:增加了很多的接口和实现类。代码逻辑虽然清晰,但是代码量要庞大一些。