something interesting

findViewById findviewbyid用来根据id找到对应的view组件,可以直接调用activity的findviewbyid方法,也可以通过一个view的findviewbyid方法找到。这两个有什么区别? activity的方法,是通过getwindow–getdecorview的findviewbyid方法去查找的,decorview是最顶层的父控件,所以最终是通过view的getviewbyid方法去查找的。findviewbyid没有再被重写,但是其中调用的findViewTraversal会被viewgroup重写,在这个方法中,viewgroup会在自己的children中遍历查找id,这也是一个树形遍历的过程,每个child也会去找自己的children,最终到view就是去比较view的id跟当前的id是不是匹配。由此可以看出,parent的层级锁定的约低,查找的view就最少。 SharedPreferences SharedPreferences是用来做一些简单数据的存储共享的,线程安全的,其实现类是SharedPreferencesImpl,在创建的时候会去load数据,因为sharedPreferences中的内容都是通过xml文件存储的,这是个比较耗时的操作,所以会开启新线程去做这件事,load的时候会加对象锁,加载后会notifyall,对应每次读取数据前awaitLoadedLocked的wait,等到读取完成之后才能返回数据。 getSharedPreferences的方法在context中,其实现最终是在ContextImpl中,其获取的时的name与file一一对应,放在context的mSharedPrefsPaths,而file与SharedPreference对应, 开新线程觉得耗时问题 线程安全,进程不安全。 之所以看这部分的源码是因为一个面试官说到SharedPreferences的关联启动优化问题,所以简单看了load部分的源码,系统已经做过开启线程的处理,所以在启动的时候在最早去做一次开启新线程load的处理,并不会起到优化的作用啊? 不过这里面提到了另一个生命周期的问题,在onCreate里面去做这个处理已经比较晚了,所以有没有比oncreate更早的时候,搜了一下,大概是这个过程: main()->Application:attachBaseContext()->onCreate()->Activity:onCreate()->onStart()->onPostCreate()->onResume()->onPostResume()。可以在attachBaseContext里面做这个操作。 关联—-multidex 和 启动优化的相关知识。 view设置gone时,view在layout布局文件中不占用位置,但是该view还是会创建对象,会被初始化,会占用资源。...

1 minute read

问题整理(更新至7.25)

Android基础篇 onclicklistener是如何调用的 就是在UP事件中创建一个实现了Runnalbe接口的PerformClick对象,run方法中调用performClick执行点击,在handelr中post,如果post失败则执行方法performClick立即执行onClickListener的onClick方法 onTouchListenerd的onTouch方法 > onTouchEvent > onClickListener onLongClickListener是如何实现的 CheckForLongPress实现一个Runnable接口,run方法中执行performLongClick方法执行长按的处理。 <— CheckForLongPress在checkForLongClick方法中创建,并在私有变量mPendingCheckForLongPress中存储。 <— checkForLongClick方法创建CheckForLongPress对象后,发送一个延迟事件,在特定时间之后执行CheckForLongPress,延迟的时间为系统设定的长按的时间-传入的延迟时间(一般为0,特殊处理时在CheckForTap中,暂时不关注)。 <—...

3 minute read

MVP、MVVM(未完)

MVP模式 mvp模式(model, view, presenter)主要是解决MVC模式中,M和V的交互。基本结构如下,view表示界面,负责和用户的交互,在有交互事件时,通过presenter来实现相关的业务逻辑。Presenter负责更新model层,并且在model发生变化时,同步给view,而不是由model直接同步给view。 (按照对mvc、mvp和面向对象的理解,觉得目前项目中的代码可能连mvc都不算,没有实现v和m或者c和m的划分,model虽然表示数据层,但从面向对象的思想来说,model也是一个对象,对象应该是包括属性和行为的,只包含属性以及getter、setter的对象应该再去考量是不是设计有问题(当前数据定义没有什么可改的,应该是controller中的逻辑太多)。所以,数据相关的行为应该放在数据层,很多时候,这些相关逻辑都放在了v或者c中,有时候复杂数据逻辑抽离在utils类,但是调用仍然是在controller中) model: TaskReposiry,定义了很多task的创建、更新、获取等接口,整个app内公用的数据模型。在Injection类中获取,TaskRepository持有远程数据源 (FakeTasksRemoteDataSource),和本地数据源(TasksLocalDataSource)的实例,三者都是单例模式,继承TasksDataSource接口,提供数据以及相关操作功能。 view:AddEditTaskFragment,持有界面中的字view,继承自AddEditTaskContract.View,对外提供界面相关的操作接口,比如showTaskList, setTitle等。持有presenter,当界面需要显示或保存数据时,借助presenter操作datarepository。 presenter: AddEditTaskPresenter, 持有view和数据model,数据的获取和存放,都通过presenter,获取和存放的逻辑以及关联的操作逻辑(比如保存之后要显示列表)都在presenter中,view只提供简单的展示和切换逻辑。 隔离了view和数据,解耦了数据反向对view的通知,数据变化对view的操作,通过presenter调用view对外的接口进行。与mvc的区别就是,类似controller角色的presenter可以反作用于view。mvc中controller像是为view服务的,view持有controller,触发controller去操作,而presenter也可以对view的接口进行操作。这样的好处是,view不依赖于model,所以数据如何定义获取操作view不关心,可以专注于于用户的交互,因此可以实现复用。在实例的架构中,presenter、view的相互持有都是持有接口的,所以替换presenter的实例和view的实例都很方法,因此都是很方便复用的。 问题:跟activity,fragment的生命周期相关的逻辑;复用的可能性?会出现大量的presenter,presenter之间的交互需要考虑路由机制等;划分逻辑块?有很多功能应该数据更新很少,presenter来解耦model和data的意义似乎不大,但是presenter划分view和逻辑块的想法可以考虑。...

