BAT大咖助力 全面升级Android面试笔记 (自己补充)

https://blog.csdn.net/qq_23575921/article/details/78947051 原文 补充

Android任务栈

singletop(栈顶复用):Android系统内置的书签应用
singletask(栈内复用):商城首页,在分页中点了主页其他的分页全部出栈

scheme跳转协议

  • 在不知道对方的包名,类名的情况下要打开对方,不如浏览器要打开其他的app,或者本应用 打开 其他的应用的时候就可以采用这种方法;他是通过在activity中注册intent-filter来实现的包含 data(含scheme),cataglory,action

Fragmen相关

  • addToBackStack 加入栈中,返回的时候销毁Fragment

Service和Broadcast都是运行在mainThread中所以不能做耗时操作

数据库相关

  • SQLiteOpenHelper 构造方法创建数据库(方法参数一样只会调用一次,当版本号不一样的时候会调用onUpgrade方法),用这个对象的拿数据库会掉onCreate方法,这个方法里创建数据库表
  • helper对象拿db对象,db对象操作数据库,这些操作的方法封装到Dao里面提供给外面调用

获取 Message 的方法

  • 在 Hanlder 机制中都需要用到 Message 对象,该对象的创建或者获取有多种方式。
    • Message msg = new Message(); 直接创建一个新的 Message 对象。
    • Message msg = handler.obtainMessage(); 通过 handler 对象获取一个 Message 对象,该对象从消息缓存池中获取的,可以提高 Message 的使用率,减少垃圾回收次数。
    • handler.post(Runnable r); post()方法中传递一个 Runnable 对象,那么该对象会被主线程执行。该方法表面上看跟 Message 没任何关系,但是其内部帮我们封装了 Message。
    • 同样View.post 也是同样的机制

常用的线程调度操作

  1. 通过View对象执行延时操作
        View view = ...;
        view.postDelayed(new Runnable() {
			
			@Override
			public void run() {
				// 这里的代码在200毫秒后运行在主线程
			}
		}, 200);
  1. 通过Handler发送延时请求(可以在子线程发出)
        new Handler().postDelayed(new Runnable() {
			
			@Override
			public void run() {
				// 这里的代码在3秒后运行在主线程
			}
		}, 3000);

本质是sendmessage,让后把runnable一起传出去,代替了handlemessage

  1. 在子线程执行Activity中的runOnUiThread方法
        new Thread(){
        	public void run() {
        		// 这个方法只能在Activity里调用
        		runOnUiThread(new Runnable() {
					@Override
					public void run() {
						// 这里的代码可以运行在主线程
					}
				});
        	};
        }.start();
### 有关动画
- 属性动画animator:是为动画设置执行的客体,然后指向动画
- 补间动画animation:是为客体指定要执行的动画

广播:要注册清单文件

  • 注册广播:写好广播接受者类,完成onrecevie方法
    • 静态注册:在清单文件里注册广播写好意图过滤(杀死进程,都可以收到广播,但是不灵活)
    • 动态注册:在代码中注测action吗(受activity生命周期影响)
  • 实现机制
    • 通过binder向AMS注册广播接收者 :登记接收者
    • 通过binder向AMS发广播:登记广播
    • AMS找到对应的接收者,把广播放在接收者的消息队列中
    • 接收者回调onreciver
myReceiver = new OutCallReceiver();
IntentFilter intentFilter=new IntentFilter(Intent.ACTION_NEW_OUTGOING_CALL);
intentFilter.setPriority(Integer.MAX_VALUE);
registerReceiver(myReceiver,intentFilter);
  • 发送广播:
    • 无序:
		Intent intent = new Intent();
    	// 设置动作, 广播频道
    	intent.setAction("com.itheima.cnr.XWLB");
    	// 添加一些数据
    	intent.putExtra("content", "这里是中央人民广播电台! 欢迎收听!");
    	// 发送广播
    	sendBroadcast(intent);
  • 有序:各级接受者要配置priority,高的可以中断广播,内线一定可以接收到最后一个结果
// intent 要发送的意图
    	// receiverPermission 接收者需要配置的权限
    	// resultReceiver 结果接收者, 一定可以在最后收到消息
    	// scheduler 线程调度器new Handler()
    	// initialCode 结果码
    	// initialData 初始数据
    	// initialExtras 额外的参数 Bundle -> map
    	
    	// 发送广播
    	sendOrderedBroadcast(
    			intent, 
    			null, 
    			new NeixianReceiver(), 
    			null, 
    			1, 
    			"中央下发粮食了, 每人1000斤, 大家吃好喝好!", 
    			null
			);
  • localbroadcastmanager(本地广播)
    • 防止反编译到action,利用你的app分享他自己的连接(植入广告)
    • 比系统广播更高效
    • 别的app无法向你发广播。只在本app传播
    • 不同于系统广播发送通过binder,本地广播发送是通过handler

android中任务栈情况,但是进程依然保留(为了下次打开快)

  • 一个应用可以run在多个进程中
  • 前台进程(可以操作),可视进程(被透明的前台遮挡,不能操作),服务进程(没有界面的程序),后台进程(home键回到主界面),空进程(任务栈清空,按返回键造成)—按优先级回收

