笔记记录

001.Android 高级开发面试题以及答案整理
002.Android 高级面试高频知识点
003.106道Android核心面试题及答案汇总

1.AsyncTask 用法

onPreExecute()
在UI thread调用 显示一个进度条

doInBackground(void......params)
通过调用publishProgress()方法实时更新进度- 触发onProgressUpdate

onProgressUpdate(Integer...values)

onPostExecute(Boolean result) 更新UI

public class JniTest{

private JniTest (){}
}

2.JNI用法
(1).新建一个jniTest文件
public class JniTest{
private JniTest(){}
private static JniTest instance=null;

public static JniTest getInstance(){
    if(instance==null){
         instance=new JniTest();
     }
     return instance;
}
 static{
     System.loadLibrary("JniTest");
 }  
 public static native String getJniString();

}

(2).build--->make project 在build目录下找到生成的JniTest.class文件

(3).切换到更目录下,执行javah -jni com.example.firstndk.JniTest 生成
com_example_firstndk_JniTest.h文件

(4).新建一个JNI文件夹,并在此文件夹下来新建一个.c文件,将.h文件中的内容拷贝到
.c文件中,并且实现里面的空方法。

(5).在JNI文件下新建android.mk和application.mk文件,然后Terminal切换到JNI目录下,
执行ndk-build ,生成so库文件

1.新建一个JniTest class类
public class JniTest{
public static native JniString(){}
static{
System.loadLibrary("JniTest")
}
}

2.执行build--make project 在bulid文件夹下来会
生产 jniTest.class文

3.在命令终端中,cd 切换到当前目录,执行
javah -jni com.example.JniTest.class
生成 com_example_JniTest.h文件,

4.新建一个JNI文件夹,创建一个.c文件,把.h文件里面的代码
复制到.c文件,实现里面的 getJniString()方法,

5.执行build---->rebulid project,会在build文件夹下面生产多个.so文件】

3.AIDL用法
3.1.新建一个aidl的文件,同时建立一个aidl的接口文件,比如BookManager.aidl,如果是Bean类型,必须parcelable序列化,客户端和服务端aidl文件同时存在,且是一样的。

3.2.服务端的AIDLService 要实现这个Booknamager.aidl接口,并通过onBind()方法返回该接口的实例化对象

3.3.客户端通过bindService方法建立链接,实现ServiceConnection接口,在onServiceConnected方法中把IBinder对象转换成
aidl接口的实例化对象,一旦链接成功,客户端就可以和服务端进行通信了。

private void attemptToBindService() {
Intent intent = new Intent();
intent.setAction("com.lypeer.aidl");
intent.setPackage("com.lypeer.ipcserver");
bindService(intent, mServiceConnection, Context.BIND_AUTO_CREATE);
}

1.新建一个aidl文件夹,然后新建一个.aidl的接口文件,比如BookManager.aidl文件,里面有一个BookManager接口
interface BookManager{
float getBookPrice()
String getBookName()
}
客户端和服务端同时持有aidl文件.
2.在服务端新建一个AidlService 服务,在onBind()方法中返回
BookManager接口实例
】,在AndroidManifest文件中配置AidlService的Action
3.客户端通过bindService方法连接远程远程AIDL服务,实现ServiceConnection接口,onServiceConnect()
中拿到IBinder对象,将IBinder对象转换成BookManager接口实例,
就可是服务端的getBookPrice和getBookName方法了

4.BroadCastReceiver
(1).常驻型广播-->静态注册(manifes中注册)
<receiver android:name=".MyBroadcastReceiver">
<intent-filter>
<action android:name="android.intent.action.NEW_OUTGOING_CALL" />
</intent-filter>
</receiver>

(2).非常驻型广播-->动态注册

IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(String); //为BroadcastReceiver指定action,使之用于接收同action的广播
registerReceiver(BroadcastReceiver,intentFilter);

一般动态注册的广播,要在onDestory中解除注册,否则会导致内存泄露。

常驻型广播(静态注册)和非常驻型广播(动态注册
【registerReceiver(broadcastReceiver,intentFilter)】)

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

(1).ContentProvider的作用是为不同的应用之间的数据共享,提供统一的接口

(2).自定义
MyContentPovider extends ContentProvider{

指定authority="com.shuijian.authority"

实现 inster,delete,update,query

}

(3).其他应用操作ContentProvider中的数据

获得contentResolver=getContentResolver();

根据authority="com.shui.jian.authority"生成一个Uri,contentResolver通过
这个Uri就可以操作
其他应用中的ContentProvider中的数据了,实现了数据的共享。

6.设计模式

A:单例模式7种(getInstance 方法一定要是public)
饿汉式
(1).
public class SingleTon{
private SingleTon(){}
private static SingleTon instance=new SingleTon();

private static getInstance(){xxxxxxxxx

 return instance;

}

}

(2).静态代码块
public class SingleTon{
private SingleTon(){}
private static SingleTon instance;
static{
instance=new SingleTon()
}
private static getInstance(){ xxxxxx
return instance;
}

}
(3).静态内部类(holder)
public class SingleTon{
private SingleTon(){}
private static class SingleTonHolder{
private static SingleTon instance=new SingleTon();

}
private static getInstance(){ xxxxxx
return SingleTonHolder.instance;
}

}

(4)懒汉线程不安全
public class SingleTon{
private SingleTon(){}
private static SingleTon instance;

private static getInstance(){xxxxx
if(instance==null){
instance=new SingleTon();
}

 return instance;

}

}

(5)懒汉线程安全
public class SingleTon{
private SingleTon(){}
private static SingleTon instance;

private static synchrozied getInstance(){xxxxxxxx
if(instance==null){
instance=new SingleTon();
}

 return instance;

}

}
(6)懒汉线程安全
public class SingleTon{
private SingleTon(){}
private static SingleTon instance;

private static synchrozied getInstance(){xxxxxx
if(instance==null){
synchrozied(SingleTon.class){
if(instance==null){
instance=new SingleTon();
}
}
}

 return instance;

}

}
(7)
public enum SingleTon{
Instance;
}

B.工厂模式
public interface Sender{
public void send()
}