2 minute read

与h5的交互

JSBridge 原理 设置具备与js交互的能力,通过mWebView.addJavascriptInterface的方式将JavaScriptinterface对象交给页面(WebView.addJavascriptInterface接口向Web页面注入Java对象,页面Javascript脚本可直接引用该对象并调用该对象的方法。) ——> 页面可以调用JavaScriptinterface的方法 JavaScriptinterface实现所有接口的执行方式。 JavaScriptinterface中持有一个handler,通过handler来处理调用app的一些方法。 传入参数:所有的方法的调用参数都有一个json串,在方法中解析这个json串按照约定的格式解析出对应的需要参数。 回调:在页面传入的json数据中会有callback_id,app在接收到数据后会解析出里面的callback(方法名)和callback_id(回调的id),再加上结果拼成调用javascript的url:“javascript:callback(‘callbackid’,result);然后通过webview的loadurl来发送这个方法。 调用js,就是通过loadurl public void setJSBridge(Activity activity, WebView...

1 minute read

Handler学习(未完)

Handler, MessageQueue, Looper Handler: 外界通过handler发送Message,handler将Message放入MessageQueue中 Handler收到looper调用处理Message的方法,根据消息内容做相应处理(dispatchMessage)。调用的位置决定了处理消息位于哪个线程。 MessageQueue: 存放Message的队列 Looper: 循环从MessageQueue中取出message,调用Message中的Target的diapatch方法实现消磁处理(即Handler) 源码解析 Message结构本身是一个数据链表。 Looper的作用就是从消息队列中取消息交给handler去处理。 looper是一个线程一个的,Looper类可以认为是一个单例模式,只不过有几点特殊:(1)不是传统的static持有自己对象,而额外加了ThreadLocal来标明是线程内独有的,因此looper的方法几乎都是public static修饰的。(2)创建looper不是在过去的时候,而是在prepare中,在获取的时候直接用当前ThreadLocal的get方法来返回...

5 minute read

AsyncTask, HandlerThread, IntentService源码解读

AsyncTask, HandlerThread, IntentService源码解读 AsyncTask 线程池的配置参数 private static final int CORE_POOL_SIZE = Math.max(2, Math.min(CPU_COUNT - 1,...

10 minute read

事件分发学习中的疑问与解答

当一个viewgroup中有重叠的view时,是如何决事件处理的? 在viewgroup遍历子view时,是通过一个list去遍历,然后分别判断每个view是否包含当前event中的坐标点来决定是否有接收事件的资格。 判断范围,可以看出,在判断点是否在组件内时并不会考虑同级view的遮盖,只考虑父组件的位置,因此,能够判断分发顺序只需要考虑在list中的顺序,在顺序前的先被执行。在生成list时,是通过 buildOrderedChildList方法构建了一个先序列表,方法的注释是如下,大概意思就是按照z轴排序,然后再按照控件的绘制顺序,也就是添加到group的顺序。在遍历的时候反向遍历,从最后一个开始遍历,因此z最大或者最后添加的接受事件的优先级更高 /** * Populates (and returns) mPreSortedChildren with a pre-ordered list of...

2 minute read

ListView优化

ListView优化 1- convertView重用: 在getview中先判断convertView是否为空,这样在view没有改变宽高时,可以减少重新分配缓存; 2- ViewHolder优化:findViewById方法耗时较大,viewholder中持有各个view控件,然后利用view的setTag,getTag直接获取View。 3- 当ListView滚动时busy设为true,停止各个view的图片加载。否则可能会让UI不够流畅用户体验度降低。(这个下载控制并不能处处用到:建议是glide的功能项目地址:https://github.com/bumptech/glide) OnScrollListener() { @Override public void onScrollStateChanged(RecyclerView recyclerView,...

1 minute read