服务:要注册清单文件

  • 启动和显示意图的activity一样,反复开启(startservice)不会走oncreate,只会执行onstartcommand
  • 关闭要到设置里,或者手动调stopservice走一次ondestroy

绑定服务的方法

  • 创建连接对象,实现连上和解开两个方法,在服务的绑定和解绑服务中被回调
  • 绑定服务传入的是conn和service
  • 服务被绑定要传回一个ibinder对象,用这个ibinder来通信
  • 要解绑,否则连接器会leak,服务会自动销毁
  • 服务是被start打开的,主程序意外退出,服务不会退出;如果服务是bind方式打开,主程序意外退出(没有手动unbind),服务会自动解绑并且destroy
  • 总结是前台进程通过绑定conn和服务的方式启动服务,服务返回ibinder对象给前台进程,ibinder对象可以带上服务里的方法给前台进程调用
  • 当 service 同时被 startService 和 bindService 启动时,只有 stopService 和
    unbindService 都被调用后,service 才会被销毁。

单例吐司

if(toast == null){
			toast = Toast.makeText(context, "", Toast.LENGTH_SHORT);
		}
		toast.setText(string);
		toast.show();

隐式意图应用间用,用了意图过滤器or export=true那么就可以被其他应用打开;显示意图默认是应用内部用

aidl(服务代码在另一个应用中 接口定义语言)

  • 是一种采用共享存储区的IPC通信方法,通过asinterface的方法用key值在共享文件binder中找到服务接口,返回给调用对象使用;调用者用aidl生成的类里的方法处理返回的binder对象可以生成远程服务指定的接口类,并调用其中的方法,达到调用服务里方法的目的

既然service不能做耗时操作,也要new thread 那么为什么不直接在 activity中new thread;

  • 因为activity会销毁finish ,很难对线程做到很好的管理,但是service就不同,可以长时间在后台运行,完成对thread的管理。比如音乐播放器、数据统计。
  • activity与service的通信用的是binder机制,这本身就是IPC通信的原理,应为activity和service完全可以运行在不同的进程当中。

服务可以不用直接和activity交互,通过startservice方式启动的服务,可以发送广播给接收者,让广播处理相应的业务。让activity和service之间解绑。

webview

  • 内存泄漏:自己会开辟线程(类似匿名内部类持有外部类的引用)不懂
    • 动态通过viewgroup添加,销毁前remove
    • 独立进程
  • 渲染:关闭硬件加速
  • 耗电:

binder机制

  • Linux是进程间隔离的,进程之间没有办法传数据
  • 所以通过第三者servicemanager来管理,传回一个代理对象给client
  • client把代理对象调的结果告诉binder,binder调service里的真方法

aidl机制

  • stub实现了IService接口,
  • 在asinterface里面按照key查找本地的接口,如果有就表示是本地的调用直接返回,如果没有则返回proxy代理对象
  • 代理对象实现的方法是个空方法,调用了transact,最终回到onTranact,调用的还是本地的方法,中间通过了Ibinder

内存泄漏https://blog.csdn.net/bigbangwqf/article/details/51329223

  • 非静态内部类持有外部类的引用(静态的不会持有,跟对象无关):handle
    • 可以关闭的时候销毁掉 handle.removecallback()
    • 可以弱引用
    • 可以静态化(这样调不了外部类的方法)
  • 匿名内部类持有外部类的引用:webview

AsyncTask使用方法

  • 三个参数(传入,进度,结果)
  • 五个方法:
    • onPreExecute:在UI线程调用,任务前准备工作
    • doinbackground<第1个参数>:耗时
      • 结果传入:onPostExecute<第3个参数>
      • 更新进度:publishProgress(内部),onProgressUpdate<第2个参数>(外部跟新)
  • 原理:内部封装线程池,用handle实现子线程和ui线程的传递
  • 泄漏:cancel

HandlerThread相关https://blog.csdn.net/u011240877/article/details/72905631

  • 处理串行的子线程调用
  • 继承类消息群是在prepare里完成插入,同时创建handle,定义处理消息的处理方式handlemessage

IntentService相关

Android studio

  • classpath ‘com.android.tools.build:gradle:3.0.1’ 这个跟Android studio的版本一样
  • compileSdkVersion :sdk/plateform
  • buildToolsVersion :sdk/build-toos
  • 目录:
    • .gradle:构建文件
    • gradle:由于gradle更新的速度超过Androidstudio所以弄了个包装类wrapper来跟上进度。
    • .idea:Androidstudio自己要用的工具

listView 优化

  • convertview重用: 不用new
  • viewHolder : 不用找
  • 图片缓存 :不用每次都加载
  • 滑动监听:尽量不要做耗时操作,一定要做的话,加滑动监听,停下来的时候在请求网络等等