public Sender SMSSender implements Sender{

public void send(){
    System.out.print("sms);

}

}

public Sender QQSender implements Sender{

public void send(){
    System.out.print("QQsms);

}

}

(1).普通工厂模式

public class FactoryOne{

 poublic Sender produce(String type){
   if(type equals "sms"){
         return new SmsSender();
    }else if(type equals "QQ"){
 

      return new QQSmsSender();
    }

}

}

(2).工厂方法模式
public class FactoryTwo{
public Sender smsSender(){

        return SmsSender();
 }
  public Sender qqSender(){

        return QQSender();
 }         

}

(3).静态工厂方法模式
public class FactoryTwo{
public static Sender smsSender(){
return SmsSender();
}
public staic Sender qqSender(){
return QQSender();
}
}

(4).抽象工厂模式

public interface Provider{
void produce();

}

public class FactorySms implements Provider{

public Sender produce(){
        return new SmsSender();

 }

}

public class FactoryQq implements Provider{

public Sender produce(){
        return new QQSender();

 }

}

3.观察者模式
public interface Observer {
void update();
}

public interface Observerable(){

void registerObserver(Observer observer);
void removerObserver(Observer observer);
void notifyObservers();

}

public class User1 implements Observer(){
public void update(){
System.print.out("收到消息1");
}
}

public class User2 implements Observer(){
public void update(){
System.print.out("收到消息2");
}
}
public class Watcher implements Observerable{
public List<Observer> list=new ArrayList<Observer>();

public registerObserver(Observer observer){
    list.add(observer);
}
  public removeObserver(Observer observer){
    list.remove(observer);
}

public void notifyObservers(){
   for(list:item){
     item.update();
   }   
}

public void opration(){

    notifyObservers();

}
}

4.适配器模式
interface PS2{ void isPS2}
interface USB { void isUsb}
public class Usber implements usb{ public void isUsb(){ }}

(1).类适配器

public AdapterOne extends Usber implements PS2{ public void isPs2{ isUsb()}}

(2).对象适配器

public AdapterOne implements PS2{ public AdapterOne(Usber usber){ this.usber=usber;} public void isPs2{ usber.isUsb()}}
(3).接口适配器

interface A { void A(),void B(),void C ,
void D(),void E(),void F()}

public abstract class Adapter implemntA{
void A(){} void B(){} void C(){}

}

public class MyAdapter extends Adpater{

  void A(){}......

}


abstract FragmentStatePageAdapter getPageTitle()

5.策略模式

6.Builder模式(AlertDialog)
AlertDialog.Builder bulider= new AlertDialog.Builder(context).setTitle(R.string.app_name).setMessage("此版本已是最新版本")
.setPositiveButton("好的", null);
AlertDialog alertDialog=bulider.show();

7.责任链模式

(1).构造Request{ name ,reason,days, groupLeaderInfo ,managerInfo,departLeaderInfo}对象和Result{ isRatify ,info}结果对象

(2).interface Chain {
Request request();//获取当前的Request
Result proceed(Request request)//转发Request
}

(3).interface Ratify{ Result deal(Chain chain)}

(4). GroupLeader implements Ratify ( Result deal( return chain.proceed()or new Result))
Manager implements Ratify
CustomeLeader implements Ratify

(5)
RealChain implements Chain{
List<Ratify> list;
RealChain(List<Ratify> list,Requst requst ,int index){}
request(){ return this.request}
proceed(Request request){
Result result=null;
if(list.size>index){
Ratify ratify=list.get(index);//得到当前的责任人
Realchain chain=new Realchain(list,request,index+1);//初始化责任的位置,以便转发过来的时候使用新的责任人
result= ratify.deal(chain);
}
return result

        }

}
(6).新建链条客户端类
ChainClient {

List<Ratify> list;
addRatify(){ list.add()}//增加自定义的责任人

void executed(Request request){
List<Ratify> listNew= new List<Ratify>()
listNew.addAll(list);
listNew.add(new GroupLeader());
listNew.add(new Mannger());
listNew.add(new departLeader());
RealChain chain=new RealChain(list,request,0);
}
}

1.Request请求
2.Interface Chain{
Request request(){}
Result proceed(Request request){}
}
3.Interface Ratify{ Result deal(Reqeust request)}

4.GroupLeader ,DepartLeader{
Result deal(Chain chain){
Request request=chain.request;
if(request.getDays>3){
return chain.proceed(request);
}
return Result(true,"早去早回")
}
}

  1. RealChain implement Chain{
    RealChain (list,index,request){}
    Request request(){}
    Result proceed(Request request){
    RealChian chain=new RealChain(list ,request,index+1)
    Ratify ratify=list.get(index)
    Resutl result= ratify.deal(chain);
    return result;
    }
    }
    new RealChain(list,request,index).process(request)

8.代理模式

public DynamicProxyHandle implements InvocationHandler{
//invocationHandler持有被代理类的对象
public DynamicProxyHandle(Object obj){
this.obj=obj;
}
public Object invoke(Object proxy,Method method,Object[] args){

     Object proxy=method.invoke(obj,args);

     return proxy;

}
}

IBuy home=new Home();

DynamicProxyHandler dynamicHandler=new DynamicProxy(home);

Ibuy dynamicProxy=Proxy.newProxyInstance(home.getclass.getclassLoader,new Class[]{IBuy.class},dynamicHandler);

dynamicProxy.buy();

【Proxy.newProxyInstance(classLoader,class[],myInvocationHandler)】

10.SQLite
(1).创建一个extends SQLiteOpenHelper的类,并实现onOnCreate(建立表格的代码)和onUpgrade(删除原来表格,重新建立表格)方法。

当表结构发生变化的时候,会自动触发onUpgrad()方法,删除原来的表,并重写创建新的表结构。

(2).在创建一个OrderDao用于处理所有的数据操作。
insert ,delete ,update, search

11.XML解析 解析速度快,占用内存少,一旦开始无法暂停
(1).Sax解析,基于DefaultHandler,继承DefaultHandler 实现5大方法

5大方法:startDocument endDocument startElement endElement characters 函数驱动型

(2).Dom解析 占用的内存比较大,容易OOM 双层for循环, getElementByTagName()遍历

(3).解析速度快,消耗内存少,很灵活,Pull解析 提供了开始标签
4大标签:START_DOCUMENT, END_DOCUMENT,START_TAG,END_TAG,while循环,更具标签进行解析,可以根据需要跳出解析(parse.next)

12.Git常用命令

git init
git add index.html
git commit -m " beizhu"

git commit -am "添加并提交"

git log git status 项目目前的状态

git branch 查看当前分支

git branch develop 创建分支

git branch develop origin/test

git checkout develop 切换倒develop分支

git checkout -b develop 创建develop并切换到develop

git merge develop

git branch -d develop 删除本地分支

git branch -r -d origin/develop 删除远程分支

git push -u origin master

git remote add origin http://自己的仓库地址 注册远程版本库的地址

git remote remove origin 删除远程版本库地址

git tag 1.0

git push origin 1.0

git show 1.0

13.Java面向对象

(1)封装
属性封装(private protected public )
方法封装
内部类(成员内部类,静态内部类,方法内部类)

(2)继承

(3)多态

引用多态:Animal animal=new Animal()
Animal dog=new Dog();
方法多态:

Animal animal=new Animal() 可以访问Animal本类中的非private属性和方法

Animal dog=new Dog(); 可以只能访问Animal本类中的非private属性和方法,如果有重写父类的方法,调用的时调用的自己重写的,还有自己添加的方法和属性

14.Java泛型
(1).泛型类
public class Generics<T>{ private T key ; }
(2).泛型接口
public Interface Generics<T> { public T next();}
(3).泛型方法
public <T> T getKey(T t){}
(4).通配符和上下边界
Generics<?>

上边界:Generics<? extends T> 只能传入T的子类
下边界:Generics<? super T> 只能传入T的父类

15.抽象类和接口的区别
(1).抽象类只能单继承,而接口却可以多实现

(2).抽象类中啥都有,但是抽象接口中一般不能有非抽象的方法。

(3).抽象类时对类的抽象,接口是对行为的抽象。(Door open close alarm)
【抽象类是对类的抽象,接口时对行为的抽象,抽象类只能单继承,
而接口可以多实现,接口中只能有变量或者未实现的方法,
但是抽象类中什么都可以有~】

16.Java集合
(1)List
ArrayList 非同步的 基于动态数组 可以随机访问

LinkedList 非同步的 基于双向链表 不可以随机访问,必须从开头或者结尾遍历列表 Collect.synczoiedList()变成同步列表

Vector 是同步的,其余和ArrayList一样

Stack 继承自Vector ,提供pop push ,peek,empty,search方法
(2).Set 【Set集合都是非线程安全的】
HashSet 非同步,无序,可以插入null值。【底层HashMap】
LinkedHashSet 非同步,有序,可以插入null值。【底层LinkedHashMap】
TreeSet 非同步,有序,可以实现自然排序和定制排序。【底层TreeMap】
(3).Map
HashMap 非同步,无序,key,value都可以为null
LinkedHashMap 非同步,有序, key,value都可以为null
Hashtable 同步的, 无序的,key,value都不能为null
TreeMap 非同步,有序的【支持自然排序和定制排序】 【红黑二叉树】

17.Handler和Looper,Message之间的关系
https://juejin.cn/post/6844903783139393550
(1).ActivityThread类 App进程的初始化类,开启死循环
Looper.prepareMainLooper() 【创建Looper,并通过ThreadLocal类
通过WeakReference,set ,get方法把当当前线程和Looper对象进行绑定】
Looper.loop();【开启死循环】

(2).new 一个Hanlder对象的时候,构建方法中对Looper和MessageQueue进行了初始化,
当我们调用handler.sendMessage()---->enqueueMessage(),将此Message注入到
Looper所在的MessageQueue队列中

(3).一旦Looper所在的MessageQueue队列中有message,loop()死循环方法中,通过

queue.next拿到消息,如果消息不为null,那么msg.target.dispatchMessage()处理消息,

dispatchMessag内部会调用handlerMessage()方法。
(4).Handler在子线程中使用:
class LooperThread extends Thread {
public Handler mHandler;
public void run() {
Looper.prepare();
mHandler = new Handler() {
public void handleMessage(Message msg) {
// process incoming messages here
}
};
Looper.loop();
}
}
(5).Handler为什么不会阻塞主线程:
MessageQueue没有消息时,
便阻塞在loop的queue.next()中的nativePollOnce()
时,主线程会释放CPU资源进入休眠状态,有消息时,会调用
nativeWake唤醒。

Handler导致内存泄露怎么解决:
https://www.jianshu.com/p/804e774d9f76
静态内部类+弱引用【java中只有静态内部类不会持有外部类引用,
而普通内部类会持有外部类的引用】
private static class AppHandler extends Handler {
//弱引用,在垃圾回收时,被回收
WeakReference<Activity> activity;

    AppHandler(Activity activity){
        this.activity=new WeakReference<Activity>(activity);
    }

    public void handleMessage(Message message){
        switch (message.what){
            //todo
        }
    }
}

18.自定义View和ViewGroup
(1).4个构造方法
new ,AttributeSet ,view 有style,api>=21且view有style属性的时候调用

(2).onMeassure()
specMode=MeasureSpec.Exactly 精确值 match_parent
specMode=MeasureSpec.AT_MOST 取最大值
specMode=MeasureSpec.UNSPECIFIED 父容器对当前的View不限制

setMeasureDimension()设置View大小

onDraw View disPatchDraw ViewGruop

invalidate主线程 postInvalidate子线程

自定义属性attrs.recycle()// 进行对象回收

onLayout()中child.layout(), rquestLayout();

19.Android间的跨进程通信 https://www.cnblogs.com/andy-songwei/p/10256379.html
(1).Activity可以跨进程调用其他应用程序的Activity;
打电话 startActivity()来启动另外一个进程的Activity。

Intent callIntent = new Intent(Intent.ACTION_CALL, Uri.parse("tel:12345678"); 隐式Intent
startActivity(callIntent);
(2)ContentProvider可以跨进程访问其他应用程序中的数据(以Cursor对象形式返回),
当然,也可以对其他应用程序的数据进行增、删、改操作;
Android系统本身提供了很多Content Provider,例如,音频、视频、联系人信息等等。我们可以通过这些Content Provider获得相关信息的列表。这些列表数据将以Cursor对象返回。因此,从Content Provider返回的数据是二维表的形式。

(3).Broadcast可以向android系统中所有应用程序发送广播,
而需要跨进程通讯的应用程序可以监听这些广播;
广播是一种被动跨进程通讯的方式。当某个程序向系统发送广播时,其他的应用程序只能被动地接收广播数据。这就象电台进行广播一样,听众只能被动地收听,而不能主动与电台进行沟通。

(4)Service这种可以跨进程通讯的服务叫AIDL服务。
注意普通的Service并不能实现跨进程操作,实际上普通的Service和它所在的应用处于同一个进程中,而且它也不会专门开一条新的线程,因此如果在普通的Service中实现在耗时的任务,需要新开线程。
要实现跨进程通信,需要借助AIDL(Android Interface Definition Language)。Android中的跨进程服务其实是采用C/S的架构,因而AIDL的目的就是实现通信接口。

Socket 其实也可以实现跨进程调用,但是一般使用在网络通信中。

20.Android多线程实现
(1).继承Thread类

(2).实现Runable接口

(3).线程池

Executors.newFixedThreadPool 定长线程池,可以控制最大并发数,超出的线程会在队列中等待

Executors.newScheduledThreadPool 带有周期性质的定长线程线程,支持定时和周期任务的执行

Executors.newCachedThreadPool 可缓存的线程池,如果线程池长度超多处理的需要,可以灵活回收空闲线程,
如果没有可以回收的,也可新建线程。

Executors.newSingleThreadExecutor 单线程化的线程池,他确保了所有的任务都在一个线程中执行,不存在线程同步的问题

5个参数
new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>(),
ThreadFactory,
RejectedExecutionHandler


1.newFixedThreadPool coreThread=2 ,nocoreThread=2
2.newSchduledThreadPool coreThread=2 ,nocoreThread=Integer.maxvalue
3.newCacheThreadPool coreThread=0,nocoreThread=Integer.maxvalue
4.newSingleThreadExcutor coreThread=0,nocoreThread=0

21.MVC模式,MVP模式,MVVM模式

MVC模式
Modle JavaBean
View xml
Controler Activity业务逻辑,数据处理,UI处理
特点:所有的数据处理,UI处理都在Activity中,导致Activity上千行代码,非常冗余

MVP模式 compositeSubscrition(Rxjava1) compositeDisposed(Rxjava2)
BasePresenter{ addDisposed() removeDisposed(compositeDispose.disposed())}

BaseView { showLoading() , hideLoading()}

HomePresenter接口 HomeView接口

abstract BaseActivity<P extends BasePrestener> P createPresenter (){ new HomePresenter(this)};

MVVM模式
BaseViewModel{ addDisposed removeDisposed}

abstract BaseActivity<M extends BaseViewModel> M createViewModel() onDestory { viewModel.removeDisposed()}

HomeViewModel {
HomeViewModel(Activity context,ViewDataBinding databing){}

context.showDialog()
addDisposed{}   处理各种请求
context.disDialog() 

}

RecycleView多布局
onBindViewHolder onCreateViewHolder
ItemFruitBinding itemFruitBinding = DataBindingUtil.inflate(inflater, R.layout.item_fruit, parent, false);
return new FruitViewHolder(itemFruitBinding);

((FruitViewHolder) holder).getBinding().setItem(fruitBean);
((FruitViewHolder) holder).getBinding().executePendingBindings(); //解决databinding闪烁问题

22.框架原理
Glide
(1).三级缓存
内存缓存(skipMemoryCache(true))
磁盘缓存 diskCacheStrategy(DiskCacheStrategy.None)

DiskCacheStrategy.None 不缓存

DiskCacheStrategy.All 缓存所有

DiskCacheStrategy.RESULT 缓存转换过的

DiskCacheStrategy.SOURCE 只缓存原图
网络读取
默认的内存磁盘缓存目录:data/data/包名/cache/image_manager_disk

默认的内存磁盘缓存目录:Android/data/包名/cache/

(2).源码分析
Glide绑定生命周期,Glide.with()根据传入的context对象和当前的线程创建不同的

RequestManager实例,如果是在UI线程中,context是Activity,则会创建一个能感知

Activity生命周期的RequestManager,如果context是Fragment,则会创建一个能感知

Fragment生命周期的RequestManager,如果是在非UI线程中或者传入ApplicationContext,则会一个applicationManager

对象,能感知application的生命周期,在创建RequestManager的同时,也会创建一个

SupportRequestManagerFragment,里面有onAttach,onStart,onStop,onDestory,onDetach等生命周期的方法,停止加载
图片,释放资源。

与Picasso的对比:
Glide可以加载Gif,Picasso不能.

Picasso.with()只能接受context作为参数,但是glide的可以是
context,activity,fragment glide能根据context的类型动态的
加载和释放资源,更加灵活。

23.Retrofit2.0
(1).创建和用法
mRetorift=new Retrofit.Builder().baseUrl(Base_URL).client(new OkHttpClient())
.addConvertFactory(GsonConverterFactory.create())
.addCallAdapterFactory(Rxjava2CallAdapterFactory.create()).build().

Get请求
@GET("article/list/{type}?")
Call<QiushiModel> getInfoList(@Path("type") String type, @Query("page") int page);

GET请求提交数据
@GET
("MyWeb/RegServlet") Call<ResponseBody> getRegInfo(@QueryMap Map<String, String> map);

@GET
Observable<CheckVersionBean> getCheckVersion(@Url String url);

Post上传多个文件,同时上传表单数据:
@POST("MyWeb/UPloadServlet")
Call<ResponseBody> postUploadFilesMultipartBody(@Body MultipartBody multipartBody);}

@POST("/member/login")
Observable<UserBean> getLogin(@Body RequestBody requestBody);

@FormUrlEncoded
@POST("MyWeb/RegServlet")
Call<ResponseBody> postFormFieldMap(@FieldMap Map<String , String> map);

(2).动态代理(代理类ApiService在程序运行时动态生成,这种方式就叫做动态代理)
public <T> T create(final Class<T> service) {
Utils.validateServiceInterface(service);
if (validateEagerly) {
eagerlyValidateMethods(service);
}
return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[] { service },
new InvocationHandler() {
private final Platform platform = Platform.get();

      @Override public Object invoke(Object proxy, Method method, Object[] args)
          throws Throwable {
        // If the method is a method from Object then defer to normal invocation.
        if (method.getDeclaringClass() == Object.class) {
          return method.invoke(this, args);
        }
        if (platform.isDefaultMethod(method)) {
          return platform.invokeDefaultMethod(method, service, proxy, args);
        }
        ServiceMethod<Object, Object> serviceMethod =
            (ServiceMethod<Object, Object>) loadServiceMethod(method);
        OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
        return serviceMethod.callAdapter.adapt(okHttpCall);
      }
    });

}

Proxy.newProxyInstance(classLoader,class[],new InvocationHanlder({
public object invoke(){
return ;
}

}))

24.Rxjava 类似于观察者模式,是一个可以完成异步任务,基于事件的程序库。
(1).
Observable(被观察者)
Observer 观察者 Consumer 消费者,顾客 ,Subscriber 订阅者
subscribe 订阅
Map遍历List<Student>的每门课程的成绩
Observable.form(studentList).map(new Func1(Student,List<Course>){

             public List<Course> call(student){
                   return student.getCourseList();
             }

}).subscribe(new Action1<List<Course>>(){
public void call( List<Course> courseList){
for(){
course.getScore
}
}
})

flatMap遍历List<Student>的每门课程的成绩
Observable.form(studentList).flatmap(new Func1(Student,Observable<Course>){
public Observable<Course> call(student){
return Observable.from(student.getCourseList);
}
}).subscribe(new Action1<Course>(){
public void call(Course course){
course.getScore
}
})

(2).取消订阅
取消订阅:
!dispose.isDisposed dispose.disposed();

compositeDispose.disposed();

compositeSubcrition.unScribe();

(3)操作符:
just ,from ,create map floatMap

map:将一种类型的数据转换成另外一种类型的数据。Integer, String
Observable.just(666).map(new Func1<Integer, String>() {
@Override
public String call(Integer integer) {//Integer---->String
return integer+"";
}
}).map(new Func1<String, Long>() {
@Override
public Long call(String s) {
return Long.parseLong(s);
}
}).subscribe(new Action1<Long>() {
@Override
public void call(Long aLong) {
Log.i(TAG,"call:"+aLong);
}
});

floatMap:将原数转换成新的Observable Student, Observable<Course>

List<Student> students= DataUtils.getStudentList();
Observable.from(students).flatMap(new Func1<Student, Observable<Course>>() {
@Override
public Observable<Course> call(Student student) {
return Observable.from(student.getCourses());
}
}).subscribe(new Action1<Course>() {
@Override
public void call(Course course) {
Log.i("TAG","couseName:"+course.getCourseName);
}
});
Map: Observable.form(students).map(new Func1(Student,List<Cource>){
pulbic List<Course> call(Student student){
retrurn student.getCourseList()
}
}).subcribe(new Action1(List<Course> courseList){
courselist.foreach{
course.getName()
}
})

(4).线程调度
Scheduler.io()
AndroidSchedulers.mainThread()
Observable.just(1, 2, 3, 4)
.subscribeOn(Schedulers.io()) // 指定 subscribe() 发生在 IO 线程
.observeOn(AndroidSchedulers.mainThread()) // 指定 Subscriber 的回调发生在主线程
.subscribe(new Action1<Integer>() {
@Override
public void call(Integer number) {
Log.d(tag, "number:" + number);
}
});

25.Okhttp (RequestBody,MultipartBody)
(1).构建请求的方式
new Okhttp().newCall(new Reuqest.Builder().url.post(requestBody).build()).enqueue(new Callback(){

 onFailture()
 
 onResponse()

}))

