美文网首页
面试笔记记录

面试笔记记录

作者: Owen270 | 来源:发表于2021-05-11 12:06 被阅读0次

    1.AsyncTask 用法

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

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

    onProgressUpdate(Integer...values)

    onPostExecute(Boolean result) 更新UI

    2.JNI用法
    (1).新建一个jni文件
    public class JniTest{

    private JniTest(){}
    
    public 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库文件

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

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

    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);
    }

    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中解除注册,否则会导致内存泄露。

    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 void produce(){
            return new SmsSender();
    
     }
    

    }

    public class FactoryQq implements Provider{

    public void produce(){
            return new QQSender();
    
     }3
    

    }

    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}

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

    }
    

    public class MyAdapter extends Adpater{

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

    }

    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);

    }

    }

    8.代理模式

    public DynamicProxyHandle implements 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();

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

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

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

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

    startDocument endDocument startElement endElement characters 函数驱动型

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

    (3).解析速度快,消耗内存少,很灵活,Pull解析 提供了开始标签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方法

    17.Handler和Looper,Message之间的关系
    (1).ActivityThread类 App进程的初始化类,开启死循环
    Looper.prepareMainLooper()
    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()方法。

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

    (2).onMeassure()
    specMode=MeasureSpec.Exactly 精确值
    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.newCachedThreadPool 可缓存的线程池,如果线程池长度超多处理的需要,可以灵活回收空闲线程,
    如果没有可以回收的,也可新建线程。

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

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

    new ThreadPoolExecutor(nThreads, nThreads,
    0L, TimeUnit.MILLISECONDS,
    new LinkedBlockingQueue<Runnable>());

    原理:https://www.cnblogs.com/dongguacai/p/6030187.html

    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 { loading() success()}

    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 订阅

    (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<String>

    List<Student> students= DataUtils.getStudentList();
    Observable.from(students).flatMap(new Func1<Student, Observable<String>>() {
    @Override
    public Observable<String> call(Student student) {
    return Observable.from(student.getCourses());
    }
    }).subscribe(new Observer<String>() {
    @Override
    public void onCompleted() {

                    }
    
                    @Override
                    public void onError(Throwable throwable) {
    
                    }
    
                    @Override
                    public void onNext(String s) {
                        Log.i("TAG","couseName:"+s.toString());
                    }
                });
    

    (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(自定义的责任人)

    Okhttp5大拦截器(https://blog.csdn.net/lxk_1993/article/details/101288561
    RetryAndFollowUpInterceptor 负责请求的重试和重定向

    BrideInterceptor 给请求添加对应的 header 信息,处理响应结果的 header 信息

    CacheInterceptor 根据当前获取的状态选择 网络请求 、读取缓存、更新缓存。

    ConnectInterceptor 建立 http 连接。

    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);

    Okhttp缓存 https://juejin.cn/post/6844903552339410958

    缓存主要是通过header的Cache-Control来控制,
    通过对Cache-Control进行设置,即可实现不同的缓存策略。

    max-age 访问缓存的有效时间(一般很短)

    max-state 可接受的缓存过期的时间

    有网络的时候:

    可定义网络拦截器来为Response设置缓存策略

    无网络的时候,可以通过自定义拦截器设置Request使用缓存的策略

    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

    ()),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继承自ContextTheamWrap(带主题的相关类,内部包含了主题相关的接口,可

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

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

    命周期绑定。

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

    layotuInflate解析一个文件都只能使用activigty用了,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);

    35.http和https

    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://www.cnblogs.com/claireyuancy/p/7387696.html

    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不使用的时候,必须取消,new thread。

    (3).Static Context Static Drawable 会导致内存leak.

    Static 集合类,比如ArrayList ,Vector 如果不及时的设置为null的话,

    也可能导致内存泄露。

    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里面也不要做耗时的操作。尽量把耗时的操作交给异步线程。

    按键或触摸事件在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.HashMap原理
    HashMap(https://juejin.cn/post/6844904084219101197
    JDK1.7---数组+链表 JDK1.8---数组+链表+红黑二叉树
    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的时候,
    就会把链表转换成红黑二叉树】
    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。

    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值分布更加均匀。

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

    千里马骏

    1.ConstraintLayout 布局 百分比布局

    UI适配,多屏幕适配

    2.Binder原理

    3.new OkHttp().newCall(new Request).execute()

    new OkHttp().newCall(new Request).enqueue() 按照调用方式说原理

    4.点击桌面的图标,Application启动原理。

    5.recycleview四级缓存机制 https://blog.csdn.net/u014644594/article/details/105771763
    mAttachedScrap 缓存当前页面的数据

    mCachedViews 缓存刚刚划出屏幕外的数据(2个)

    RecycleViewPool 缓存Cache中出来的数据(5)

    先充Scrap和Cache中取ViewHoder,如果没有取到,就从RecycleViewPool 中取,如果还是没有取到,就CreateViewHolder

    6.垃圾回收算法

    compare比较算法

    7.虚拟机内部区域划分

    酷派外包:
    负责哪些模块,问ListView和RecycleView缓存机制的区别。
    UI刷新的原理
    Fragment和Activity的区别
    A:生命周期不同
    B:可以在XML在灵活的添加Fragment,Activity不能,Fragment是3.0之后引入的,通过FragmentManager管理,Activity是四大组件之一,通过ActivityManager管理。
    C:从灵活性上来说,Fragment
    Context为null的原因

    OPOP外包:
    项目中的难点,如何解决的。
    自己创建线程池,需要传递哪些参数。

    OkHttp的缓存机制
    https://juejin.cn/post/6844904095233376269
    Http和Https的有什么区别。证书主要是放在服务端还是客户端?

    SoftReference
    WeakReference

    Handler导致内存泄露的例子,内部类导致内存泄露的例子。
    https://www.jianshu.com/p/b56731447179

    反射(学习一下)

    相关文章

      网友评论

          本文标题:面试笔记记录

          本文链接:https://www.haomeiwen.com/subject/uzmgdltx.html