整理的关于常见的几种问题

MVP模式
1.mvp是什么,为什么用mvp
是什么:
mvp是android开发的一种模式,再MVC的基础上把Activity的View和Controller抽离出来就变成了View和Presenter,这就是MVP模式。
为什么用:
我们平常开发中的Activity、XML界面加起来就已经相当于一个MVC的架构模式,这种开发方式的缺点就是业务量大的时候,一个Acitvity多到上千行代码,想要改一处业务逻辑光是去找就要费半天劲,而且有点地方逻辑处理是一样的无奈是不同的 Activity 就没办法很好的写成通用方法。
MVP 模式将Activity 中的业务逻辑全部分离出来,让Activity 只做 UI 逻辑的处理,所有跟Android API无关的业务逻辑由 Presenter 层来完成。
将业务处理分离出来,管理方便,但是缺点就是增加了代码量

2.mvp的优缺点是什么
优:
1.UI层和逻辑层分离,UI层不在涉及业务逻辑代码,某层的改动不需要到处去修改代码;
2.测试方便,可以直接调用Presenter层写测试用式(可以使用Junit框架);
3.可维护性和可扩展性,MVP的各个类职责都非常明确且单一,后期的扩展,维护都会更加容易。
缺:
1.首先代码量增加了,一个小功能你可能要为它专门写Presenter和Model层的实现,以前这些你一口气就加在View层了。
2.需要对新进项目的人员进行一些MVP模式的培训,以便他们不会写出破坏已有模式的代码

引入mvvm的概念。

3.怎么优化MVP 的类文件量?

1.采用泛型定义契约类,将model,view,以及presenter定义在一个契约类里面,这样结构很清晰,一个类对应一个模块

Handler
1、handler是什么?

handler是更新UI界面的机制,也是消息处理的机制,我们可以使用handler 发送消息、处理消息

2、为什么要有Handler?

Android在设计的时候,封装了一套消息创建、传递、处理机制,如果不遵循这样的机制就没办法更新UI信息,就会抛出异常。

3、handler怎么用?

   1、post(Runnable);
   2、postDelayed(Runnable ,long);
   3、sentMessage
   4、sentMessageDelayed

4、Android为什么要设置只能通过Handler机制更新UI?

  为了解决多线程并发的问题;
  因:
  如果在一个Activity中,有多个线程去更新UI,并且都没有加锁机制,更新界面会混乱;
  如果对更新UI 的操作都加锁处理的话会使性能下降
  果:
  所以Android提供了一套更新UI的机制,我们只需要遵循这样的机制就好了。
  不用关心多线程的问题,更新UI的操作,都是在主线程的消息队列当中轮询处理的。

5、handler的原理是什么?

1、handler封装消息的发送(主要包括消息发送给谁)
2、Looper——消息封装的载体。
  (1)内部包含一个MessageQueue,所有的Handler发送的消息都走这个消息队列;
  (2)Looper.Looper方法,死循环,不断地从MessageQueue取消息,如果有消息就处理消息,没有消息就阻塞。
3、MessageQueue,一个消息队列,添加消息,处理消息
4、handler内部与Looper关联,handler->Looper->MessageQueue,handler发送消息就是向MessageQueue队列发送消息。
总结:
 handler负责发送消息,Looper负责接收handler发送的消息,并把消息回传给handler自己。 MessageQueue存储消息的容器。

6、HandlerThread的作用是什么?

 HandlerThread thread=new HandlerThread("handler thread");自动含等待机制,等Looper创建好了,才创建Handler,避免出现空指针异常。

7、主线程

  • ActivityThread 默认创建main线程,main中默认创建Looper,Looper默认创建MessageQueue

  • threadLocal保存线程的变量信息,方法包括:set,get

8、Android更新UI的方式?

1、runOnUIThread
2、handler post
3、handler sendMessage
4、view post

9、非UI线程真的不能更新UI吗?

不一定,之所以子线程不能更新界面,是因为Android在线程的方法里面采用checkThread进行判断是否是主线程,而这个方法是在ViewRootImpl中的,这个类是在onResume里面才生成的,因此,如果这个时候子线程在onCreate方法里面生成更新UI,而且没有做阻塞,就是耗时多的操作,还是可以更新UI的。

10、使用Handler遇到的问题?

比如说子线程更新UI,是因为触发了checkThread方法检查是否在主线程更新UI,还有就是子线程中没有Looper,这个原因是因为Handler的机制引起的,因为Handler发送Message的时候,需要将Message放到MessageQueue里面,而这个时候如果没有Looper的话,就无法循环输出MessageQueue了,这个时候就会报Looper为空的错误。

11、主线程怎么通知子线程?

可以利用HandlerThread进行生成一个子线程的Handler,并且实现handlerMessage方法,然后在主线程里面也生成一个Handler,然后通过调用sendMessage方法进行通知子线程。同样,子线程里面也可以调用sendMessage方法进行通知主线程。

XML和JSON的区别
xml:扩展标记语言
json:一种轻量级的数据交换格式
数据体积方面,JSON相对XML来讲,数据的体积小,传递的速度更快些
数据交互方面,JSON与JavaScript的交互更加方便,更容易解析处理,更好地进行数据交互
数据描述方面,JSON对数据的描述性比XML较差
传输速度方面,JSON的速度要远远快于XML