(2).原理

new Okhttp().newCall(request)--->RealCall()---->

同步--->execute()

异步---enqueue()----->dispatcher---->execute()

execute---> getResponseWithInterceptorChain()

getResponseWithInterceptorChain()----> new List<interceptors>().addAll(自定义的责任人)

RetryAndFollowUpInterceptor 重试,重定向

BrideInterceptor 桥接,添加http请求头【host请求头】

CacheInterceptor 处理缓存,判断是否需要缓存

ConnectInterceptor 建立https连接

CallServerInterceptor ----->Response {code ,message ,header,body}

RealInterceptorChain ----->递归调用,index+1
RealInterceptorChain next = new RealInterceptorChain(interceptors, streamAllocation, httpCodec,
connection, index + 1, request, call, eventListener, connectTimeout, readTimeout,
writeTimeout);
Interceptor interceptor = interceptors.get(index);
Response response = interceptor.intercept(next);

25.热更新的实现原理
(1).AndroidFix (https://github.com/alibaba/AndFix
A:加载方式(init loadPatch addPatch)

mPatchManager = new PatchManager(this);
mPatchManager.init("1.0");
mPatchManager.loadPatch();
String patchFileString = Environment.getExternalStorageDirectory()
.getAbsolutePath() + APATCH_PATH;
mPatchManager.addPatch(patchFileString);

B:生成补丁的命令

apkpatch.bat -f 新apk -t 旧apk -o 输出目录 -k app签名文件 -p 签名文件密码 -a 签名文件别名 -e 别名密码

将生成的补丁手动放到SD目录下或者自己从云端下载下来。

C:原理
通过Native层,使用指针替换的方式替换bug,达到修复。
不能修改xml布局文件,资源文件无法替换

(2).Bugly热更新
A:集成方式
重写SmapleApplicationLike extends DefaultApplicationLike

配置基准thinkId,assembleRelease编译生成基准包,修改代码后,

根据基线版本生成补丁包,然后将补丁包patch_signed.apk上传。

B:原理
通过base.apk(base.dex) 和Fix.apk(fix.dex) 生成 patch.apk(patch.dex)

patch.dex和本地的base.dex 合并生成新的patch_base.dex文件,然后重新启动

就可以了。(patch.dex插入到dexElements数组的前面,同时删除旧的base.dex)

C:优势
Tinker热补丁方案不仅支持类、So以及资源的替换,
Tinker不支持修改AndroidManifest.xml,Tinker不支持新增四大组件

25.Jpush推送的实现原理
(1).从写MyJPushMessageReceiver
处理自定义消息:

if (JPushInterface.ACTION_MESSAGE_RECEIVED.equals(intent.getAction())) {
String message = bundle.getString(JPushInterface.EXTRA_MESSAGE);

if (!TextUtils.isEmpty(message)) {
PushBean mBean = mGson.fromJson(message, PushBean.class);
mNotificationUtils.simpleNotify(context, mBean);
}

用户打开通知:

JPushInterface.ACTION_NOTIFICATION_OPENED.equals(intent.getAction())

(2).登录后使用Id作为绑定的别名。

JPushInterface.setAlias(getApplicationContext(), Integer.parseInt(bean.getResultObject().getUserId());

集成Jpush时,我们已经把应用的包名,appkey值,发到Jpush服务端进行注册,然后本地集成了JpushReceiver的BroadCastReceiver,在onReceiver

中,通过官方提供的各种Action,分类处理各种服务端推送过来的消息。

26.Inflate解析文件的原理

inflate() ---->获取根节点的名称--->调用createViewFragTag通过class.forName反射的方式创建根View,

通过调用rInflate,遍历该View下面的子View,如果子View中还有子View,那么会递归性的调用rInflate(),

直到遍历完所有的View,不在进入while循环,最后调用parent.onFinishInflate()遍历完结

27.Java虚拟机和Delivk虚拟机的区别

(1)Java虚拟机运行的是java字节码,但是Dalvik运行的是dex文件

(2).Java虚拟机是基于栈,需要用指令来载入和操作数据,Dalvik是基于寄存器的,能有效减少指令的

分发和减少内存的读写访问。

28.Context 有哪几种,都有什么区别

(1)Application继承自ContextThemeWrap(带主题的相关类,内部包含了主题相关的接口,可

以加在主题),Activity和Service继承自ContextWrap,并不需要加载主题。

(2)生命周期不一样,applicaton和应用的生命周期绑定,但是activity和service的自身的生

命周期绑定。

(3)使用的场景也会有不一样,比如启动一个activity,show一个dialog,或者

layotuInflate解析一个文件都只能使用activity用了,application和service不可以。

(4)applicaton一个,activity和service有多个。

28.线程中sleep和wait有啥区别。

(1).一个来自Thread类,一个来自Object类

(2).sleep没有释放锁而wait方法释放了锁,使得其他的线程可以使用同步代码块,或者方法.

sleep不出让系统资源,wait进入线程池等待,出让系统资源,一直等到notify/notifyAll,

才会从新进入就绪队列等待OS分配系统资源

(3).使用范围不同,wait,notify和notifyAll只能在同步代码块,或者同步方法中使用,但是

sleep可以在任何地方使用。

(4).sleep必须要捕获异常,但是wait,notify和notifyAll不需要捕获异常。

29.queue和Stack有啥不同
(1).队列先进先出,栈先进后出
(2).队列只能在表尾进行插入,在表头的进行删除,栈只能在表尾(栈顶)进行插入和删
除操作

(3).遍历数据的速度不同
队列遍历的速度更快,从队头或者队尾开始遍历,它是基于地址指针进行遍历,不需要另外的开
辟临时空间,不影响数据的结构。
栈遍历的速度比较慢,只能从栈顶开始遍历,为了保证遍历前的一致性,需要另外开辟临时空间。

(4).队列:应用的范围也不一样,线程池,消息传递机制,以及系统中的各种资源的管理等用到的一般都是队列。

栈的:问题的求解,函数调用和递归实现,计算机中断,数据保存和恢复。

30.ArrayList和LinkedList有啥区别
(1).arrayList是基于动态数组,linkedList是基于双向链表。

(2).对于随机访问get和set,ArrayList优于LinkedList,因为ArrayList可以随机定位,
而LinkedList要移动指针一步一步的移动到节点处。

(3).对于新增和删除操作add和remove,LinedList比较占优势,只需要对指针进行修改即可,

而ArrayList要移动数据来填补被删除的对象的空间.

31.Android项目安全性(混淆,加固)

minifyEanble true

proguard-android.txt

-keep 保留某个类不被混淆

-dontwarn去除警告

android四大组件不应该被混淆

使用了自定义控件那么要保证它们不参与混淆

对第三方库中的类不进行混淆

使用了 Gson 之类的工具要使 JavaBean 类即实体类不被混淆

32.Android动画
(1).View动画
TranslateAnimation
ScaleAnimation
RotateAnimation
AlphaAnimation

AlphaAnimation alphaAnimation = new AlphaAnimation(0, 1);
view.startAnimation(animation);

(2).属性动画 3.0之后

ObjectAnimator
ObjectAnimator.ofFloat(view, "rotationY", 0.0f, 360.0f).setDuration(1000).start();

ValueAnimator
ValueAnimator animator = ValueAnimator.ofFloat(0, mContentHeight); //定义动画
animator.setTarget(view); //设置作用目标
animator.setDuration(5000).start();
animator.addUpdateListener(new AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation){
float value = (float) animation.getAnimatedValue();
view.setXXX(value); //必须通过这里设置属性值才有效
view.mXXX = value; //不需要setXXX属性方法
}
});

AnimatorSet 动画组合,时播放、顺序播放或延迟播放

ObjectAnimator a1 = ObjectAnimator.ofFloat(view, "alpha", 1.0f, 0f);
ObjectAnimator a2 = ObjectAnimator.ofFloat(view, "translationY", 0f, viewWidth);
......
AnimatorSet animSet = new AnimatorSet();
animSet.setDuration(5000);
animSet.setInterpolator(new LinearInterpolator());
//animSet.playTogether(a1, a2, ...); //两个动画同时执行
animSet.play(a1).after(a2); //先后执行
......//其他组合方式
animSet.start();

(3).帧动画
<animation-list xmlns:android="http://schemas.android.com/apk/res/android"

android:oneshot=["true" | "false"] >

<item
android:drawable="@[package:]drawable/drawable_resource_name"

android:duration="integer" />

</animation-list>

rocketAnimation = (AnimationDrawable) rocketImage.getBackground();
rocketAnimation.start();

(4).6.0之后触摸反馈动画

Ripple

<?xml version="1.0" encoding="utf-8"?>
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
android:color="#4285f4">
</ripple>

Reveal 揭露动画

ViewAnimationUtils.createCircularReveal()

Transition Animation 转场动画

你需要给共享元素的两个View设置相同的android:transitionName属性值

layout/activity_a.xml

<ImageView
android:id="@+id/small_blue_icon"
style="@style/MaterialAnimations.Icon.Small"
android:src="@drawable/circle"
android:transitionName="@string/blue_name" />

layout/activity_b.xml

<ImageView
android:id="@+id/big_blue_icon"
style="@style/MaterialAnimations.Icon.Big"
android:src="@drawable/circle"
android:transitionName="@string/blue_name" />

String transitionName = getString(R.string.blue_name);

    ActivityOptions transitionActivityOptions = ActivityOptions.makeSceneTransitionAnimation(MainActivity.this, sharedView, transitionName);
    startActivity(i, transitionActivityOptions.toBundle());

SVG矢量动画,通过Path路径构建动画

33.安卓内存优化
https://blog.csdn.net/tuke_tuke/article/details/52316285

Bitmap不被使用的时候recycle掉

Cursor和I/O流及时关闭

BroadCastReceiver、Service

线程不再需要继续执行的时候要记得及时关闭,开启线程的时候,使用线程池

使用Rxjava做网络请求的时候,在Activity销毁的时候,取消订阅

使用FindBus和Lint代码检查工具,提高代码质量

34.UDP&TCP的区别和应用场景
https://www.cnblogs.com/williamjie/p/9390164.html

相同点:UDP协议和TCP协议都是传输层协议
打电话之前先拨号
TCP:面向连接的,可靠性高,基于字节流的,中间会有三次握手来建立连接,但是占用的系统资源高,容易被攻击,。
Socket socket = new Socket("111.111.11.11", 12306);//111.111.11.11为我这个本机的IP地址,端口号为12306.
socket.getInputStream
socket.getOutputStream

实时视频会议
UDP是面向非连接的,可靠性低,基于字节流,在网络不好的时候,容易丢包,但是传输速度很快,效率比较高,基于用户数据报的。
DatagramPacket packet = new DatagramPacket(bytes, bytes.length, address, 12306);
socket.send(packet);
socket.receive(receiverPacket);

TCP/IP五层模型详解
应用层 各种网站,App
传输层 TCP / UDP协议
网络层
数据链路层
物理层 计算机 + 光缆 +计算机

TCP的三次握手4次挥手过程
https://www.cnblogs.com/bj-mr-li/p/11106390.html

35.http和https协议
https://juejin.cn/post/6844904065227292685
https://www.jianshu.com/p/7a40e874f6c2?utm_source=oschina-app

https客户端和服务端建立SSL连接的过程:

(1).客户端发起请求,服务端会把公钥发给客户端。

(2).android客户端利用本地证书对公钥进行校验,合法的话,生成一个随机值并用服务端给的公钥进行加密,

然后传给服务端,服务端利用私钥进行解密,此时客户端和服务端都有这个随机值,然后利用这个随机值作为

二边的私钥,建立SSL连接,开始通信。

36.Kotlin

(1).?. null safety,object直接创建单例,compain Object (相当于static,可以通过类.方法名调用)
属性委托(protected var isLogin:Boolean by Preference(Constant.LOGIN_KEY,false))

(2).主要构造函数和次级构造函数(Secondary Constructor是定义在类体中。第二,Secondary Constructor
可以有多个,而Primary Constructor只会有一个。)
主要构造函数:
class Person constructor(username: String, age: Int){

private val username: String

private var age: Int

init{
this.username = username

this.age = age

   }

}

class Person (username: String, age: Int){

private val username: String

private var age: Int

init{
this.username = username

this.age = age

   }

}
次级构造函数:
class User{

private val username: String

private var age: Int

constructor(username: String, age: Int){

this.username = username

this.age = age

}

}

(3).为什么要转战kotlin
kotlin比Java要简单。它去除了很多Java里面的冗余代码,而且有很多新的特性
比如说不用findViewById,在xml定义Id之后,直接可以在代码中引用,
类扩展,直接给类添加方法,而不需要继承。
fun Activity.showSnackMsg(msg:String){
val snackbar=Snackbar.make(this.window.decorView,msg,Snackbar.LENGTH_SHORT)
val view=snackbar.view
view.findViewById<TextView>(R.id.snackbar_text).setTextColor(ContextCompat.getColor(this,R.color.white))
snackbar.show()
}

(4).声明变量,支持面向对象和面向过程编程, range操作符 for(1 in 1...15)
var a:Int  kotlin类缺省是final的。因为kotlin支持多重类继承。开放类代价要比final类高很多,
如果一个类可以被继承或者方法被重写,必须open

PlayAndroid

设置白天黑夜模式:
value-night DayNight主题
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO)