类加载器的双亲委托模型

  • 先交给最顶层的加载器加载
  • 步骤:
    • 加载
    • 验证
    • 准备:赋值,局部变量一定要赋值才能使用,否则编译不通过,其他的按照jvm的规则进行赋值or默认值;同时被static和final修饰的要在声明是就赋值,final修饰的要在初始化前赋值;
    • 解析:解析类、方法、变量,方法先找类
    • 初始化
    • 使用
    • 卸载

内存管理

  • 静态存储器(方法区):静态数据,常量;存在于整个生命区
  • 栈区:基本类型变量,对象引用
  • 堆区(动态存储器):
  • 回收机制
    • 用有向图是否可达类管理内存

git 命令

  • git init
  • git status
  • git diff
  • git add
  • git commit
  • git clone
  • git branch
  • git checkout
  • 下面的模型区别于传统的直接跟远程仓库打交道,忽略了代码管理员的角色,增加了fork和pull
  • 在这里插入图片描述

proguard

  • 压缩
  • 优化
  • 混淆
  • 预检测
  • entrypoint

框架

volley

-支持图片加载

  • 使用:
    • 创建请求队列
    • 创建请求
    • 把请求加入请求队列
  • 源码:
    • 创建请求队列:封装了httpclientstack,创建了queue开启并返回
    • queue开启创建了两个线程死循环,一个是缓存线程,一个是网络请求线程
    • 在请求加入请求队列后
      • 判断是否要缓存,要就加入缓存线程
      • 加入网络请求线程
      • 其中缓存线程的run方法会先按照key从缓存队列中拿,返回为空,就把他加入网络请求队列。发出返回结果,触发回调函数
      • 而网络请求队列是直接加入请求,发出返回结果,触发回调函数

butterknife

  • 是用注解在编译期完成的,并非运行时反射的
  • 变量要是public否则只能反射才能获得

开发架构

MVC

  • M:业务逻辑,耗时,数据库
  • V:显示,xml
  • C:activity 处理交互,从v拿到用户输入的数据,交给m查数据库or请求服务器,返回的结果交给v显示;解耦v 和 m

MVP

  • 由于Android的v(xml)所做的的详情,相比于web来说非常有限。很多工作交给了c层的activity实现导致C太耦合了,所以引入MVP

  • 在MVP中activity变成了v,他原本的处理交互的工作交给了presenter来处理

  • M:网络请求,数据库查询,数据bean

  • V:activity

  • P:业务层,彻底分开view和model

  • 在这里插入图片描述

  • 上图可以清晰的看到presenter要调view,只能通过定义好的接口,限制好能做的事

  • **特点:**与业务有关的M(网络请求,数据库查询)或V(成功返回,失败返回,显示关闭进度条) 都是要在接口中定义好交给对应的M 或者V (activity)实现,让代码看的结构清晰。就是P要调用v还是M都是接口定义好的只要看接口就知道要做什么事。

  • 接口回调:网络请求为例,我不知道请求几时能结束,所以把结束要做的事的函数跟着网络请求一起传给请求函数,请求结果出来了由他回调。在Android里这个回调方法执行一般要更新ui,所以要交给handler处理(runonuithread就是这么封装的)。

PathClassLoader,DexClassLoader

  • DexClassLoader:加载dex字节码里的类(动态)
  • PathClassLoader:加载文件目录里的类

有关进程的优先级

  • 空进程的存在是为了缓存,下次打开apk快一些,不包含任何组件
  • 进程回收:low memory kill 打分
  • 保活:service拉活,native拉活

###Android中哪些操作在主线程

  • Activity的所有生命周期方法
  • Service执行
  • 广播的onReceive
  • 没有使用子线程的Looper的Handler的HandleMessage,post是执行在主线程的
  • AsyncTast的回调中除了doInbackgound,其他都是在主线程的

如何解决ANR

  • 使用AsyncTast处理IO操作
  • 使用Thread或者HandlerThread提高优先级
  • 是哦用Handler来处理工作线程的耗时任务
  • Activity的onCreate和onResume回调中尽量避免耗时的代码

oom

  • 当前占用的内存加上我们申请的内存资源超过了Dalvik虚拟机的最大内存限制就会抛出Out Of Memory异常

内存泄漏:

  • 单例:单例是静态的,传入的context用application。
  • 匿名内部类(就跟非静态的内部类泄漏是一样的原因,默认持有外部类的引用,不是说静态的就不可以持有,如果构造方法传进去了就会持有,但是可以改成弱引用):非静态的都会持有外部类的引用。内部不消失,外部不消失
    • 匿名内部类指的是类定义的时候没有给名字,而不是这个类生成的对象没有给名字。通常类在定义的时候就new了比如thread。
    • 所以有:匿名内部类访问方法成员变量需要加final的原因及证明
    • 解法:。弱引用
  • handle:定义在activity的匿名handle内部类,生命周期和activity不一样,他是被消息队列持有,只要队列的消息没完就不会消失。
  • 解法:静态,对持有外部类的引用改为弱应用弱引用
  • static成员变量:避免使用
  • 资源没有关闭
  • asynctask,可以在onDestroy 取消任务

猜你喜欢

转载自blog.csdn.net/hukou6335490/article/details/82944150
今日推荐