12、自定义 ViewGroup 的时候,关于 LayoutParams 有哪些注意事项(1. 可以考虑复写哪几个方法,各有什么作用。2. 自定义 layout_ 属性等。)
1.是什么
LayoutParams, 它的主要作用是用来协助ViewGroup进行布局的
在自定义ViewGroup过程中,如果需要定义我们自己的LayoutParams的话,
首先要创建一个类(通常为静态内部类),并继承自ViewGroup.LayoutParams或其子类(这个不用说)
2.重写的方法
ViewGroup需要重写的方法:
generateDefaultLayoutParams()
generateLayoutParams(ViewGroup.LayoutParams p)
checkLayoutParams(ViewGroup.LayoutParams p)
1>generateDefaultLayoutParams方法, 看名字就大概能知道--》生成默认的LayoutParams
这个方法会在 往ViewGroup中添加子View时被调用,如果该子View的LayoutParams为空,或者没有直接调用 有LayoutParams参数的addView方法的话。
2>在ViewGroup添加子View过程中,generateLayoutParams往往和第三个方法checkLayoutParams配合使用, 这个checkLayoutParams就是检查传进来的LayoutParams是否合法的,当然了,里面的逻辑是怎样的,就要看你怎么重写了,默认的实现是做个非空检查。如果检查到传进来的Params不合法的话,接着就会调用这个generateLayoutParams方法。
3>checkLayoutParams虽然说不重写,在一般情况下也不会报错,但还是建议重写,并且在里面判断这个传进来的Params,是不是你自己定义的Params。

3.自定义 layout_ 属性
我们平时在xml里写布局时,通常会用到一些ViewGroup提供的属性, 比如FrameLayout的layout_gravity属性、LinearLayout的layout_weight等等。 可以发现,不同的ViewGroup它们所支持的属性也不同,这个其实也就是自定义的LayoutParams属性了,
那么我们要怎么去自定义LayoutParams属性呢?
首先,要在自定义的ViewGroup中重写一个generateLayoutParams(AttributeSet attrs)方法,等下可以从attrs中拿到各个子View所设置的属性。
接着,也是像自定义View属性那样,在attrs.xml中去定义一些需要用到的属性,这个styleable的命名格式一般为: "ViewGroup名_Layout"
最后,我们就可以回到LayoutParams中,找到有(Context c, AttributeSet attrs)这个参数的构造方法,在这里面就可以获取到子View中设置的属性了。

13、Android 中关于内存泄露有哪些注意点?(可以从常见出问题场景、检测方案等方面回答。)
内存泄漏的根本原因是一个长生命周期对象持有一个短生命周期对象,造成短生命周期对象没有办法被回收所导致的。
常见的有:
1>Application, Activity, Fragment, View之类有生命周期回调方法的,用static修饰很危险,
解决方案:如果万不得已,要在它们被回收前置空;
2>Cursor, Input、OutputStream之类的使用
解决方案:用完后一定要及时关闭,操作这些对象,close方法尽量放在finally块,防止出异常后不能执行;
3>使用Webview都喜欢采用布局引用方式,这其实也是作为内存泄漏的一个隐患,
当Activity被关闭时,Webview不会被GC马上回收,而是提交给事务,进行队列处理, 这样就造成了内存泄漏, 导致Webview无法及时回收.
比较安全解决方案:
1.采用布局中动态添加Webview的方式,
2.在Activity的onDestroyed方法中,先对webview进行移除所有回调,并清除所有javascriptinterface操作然后移除通过父布局移除webview.
还有其他后续再补充

14、谈一下自定义 View 的流程(可以从:1. 自定义 View 的步骤;2. 自定义 View 的注意事项;3. 自定义 ViewGroup的步骤以及注意事项;

  1. 一些特殊需要注意的地方。)

大多数自定义View要么是在onDraw方法中画点东西,和在onTouchEvent中处理触摸事件。
自定义View步骤:
onMeasure,可以不重写,不重写的话就要在外面指定宽高,建议重写;
onDraw,看情况重写,如果需要画东西就要重写;
onTouchEvent,也是看情况,如果要做能跟手指交互的View,就重写;

自定义View注意事项:
如果有自定义布局属性的,在构造方法中取得属性后应及时调用recycle方法回收资源;
某些比较重量级的资源,可以重写onDetachedFromWindow方法,并在此方法中释放;
onDraw和onTouchEvent方法中都应尽量避免创建对象,过多操作可能会造成卡顿;

如果现有ViewGroup的排版或者行为不满足当前需求,就可以自定义ViewGroup
自定义ViewGroup步骤:
onMeasure(必须),在这里测量每一个子View,还有处理自己的尺寸;
onLayout(必须),在这里对子View进行布局;
如有自己的触摸事件,需要重写onInterceptTouchEvent或onTouchEvent;

自定义ViewGroup注意事项:
如果想在ViewGroup中画点东西,又没有在布局中设置background的话,会画不出来,这时候需要调用setWillNotDraw方法,并设置为false;
如果有自定义布局属性的,在构造方法中取得属性后应及时调用recycle方法回收资源;
如果有自己的触摸事件,又不影响子View的行为,需要重写onInterceptTouchEvent并在里面去判断哪些行为是自己需要的,哪些是不需要的;
某些比较重量级的资源,可以重写onDetachedFromWindow方法,并在此方法中释放;

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

友情链接更多精彩内容