1.事件分发机制
activity-phonewindow-decorview-viewgroup----view
第一步:事件首先会传递给Activity。
第二步:传递到View的实现管理类PhoneWindow。
第三部:而PhoneWindow是通过他的内部类DecorView 来传递的。
第四步:DocorView又会传递给最大的父容器ViewGroup。
第五步:ViewGroup又会依次传递给它的子View。
1、首先事件会传递给activity中,activity会在他的dispatchTouchEvent中来进行处理,
2、他会传递给PhoneWindow,而PhoneWindow会调用它本身的内部类DecorView中的dispatchTouchEvent。此时会判断是否进行拦截,如果不拦截的话,继续往下传。
3、如果不拦截的话,就会穿第给RootView中的dispatchTouchEvent方法中分发,而在Rootview中也会通过onInterceptTouchEvent方法中进行判断是否拦截,如果不拦截就会继续下传。
4、此时ViewGroupA就会接收到RootView传递过来的事件,也会通过dispatchTouchEvent方法来进行事件的分发,通过onInterceptTouchEvent方法中进行判断是否拦截,如果不拦截就会继续下传。
5、此时View1就会得到传递下来的事件。view在它自身的dispatchTouchEvent方法中进行相应的处理,这时候它是我们案例中最底层的view。他就没有拦截时间了。如果View1的onTouchEvent返回了true。就说明view1消费掉了此事件。这个时候我们会依次返回true。依次告诉上层的dispatchTouchEvent方法,事件已经被处理了。就不要再做此事件的相应了,最后到最顶层Activity中。
2.fragment生命周期(结合activity)
页面初始化并加载的时候一直都是activity的生命周期方法先执行,只有在后面暂停并销毁的时候,fragment的生命周期方法优先执行
启动时一般都是先执行Activity的生命周期,再执行Fragment的。
Activity的onCreate,Fragment的onAttach,onCreate,onCreateView,onActivityCreated,然后调用Activity的onStart,Fragment的onStart,Activity的onResume,然后Fragment的onResume你 把啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦啦看来,kkkkkkkkk/////////////////
Home键回到主界面时又返回时
首先执行Fragment的onPause,然后的activity的onPause,然后fragment的onsaveinstancestate,activity的onsaveinstancestate,然后执行fragment的onstop方法,activity的onstop方法。主页面返回时activity的onrestart,onstart,fragment的onstart,activity的onresume,fragment的onresume.
正常销毁时
首先执行fragment的onpause,然后activity的onpause,然后fragment的onstop,activity的onstop,fragment的ondestroyview,ondestroy,ondetach最后activity的ondestroy
Fragment 切换(replace 方式)FA切换成FB
B的onAttach,onCreate
A的onpause,onstop,ondestroyview,ondestroy,ondettach
B的onCreateView,onActivityCreate,onstart,onresume
Replace 方式切换 Fragment 时,每次执行 replace 方式就会销毁上一个已存在的 Fragment,即 Activity 中只包含一个 Fragment
Fragment 切换(hide/show 方式)
FA切换成FB,
FB:onAttach,onCreate,onCreateView,onActivityCreated,onstart,onresume
3.handler
(1)什么是handler?
1、简单的来说,就是在子线程做完耗时操作,可以通过发送runnable和sendmessage方式通知主线程更新UI
2、让自己想要处理的耗时操作放在子线程,然后通过handler发送消息的机制,通知主线程更新UI。
Handler就是将消息放入队列的机制。我们在哪个线程中创新handler,handler就将消息放入所在的线程,除非在创建handler对象时是指定具体的线程。通常handler在主线程创建,handler可将消息放入主线程队列中。
Message:消息,分为硬件产生的消息(例如:按钮、触摸)和软件产生的消息。
MessageQueue:消息队列,主要用来向消息池添加消息和取走消息。
Looper:消息循环器,主要用来把消息分发给相应的处理者。
Handler:消息处理器,主要向消息队列发送各种消息以及处理各种消息。
整个消息的循环流程还是比较清晰的,具体说来:
(1)Handler通过sendMessage()发送消息Message到消息队列MessageQueue。
(2)Looper通过loop()不断提取触发条件的Message,并将Message交给对应的target handler来处理。
(3)target handler调用自身的handleMessage()方法来处理Message。
(2)handler的使用方法?
1、post(runnable)
我们在runnable做完耗时操作,然后通过handler的post(runnable)方法来通知主线程。
2.sendMessage(message)
第一步:在外部创建一个handler对象,并复写handleMessage()方法
第二步:开启一个工作线程,来处理耗时操作。并且创建Message对象,通过message.what或者message.what.arg1|message.whatarg2等方式为其赋值,这个值是区分消息的类别。可以通过what的值来获取不同的message消息来更新主线程。
第三步:通过uihandler.sendMessage()方法,将message消息传递入handler中,然后通过handerMessage()方法来进行UI线程的处理。
3.原理
handler机制包含了四大部分.
1、looper:创建looper的时候,会自动创建一个MessageQueue。
2、MessageQueue:消息对列,在创建looper的时候,就已经被创建,
3、Message:消息对象。它包含了很多的参数,
4、handler:发送消息和接收消息。处理的是looper发送过来的消息。
注意:handler发送消息不能胡乱发送,它不能发送给其他线程,他只能发送到它相关的线程,也就是它相关线程的MessageQueue中。而MessageQueue有需要looper来管理。所以handler发送消息,必须有一个looper对象来维护handler。所以我们就把handler、looper、MessageQueue关联到了一起。
问:looper对象是怎么获取到的?
码中点击Looper.mylooper()来查看下looper对象是怎么来获取的。我们看到他是通过mThreadlocal.get()方法来获取
问:为什么通过mThreadlocal来获取呢?
答:mThreadlocal中,通过不同的线程,访问同一个mThreadlocal,不管使用get方法还是set方法。他们对所有mThreadlocal做的读写操作“仅限于各自线程内部”,这就是为什么handler里面要通过mThreadlocal来保存looper,这样他就可以使每一个线程有单独唯一的looper。
问:mThreadlocal.set()有是在什么时候set的呢?
答:他是在prepareMainLooper()方法中调用的(源码100行
他首行调用了prepare()方法,点进去会发现,它就是创建了一个looper对象,并且把这个looper对象设置给了mThreadlocal,这样就保证了每一个线程looper的唯一。此时就可以说,整个的MessageQueue通过looper和线程关联上了。这样我们就可以在不同的线程访问不同的消息对列。
问:handler、looper、messageQueue在源码中怎么关联到一起的呢?
我们通过looper.Mylooper()创建了一个looper对象。又根据成员变量looper,创建了一个mQueue。handler在它的构造方法当中就和messageQueue关联到了一起。而messageQueue又是通过looper,来管理的,所以。此时就可以说他们三者通过形成了handler机制。
问:为什么非要在主线程创建handler。而不能在内部类中创建handler?
就是因为每一个handler要与主线程的消息对列关联上,所以说一定要在主线程创建handler。而不能在内部类中创建handler。这样才能让handler中的handlerMessage()方法执行在UI线程。这样才能保证线程安全,不会抛出异常。
问:looper.loop()方法到底是什么
我们上面说,发送handler消息有两种方式,pos(runnable)和sendMessage(message),但是这两种都是运行在looper.loop()方法之后。所以我们来看下looper.loop()方法。其实loop()方法就是创建了一个for循环,然后从消息对列中逐个的去获取消息,最后处理消息。
问:looper源码中的详情?
答:首先它是通过prepare()方法来创建looper,把他保存在mThreadlocat中。然后通过looper.loop开启循环。最终的消息是交给target.DispatchMessage()方法来进行消息的分发,而target就是一个handler对象。
handler流程机制的过程是什么?
答:looper开启一个循环,从头部提取消息Meeage6,通过handlerMessage来处理消息,处理完成之后还是返回到looper中,不断的又开始循环,从消息对列中获取消息
4.IPC进程间通信
bundle,文件共享,AIDL,messenger,contentprovider,socket
5.自定义view
使用invalidate重绘当前视图是不会再次执行measure和layout流程的。因为视图没有强制重新测量的标志位,而且大小也没有发生过变化,所以这时只有draw流程可以得到执行。
如果你希望视图的绘制流程可以完完整整地重新走一遍,就不能使用invalidate()方法,而应该调用requestLayout()了.一个是刷新父控件,一个是局部刷新。
6.asynctask哪些方法执行在主线程,哪些方法执行在子线程?
onPreExecute,
onPostExecute
onProgressUpdate
doInBackground(子线程)
7.存储方式
SharedPreferences:以键值对形式进行存储,数据以xml形式存储在/data/data/项目包名/shared_prefs/xml.xml中。一般来说,SP只能存储基本类型的数据,如:布尔类型、浮点型、整形及字符串,默认情况下,SP保存的文件是应用的私有文件,其他应用(和用户)不能访问这些文件。SP线程不安全
内部存储:直接在设备的内部存储中保存文件。默认情况下,保存到内部存储的文件是应用的私有文件,其他应用(和用户)不能访问这些文件。 当用户卸载应用时,这些文件也会被移除。
外部存储:保存到外部存储的文件是全局可读取文件。(data 目录就是就是就是手机的内部存储,而 mnt 或者 storage 目录下的sdcard目录就是外部存储。如果是手机内存的外部存储被称为机身外部存储,外置的SD卡则称之为外部存储。当然都称两者为外部存储也没关系)
SQLite
网络连接
8.广播的分类
在Android自定义的广播中分为无序广播和有序广播
无序广播:
发送方式:通过sendBroadcast(intent)发送
无序广播类似于电视台播放新闻联播,不管你当时有没有准时收看,都会按时播放新闻联播
特点:
1、无法终止广播
2、无法修改数据
有序广播:
发送方式:通过sendOrderedBroadcast()发送
有序广播就类似于中央发送的红头文件,比如说会首先发送到哪个省,然后发送到哪个市等等,按照优先级一级一级的进行接收,就比如中央给每个村民发送1千斤大米,
特点:
1、可以终止广播
2、可以修改数据
注册广播有几种方式
1、静态注册。
静态注册是在AndroidManifest.xml文件中配置,这种方式的注册是常驻型的,也就是说当应用关闭后,如果有广播信息传来,MyReceiver也会被系统调用而自动运行。
2、动态注册。
动态注册需要在代码中动态的指定广播地址并注册,通常我们是在Activity或Service注册一个广播,当这个Activity或Service被销毁时如果没有解除注册,系统会报一个异常,提示我们是否忘记解除注册了。所以,记得在特定的地方执行解除注册操作:
9.重写viewpager实现禁用滑动
public class NoScrollViewPager extends ViewPager {
private boolean noScroll = false;
public NoScrollViewPager(Context context, AttributeSet attrs) {
super(context, attrs);
}
public NoScrollViewPager(Context context) {
super(context);
}
public void setNoScroll(boolean noScroll) {
this.noScroll = noScroll;
}
@Override
public void scrollTo(int x, int y) {
super.scrollTo(x, y);
}
@Override
public boolean onInterceptTouchEvent(MotionEvent arg0) {
if (noScroll)
return false;
else
return super.onInterceptTouchEvent(arg0);
}
@Override
public void setCurrentItem(int item, boolean smoothScroll) {
super.setCurrentItem(item, smoothScroll);
}
@Override
public void setCurrentItem(int item) {
super.setCurrentItem(item);
}
}
写一个类继承了原生的ViewPager,然后重写了onInterceptTouchEvent(MotionEvent event)及添加了setNoScroll(boolean noScroll)方法
onInterceptTouchEvent该方法判断是否拦截上面传递过来的事件,即是否需要当前的View进行处理。
- return false: 不对事件进行拦截,放行该事件。事件会被传递到当前的View的子控件中,由子控件中的dispatchTouchEvent方法进行分发处理
- return true: 拦截该事件,将该事件交给当前View的onTouchEvent方法进行处理
- return super.onInterceptTouchEvent(event):默认拦截方式,和return true一样,该事件会被拦截,将该事件交给当前view的onTouchEvent方法进行处理。
总结
我的理解是NoScrollViewPager中的onInterceptTouchEvent方法返回了false,则没有消费此事件,会向下传递,但是他又没有子View了,会结束事件分发,也不会调用父类的滑动事件!!
10.微信支付宝支付
请求自己服务器,获取订单签名字符串,然后调用支付宝SDK,发起支付请求
支付宝支付结果的回调
实际传支付结果,最好以服务端为标准,我们调用支付宝支付的时候,支付宝会有2个回调,一个是APP的回调,就是我们上面这个,9000代表支付成功,一个是支付宝服务器通知我们自己的服务器,所以,我们自己的服务器也有个回调。所以APP可以请求后台的接口来获取支付结果。
微信支付结果回调:在WXPayEntryActivity类中实现onResp函数,支付完成后,微信APP会返回到商户APP并回调onResp函数,开发者需要在该函数中接收通知,判断返回错误码,如果支付成功则去后台查询支付结果再展示用户实际支付结果。
11.retrofit
retrofit的使用
12.MVC,MVP,MVVM
MVC中moudel和view层可以直接交互,什么渲染布局,拿到对象,拿到数据等。而MVP中,这两个层是不可以直接交互的需要通过P层也就是控制层去作为一个纽带,传输这些数据,处理这些数据。这样也就降低了两者的耦合性 。
MVC主要将M层分出来,V和C分层不明确,业务复杂之后,MV层耦合严重。
MVP让View专注于处理数据的可视化以及与用户的交互,同时让Model只关系数据的处理。项目结构清晰,解耦程度高,每个功能相互之间独立,可单独测试。框架中分工就是很明确的,所以代码的可读性就会相对提高一点
MVP缺点
①项目会出现大量的presenter,大大增加了类的数量。
②因为presenter会持有Activity的引用,使用不当的话,容易出现内存泄露问题
MVP优化方法
给presenter定义将view对象置空的方法,销毁view时在view层ondestory中调p对象的置空的方法
MVP官方示例
1、todo-mvp:MVP基础架构
2、todo-mvp-loaders:基于MVP基础架构,获取数据部分使用了Loaders架构
3、todo-mvp-databinding:基于MVP基础架构,使用了数据绑定组件
4、todo-mvp-clean:基于MVP基础架构,引入Clean架构概念
todo-mvp-contentproviders:基于MVP基础架构,使用了Content Provider
todo-mvp-dragger:基于MVP基础架构,使用dragger2依赖注入
todo-mvp-rxjava:基于MVP基础架构,使用RxJava解决数据并发
13.Handle用法中Message创建方式:new Message和obtainMessage的区别?
从整个Messge池中返回一个新的Message实例,通过obtainMessage能避免重复Message创建对象。
14.Rxjava相关
优点1:简化逻辑,解耦了各个模块操作,单一化
比如要嵌套请求的时候,这个时候用flatMap操作符就可以实现优雅的链式嵌套请求
优点2:简化代码
它的操作符封装了规则,我们用一个操作符就可以实现许多功能
比如要打包网络请求,这个时候用zip就可以打包数据源
优点3:操作符强大,可以实现各种功能
flatmap解决嵌套回调的问题;mergeWith()可以把不同异步操作合并
优点4:最方便的是线程切换
优点5:错处处理
只要有异常发生onError()一定会被调用,这极大的简化了错误处理。只需要在一个地方处理错误即可以
线程切换:subscribeOn 用于指定上游线程,observeOn 用于指定下游线程,多次用 subscribeOn 指定上游线程只有第一次有效,多次用 observeOn 指定下次线程,每次都有效 。简单的来说, subscribeOn() 指定的是上游发送事件的线程, observeOn() 指定的是下游接收事件的线程.
上游事件是怎么给弄到子线程里去的?就是直接把订阅方法放在了一个Runnable中去执行,这样就一旦这个Runnable在某个子线程执行,那么上游所有事件只能在这个子线程中执行了。
15.同一个Looper是怎么区分不同的Handler的,换句话说,不同的Handler是怎么做到处理自己发出的消息的?
这个问题就要来到Handler的sendMessage方法里面,当前的Handler赋值给Message对象msg.target = this,这样在处理消息的时候通过msg.target就可以区分开不同的Handler了。也就是说handler只接受自己的message
16.String,Stringbuff,StringBuilder
String类是final类,也即意味着String类不能被继承,并且它的成员方法都默认为final方法。String类其实是通过char数组来保存字符串的
String str1 = "hello world"JVM执行引擎会先在运行时常量池查找是否存在相同的字面常量,如果存在,则直接将引用指向已经存在的字面常量;通过new关键字来生成对象是在堆区进行的,而在堆区进行对象生成的过程是不会去检测该对象是否已经存在的。因此通过new来创建对象,创建出的一定是不同的对象。
当字符串相加操作或者改动较少的情况下,建议使用 String str="hello"这种形式;
当字符串相加操作较多的情况下,建议使用StringBuilder,如果采用了多线程,则使用StringBuffer。
String为字符串常量,而StringBuilder和StringBuffer均为字符串变量,即String对象一旦创建之后该对象是不可更改的,但后两者的对象是变量,是可以更改的。
Java中对String对象进行的操作实际上是一个不断创建新的对象并且将旧的对象回收的一个过程,所以执行速度很慢。
在线程安全上,StringBuilder是线程不安全的,而StringBuffer是线程安全的
17.Serializable Parcelable
所谓序列化就是将对象变成二进制流,便于存储和传输。
Serializable是java实现的一套序列化方式,可能会触发频繁的IO操作,效率比较低,适合将对象存储到磁盘上的情况。
Parcelable是Android提供一套序列化机制,它将序列化后的字节流写入到一个共性内存中,其他对象可以从这块共享内存中读出字节流,并反序列化成对象。因此效率比较高,适合在对象间或者进程间传递信息。
18.建造者模式与工厂模式的区别:
工厂模式一般都是创建一个产品,注重的是把这个产品创建出来就行,只要创建出来,不关心这个 产品的组成部分。从代码上看,工厂模式就是一个方法,用这个方法就能生产出产品。
建造者模式也是创建一个产品,但是不仅要把这个产品创建出来,还要关系这个产品的组成细节, 组成过程。从代码上看,建造者模式在建造产品时,这个产品有很多方法,建造者模式会根据这些相同 方法但是不同执行顺序建造出不同组成细节的产品。
可以比较两个模式的example代码,一比较就会比较出来,工厂模式关心整体,建造者模式关心细节。
19.listview与recycleview
listview二级缓存 recycleview四级缓存
RecyclerView比ListView多两级的缓存,支持多个离Item的缓存,支持开发者自定义缓存处理的逻辑,支持所有RecyclerView公用同一个RecyclerViewPool(缓存池).
ListView优化主要有下面几个方面:
1、convertView重用(主要优化加载布局问题)
ListView中的每个item显示都需要Adapter调用一次getView(),这个方法会传入一个convertView参数,返回的view即item的view。如果item数量足够大,再为每个item创建view对象,必将占用大量的内存。即创建View对象(mInflater.inflate(R.layout.lv_item, null);从xml中生成View,这是属于IO操作)是耗时操作,所以必将影响性能。而此时调用的getView中的参数convertView就是被缓存的view,所以说如果能重用这个convertView,就会大大改善性能。
2、ViewHolder的子View复用
主要优化getView方法中每次回调用findviewByID()方法来获取一次控件的代码。
新增加内部类ViewHolder,用于对控件的实例存储进行缓存。
1 Listview中ViewHolder是需要自定义的,在RecyclerView中ViewHolder是谷歌已经封装好的
2 Listview中的Item是只能垂直滑动的,RecyclerView可以水平滑动或者垂直滑动,针对多种类型条目的展示效果,如瀑布流 网格 支持多种类型
3 Listview中删除或添加item时,item是无法产生动画效果的,在RecyclerView中添加、删除或移动item时有两种默认的效果可以选择SimpleItemAnimator(简单条目动画) 和 DefaultItemAnimator(原样的条目动画)。
4.ListView通过AdapterView.OnItemClickListener接口来探测点击事件。而RecyclerView则通过RecyclerView.OnItemTouchListener接口来探测触摸事件。它虽然增加了实现的难度,但是却给予开发人员拦截触摸事件更多的控制权限。
http://www.cnblogs.com/876013676ch/p/10187257.html
20.线程池的四种初始化
https://www.cnblogs.com/cspecialy/p/9093182.html
1.FixedThreadPool 线程数量固定的线程池
除非线程池被关闭,否则线程不会被回收,即时线程处于空闲状态。如果在所有线程都处于活动状态时提交额外的任务,它们将在队列中等待,直到有一个线程可用为止。由创建方法可知,FixedThreadPool 只有核心线程并且这个核心线程没有超时机制(keepAliveTime 参数为 0L),加上线程不会被回收,因此使用此类线程池可以快速地响应外界的请求。
2.CacheThreadPool 线程数量不定的线程池
没有核心线程(corePoolSize参数为0),只有非核心线程且非核心线程的数量为Integer.MAX_VALUE,这就相当于非核心线程的数量可以无限大。
线程池的线程处于空闲状态时,线程池会重用空闲的线程来处理新任务,否则创建新的线程来处理,新创建的线程会添加到线程池中。这将提高执行许多短期异步任务的程序性能。
闲置时间超过60 秒的空闲线程会被回收(keepAliveTime参数为60L)。因此,闲置时间足够长的 CacheThreadPool 也不会消耗任何系统资源。
3.ScheduledThreadPool 核心线程数量固定,非核心线程数量不定的线程池
4. SingleThreadPool
只有一个核心线程,通过Executors 的 newsinglethreadexecutor 方法创建。
21.android IntentFilter的匹配规则
https://www.jianshu.com/p/5f644e0fdba9
action的匹配规则:
action是一个字符串,action的匹配规则是Intent中的action必须能够和过滤规则中action
匹配,一个过滤规则中可以有多个action,只要intent中的action和过滤规则中任何一个匹配上,
就是匹配成功,(区分大小写)
category的匹配规则
如果Intent中的存在category那么所有的category都必须和Activity过滤规则中的category相同。才能和这个Activity匹配。Intent中的category数量可能少于Activity中配置的category数量,但是Intent中的这category必须和Activity中配置的category相同才能匹配。
注意:1、只通过category匹配是无法匹配到AActivity的。因为category属性是一个执行Action的附加信息。
所以只靠category是无法匹配的
data的匹配规则
类似于action匹配,但是data有更复杂的结构
data 由两部分组成
mineType和URI
mineType: 指媒体类型 例如: image/jpeg vided/* ...
URl可配置更多信息,类似于url
<scheme>://<host>:<port>/[<path>|<pathPrefix>|<pathPattern>]
Scheme:URI的模式。如果URI中没有指定Scheme.那么整个URI无效。默认值为content 和 file。
Host:URI的host。比如www.axe.com。如果指定了scheme和port,path等其他参数,但是host未指定,那么整个URI无效;如果只指定了scheme,没有指定host和其他参数,URI是有效的。可以这样理解:一个完整的URI :http://www.axe.com:500/profile/info我将后面的prot 和path“:500/profile/info ”去掉,这个URI任然有效。如果我单独将www.axe.com那这个URI就无效了。
Port:URI端口,当URI指定了scheme 和 host 参数时port参数才有意义。
path:用来匹配完整的路径,如:http://example.com/blog/abc.html,这里将 path 设置为 /blog/abc.html 才能够进行匹配;
pathPrefix:用来匹配路径的开头部分,拿上面的 Uri 来说,这里将 pathPrefix 设置为 /blog 就能进行匹配了;
pathPattern:用表达式来匹配整个路径。
添加了mimeType。这种匹配方法我们需要做改变。我们不能使用
setType 和 setData , 需要使用setDataAndType()。
从源码可以看出:setType() 会将URL设为null; setData()会将mineType设为null;以下为源码:
22.两个Activity之间跳转时必然会执行的是哪几个方法。?
一般情况下比如说有两个activity,分别叫A,B。
当在A 里面激活B 组件的时候, A会调用onPause()方法,然后B调用onCreate() ,onStart(), onResume()。
这个时候B覆盖了A的窗体, A会调用onStop()方法。
如果B是个透明的窗口,或者是对话框的样式, 就不会调用A的onStop()方法。
如果B已经存在于Activity栈中,B就不会调用onCreate()方法。
网友评论