37.启动模式

https://blog.csdn.net/qq_25901775/article/details/50590309

Standard 标准模式 每次启动一个Activity都会又一次创建一个新的实例入栈,无论这个实例是否存在

SingleTop 栈顶复用模式 须要创建的Activity已经处于栈顶时,此时会直接复用栈顶的Activity。
不会再创建新的Activity, onNewIntent会被回调

SingleTask 栈内复用模式 将存在栈中的Activity上面的其他Activity所有销毁,使它成为栈顶,onNewIntent

SingleInstance 单实例模式 系统会为它创建一个单独的任务栈,由于栈内复用的特性,不会创建新的Activity,除非这个独特的任务栈被系统销毁

38.Android系统架构 (https://blog.csdn.net/cpq37/article/details/5708649)

(1).Application 应用层

(2).Application Fragmework

ActivityManager PackageManager WindowManager NotificationManager

(3).Library 系统运行库

SQLite Webkit

(4).Linx内核层
Wifi Driver USB Driver CameraDriver

  1. Android性能分析
    LeakCanary 它能实时的告诉我具体哪个类发现了内存泄漏

TraceView 测量函数耗时

SysTrace

MAT

Hierarchy(hai:ra:k) Viewer 测量View的布局层次,已经每个View的刷新时间。
使用Merge,ViewStub标签优化重复的布局,尽量多使用Constraintlayout

使用自定义View

40.哪些情况可能会导致内存泄露

(1).资源使用完没有关闭
BroadCastReceiver File Crusor database Bitmap

(2).Timer或者TimeTask不使用的时候,必须取消。

(3).Handler或则Runnable做为非Static内部类可能导致内存泄漏。

41.如果避免OOM

(1).减少内存对象的暂用。
尽量少用Bitmap ,减少资源图片的大小,过大的图片可以压缩,尽量不用Enum

或者设置暂用内存较低的解码格式decode formate
ARGB_888【8bit】
RGB_564 【4bit】

(2).自定义View的时候,尽量不要在onDraw里面new 对象, 自定属性的时候,记得recycle().

(3).避免内存泄露(内存对象的泄漏,会导致一些不再使用的对象无法及时释放,
这样一方面占用了宝贵的内存空间,很容易导致后续需要分配内存的时候,空闲空间不足而出现OOM)

42.ANR怎么样避免和解决?
(1).应该避免在UI线程中处理复杂的逻辑和计算,还有耗时操作。
(2).在Activity的onCreate,onResume里面也不要做耗时的操作。尽量把耗时的操作交给异步线程。
(3).如果有耗时炒作,使用线程池或者AsyncTask处理,协程也可以~。

主线程存在耗时操作,导致阻塞
按键或触摸事件在5s内主线程没哟响应
BroadcastReceiver 前台广播在10s内,没有返回值,也会导致ANR
启动的Service在20s内没有完成,也会导致ANR

43.android线程间的通信

handler runOnUiThread view.post Rxjava .io .mainThread(线程调度)

44.Android屏幕适配
(1).尽量用dp适配屏幕,sp作为字体单位

(2).xml布局的时候,尽量使用weight

(3).代码中获取屏幕的宽高,按比例动态设置,

(4).特殊机型,可以使用value-sw1080,mipmap-w600dp

(5).约束布局

46.android进程保活机制
内存不足
省电机制
用户清理

如何保活进程:
(1).锁屏的时候,挂1像素的Activity到前台,提高进程的优先级,锁屏的时候关闭。

(2).启动一个前台Service,Service。SERVICE_ID=1

(3).双进程拉活。

(4).监听开机,锁屏等系统广播拉活。

(5).监听其他大厂的广播,拉活。

47.打包优化

代码混淆
去除无用的资源 shrinkResouce true
图片压缩
so 库配置 abiFilter armeabi armeabi-v7a

把图片放在云端,通过链接联网加载。

48.ButterKnife源码分析 https://www.cnblogs.com/tony-yang-flutter/p/12483127.html

ButterKnife.bind(this)----> 会构造一个包名+类名+_ViewBinding的构造函数类,通过constructor.newInstance()返回这个绑定的对象。

MainActivity_ViewBind.java ,这个类在编译的时候,通过ButterProcessor生成的,继承了抽象类AbstractProcessor,AbstractProcessor实现了

Processor接口,init getSupportAnnotationTypes getSupportedAnnotations ,process

最重要的就是Process方法,,首先通过findAndParseTarget()得到一个bindingMap对象,这个对象 类名称(key), 注解属性(BindingSet),

BindingSet存储的是生成类的基本信息以及注解元素的基本信息,通过遍历这个bindingMap生产对应的java文件。

当我们调用ButterKnife的bind()方法的时候,它会根据类的全限定类型,找到相应的模板代码。

45.GreenDao ,Realm数据库 对象关系数据映射
Realm和GreenDAO有很大的不同,Realm本身就是一种数据库,而且是可以支持跨平台的数据库,比SQLite更轻量级,速度也更快,支持JSON格式、数据变更通知、数据同步等等特性.

https://www.jianshu.com/p/12c46d38f6a9

@Entity
public class Student {
@Id(autoincrement = true) Long id;
String name;
int age;
String grades;
@ToMany(referencedJoinProperty = "studentId")
List<Course> courseList;
}
生成 DaoMaster DaoSesion 各种Dao类

Realm.init(this);支持新增字段
Realm.setDefaultConfiguration(configuration);

public class Student extends RealmObject{}
realm.executeTransaction(new Realm.Transaction() {
@Override
public void execute(Realm realm) {
Student student = new Student();
student.setName("小明");
student.setAge(18);
student.setGrades("一年级");
realm.copyToRealm(student);
}
});

49.Flutter

widget在flutter里基本是一些UI组件

有两种类型的widget,分别是statefulWidget 和 statelessWidget两种

statelessWidget不会自己重新构建自己,但是statefulWidget

Hot Reload

50.Glide 三级缓存源码分析
https://www.jianshu.com/p/ba7f38ede854

51.App启动优化。

1s 左右的白屏闪现, 低版本黑屏

windowBackground windowIsTranslucent

没有白屏但是中间还是有一小段不可见,增加了Splash 的广告页,增加了倒计时

TraceView检测函数的耗时情况,一个是懒加载,在一个就是使用线程池初始化 newSingleExcutor

精简xml布局

52.Lrucachef原理
https://blog.csdn.net/Coo123_/article/details/105143502

52.livedata保存数据,可以感知Activity的生命周期,是一个可被观察的数据持有类,
因此可以做到仅在组件处于生命周期的激活状态时才更新UI数据。
子线程:postValue
主线程:setValue
粘性事件
livedata.observer(this,Observer(){
onChange(){

  } 

})

53.Lifycycle使用和原理(解耦页面和组件)
Activity,Fragment 都实现了LifecycleOwner,标志着他们都是
具有lifecycle的组件。
Lifecycle是抽象类,唯一的具体实现类为LifecycleRegistry
A:注册流程:
getLifecycle().addObserver(LifecycleObserver observer)
getLifecycle().addObserver(MyObserver())
public class MyObserver implements LifecycleObserver {
@OnLifecycleEvent(Lifecycle.Event.ON_CREATE)
void prepare(){
}
@OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
void release(){
}
}
//addObserver注册干了二件事情
public class LifecycleRegister{
public void addObserver(observer){
ObserverWithState obstate=new ObservverWithState(observer,state)
map.add(observer,obstate);
}
}

ObservverWithState这个类,
(1).把observer转换成LifecycleEventObserver

(2).dispatchEvent(){
observer.onStateChanged(lifecycleOwner,envet)//真正调用
}

B:调用流程
1.注入了一个没有UI的ReportFragment
AppCompatActivity-->FragmentActivity-->ComponentActivity{

 onCreate(){ 
     ReportFragment.injectIfNeededIn(this);
}

}

public class ReportFragment {
onCreate(){ dispath(Lifecycle.Event.ON_CREATE)}
onStart(){dispath(Lifecycle.Event.ON_START)}
onResume(){dispath(Lifecycle.Event.ON_RESUME)}
onPause(){dispath(Lifecycle.Event.ON_PAUSE)}
onStop(){dispath(Lifecycle.Event.ON_STOP)}
onDestory(){dispath(Lifecycle.Event.ON_DESTORY)}
}
public void dispath(event){
getActivity().getLifecycle().handleLifecycleEvent(event)
}

handleLifecycleEvent(){
sync()
}
sync(){
while( map.hasnext){
map.getvalue().dispatchEvent()
}
}

dispatchEvent(){
observer.onStateChanged(licycleOwener,event)
}
class ReflectiveGenericLifecycleObserver implements LifecycleEventObserver {
Map map=new HashMap(event,method)
public void onStateChanged(LifecycleOwner source, Event event){
switch (event) {
case ON_CREATE:
map.get(event).invoke()//prepare
break;
case ON_START:
break;
case ON_RESUME:
break;
case ON_PAUSE:
break;
case ON_STOP:
break;
case ON_DESTROY:
map.get(event).invoke() //release
break;
case ON_ANY:
throw new IllegalArgumentException("ON_ANY must not been send by anybody");
}
}
}

54.ViewModel 【ViewModel 类让数据可在发生屏幕旋转等配置更改后继续留存。】
https://mp.weixin.qq.com/s/-Zxf_560jgjWo_pRhxJBew
获取ViewModel
ViewModelProvider(this).get(ScoreListViewModel::class.java)
(a):为什么Activity旋转屏幕后ViewModel可以恢复数据。
屏幕旋转的时候,会触发
onRetainNonConfigurationInstance (){
通过 NonConfigurationInstance 内部类保存ViewModelStore实例对象
}
调用ViewModelProvider(this),会先调用this.getViewModelStore(),通过
getLastNonConfigurationInstance (){
从NonConfigurationInstance 内部类中取ViewModelStore的实例对象。
}
取ViewModelStore实例对象,如果不存在就new ViewModelStore(),然后return,
因为viewmodelstore没有变化,所以可以恢复数据。

(b):ViewModel 的实例缓存到哪儿了。
ViewModel 对象存在了 ComponentActivity 的 mViewModelStore 对象中。

(c):什么时候 ViewModel#onCleared() 会被调用。
public ComponentActivity(){
getLifecycle().addObserver(new LifecycleEventObserver() {
@Override
public void onStateChanged(LifecycleOwner source,Lifecycle.Event event) {
if (event == Lifecycle.Event.ON_DESTROY) {
if (!isChangingConfigurations()) {
getViewModelStore().clear();
}
}
}
});
}
ViewModel 类让数据可在发生屏幕旋转等配置更改后继续留存。
ViewModel 只有在正常 Activity finish 时才会被清除。

55.viewModelScope是如何做到自动解绑网络请求的
调用ViewModel中的setTagIfAbsent方法返回CloseableCoroutineScope()实例。
创建一个CloseableCoroutineScope()实例,并使用map把CloseableCoroutineScope()实例存起来
(1).viewModelScope get(){
return setTagIfAbsent(JOB_KEY,
CloseableCoroutineScope(SupervisorJob() + Dispatchers.Main.immediate))
}
clear(){
map.foreach{
closeableCoroutine.close()
}
}
public class CloseableCoroutineScope:Closeable,CoroutineScope{
void close(){
coroutineContext.cancel()
}
}

56.DataBinding
双向绑定 使用ObservableFiled<String,Int,User>
单向绑定 不使用ObservableFiled就是单向绑定
mDataBind=DataBindingUtil.inflate(inflater,layoutId(),container,false)
mDataBind= DataBindingUtil.setContentView(this,layoutId())
RecycleView和DataBinding进行绑定

57.HashMap(https://juejin.cn/post/6844904084219101197
57.1.JDK1.7---数组+链表 JDK1.8---数组+链表+红黑二叉树
57.2.map.put(k,v)实现原理
前提条件,如果table等于null,那就resize扩容,初始化table
(1)首先将k,v封装到Node对象当中(节点)。
(2)然后它的底层会调用K的hashCode()方法得出hash值。
(3)通过哈希表函数/哈希算法,将hash值转换成数组的下标Index,
下标位置上如果没有任何元素,就把Node添加到这个位置上。
如果当前位置有元素,那就比较当前位置Node节点的key值和hash值,
如果相等,说明key存在,直接替换值即可,如果不存在,那说明,当前的
节点可能是TreeNode,或者链表,如果说下标对应的位置是TreeNode
(instanceof TreeNode),直接插入,
否者就一定是链表,此时,就会拿着k和链表上每个节点的k进行equal比较。
如果所有的equals方法返回都是false,那么这个新的节点将被添加到链表的
末尾(JDK1.8尾插法)。如果其中有一个equals返回了true,那么这个节点的
value将会被覆盖。【如果链表的长度大于8且数组长度大于64的时候,
就会把链表转换成红黑二叉树】
57.3.map.get(k)实现原理
(1).先调用k的hashCode()方法得出哈希值,并通过哈希算法转换成数组的下标。
(2).通过上一步哈希算法转换成数组的下标之后,在通过数组下标快速定位到某个位置上。
如果这个位置上什么都没有,则返回null,如果当前位置有元素,那就比较当前位置Node节点
的key值和hash值,如果相等,说明改节点就在table数组中,直接返回,否则,如果这个位置
上是红黑二叉树(instanceof TreeNode),就会调用getTreeNode(hash,key)返回当前节点,
否则就是链表,那么它就会拿着参数K和单向链表上的每一个节点的K进行equals,
如果所有equals方法都返回false,则get方法返回null。如果其中一个节点的K和参数K进行equals返回true,
那么此时该节点的value就是我们要找的value了,get方法最终返回这个要找的value。

57.4.hash(key)的源码
static final int hash(Object key) {
int h;
return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}
key.hashCode() 获取到的hashcode无符号右移16位并和原hashCode进行^运算 ,
这样做的目的是为了让高位与低进行混合,让两者都参与运算,以便让hash值分布更加均匀。

57.5数组索引index的计算采用的都是hash&(table.length-1)

58.ANR的常见场景
(1).5s内未响应键盘输入,或者屏幕触摸事件。
(2).Service TimeOut前台Service在20s未执行完任务,或者后台Service在200s内未执行完任务。
(3).BroadCastReceiver TimeOut前台BroadCastReceiver在10s内未处理完广播,后台BroadCastRecevier在60s
内未处理完广播。
(4).ContentProvider TimeOut在10s内没有处理完成任务
(5).大量的数据读写,耗时的网络访问,数据库,硬件操作(比如Camera)

59.JVM内存区域(https://mp.weixin.qq.com/s/8vXENzg580R7F2iNjSdHFw)
虚拟机栈 为虚拟机执行Java方法时服务
本地方法栈 为虚拟机执行Native方法时服务
程序计数器 行号指示器
堆 (对象实例和数组都是在堆上进行分配的,GC也主要对这二类数据进行回收)
本地内存

59.1.垃圾识别
引用计数法 String ref=new String("Java") ref=null
可达性分析算法 如果相关对象不在任意一个以 GC Root 为起点的引用链中,
则这些对象会被称为垃圾,被GC回收。

59.2.垃圾回收算法
(1).标记清除法(会产生内存碎片)
(2).复制算法(内存减少一半,效率低下)
(3).标记整理法(没进行一次垃圾清除,都要频繁的移动存活的对象,效率十分低下)
(4).分代收集算法
根据对象存活周期的不同将堆分成新生代(Eden区 8,S0区 1,S1区 1)和老生代
第一次垃圾回收:会把Eden区的存活的对象放到S0区,同时对象的年龄加1
第二次垃圾回收:会把Eden区和S0区的存活对象转移到S1区

59.3.对象何时晋升到老年代
(1).当对象的年龄达到了我们设定的阈值,则会从S0或者S1晋升到老年代
(2).大对象,当某个对象分配需要大量连续的内存时,此时对象的创建不会分配在
Eden区,会直接分配在老年代。

59.Validate和Synchrozied的区别(https://www.cnblogs.com/paddix/p/5428507.html
1.volatile就是轻量级的Synchrozied,只能修饰变量,方法和代码块无法修饰,
实现可见性,修改了volatile变量时会强制将修改后的值刷新到主内存中。
会导致其他线程工作内存中对应的变量值失效,因此,在读取变量的时候,就需要重新
从主内存中读值。

60.靠这70道面试题,我斩获了3个offer

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,311评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,339评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,671评论 0 342
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,252评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,253评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,031评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,340评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,973评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,466评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,937评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,039评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,701评论 4 323
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,254评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,259评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,485评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,497评论 2 354
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,786评论 2 345

推荐阅读更多精彩内容