安卓开发艺术探索总结

2019.1.11到2019.2.11历时一个月,这本书还算比较详细看完了,虽然说出版时间比较早,里面一些技术没有紧跟当前,这本书主要是教会我们的是安卓思想方面,还有对源码的分析,等等其他方面,这本书不适合入门,但很适合进阶,对于理解安卓开发一些底层源码还有设计师的巧妙思想都很有用,正如记者在书中提到那样,我们不必执着于代码细节,但对于一个整体流程要有清晰的认识,现在也顺便在这里记录其他的事,马上临近大四下学期,做毕设的要求看的书还没看完,考研成绩还有几天出来,希望能有好运气吧,秋招没怎么准备,拿了两个offer也拒了,目前无业游民等待春招,唉扯远了,不管怎样,还是得有上进心,去学校之前把java深入学习一点,同学们看的都是thinking in java,从网上得知java语言程序设计也挺不错的,其实也不必太执着选择什么书入门,坚持学习看完收获自然是有的,下面总结一些安卓开发艺术探索。

第一章:安卓生命周期与启动模式

1.正常的安卓生命周期从onCreate,onStart,onResume,onPause,onStop,onDestroy,顺序执行,加上三个逆行,onPaue->onResume,onStop->onStart,onStop-onCreate。

这里有一个经典问题,当前的activity处有onResume时,创建另一个新的activity覆盖当前activity。两个activity的onPause,与onResume方法调用先后顺序是怎样的,答案是旧的activity会先pause然后新的activity变成resume。具体原因要从源码去分析。

2.异常情况下的生命周期,会执行onSaveInstanceState方法保持杀死的activity的状态,以及onRestoreInstanceState恢复activity的状态。两者情况导致异常的生命周期,系统配置改变,比如旋转屏幕,以及内存不够按优先级从低到高删除activity。

3.安卓的启动模式    重点谈到singleTask这个模式, 与taskAffinity配合可以创建一个新的任务栈,taskAffinity和allowTaskReparenting配合可以应用a的activity转移到应用b的activity。理解安卓的启动模式首先要有任务栈的概念,启动activity是先找到一个任务栈,如果没有就生成,然后往任务栈寻找activity或者添加activity。也可以通过intent设置flag标记位给activity设置启动模式,这个优先级较高,当然singletask默认具有clearTop的效果。

4.activity的隐式调用。是将intent中的action,category,data与activity进行匹配的过程。注意各匹配规则。

 

第二章:IPC机制,跨进程通信。

原因:安卓中,每个进程都分配一个独立的虚拟机,不同进程访问同一个类会产生多份对象副本。

对象序列化,是将对象的一个状态存储起来,ipc机制通信都需要对象进行序列化。有两种方式序列化Serializable和Parcelable。在这里详细介绍一些AIDL,它是通过Binder通信,支持有限数据类型,AIDL中主要是AIDL接口,声明接口后,可以自动生成服务端,客户端代码,两个代码是放在一个java文件中。服务端需要去真正实现接口中的方法,客户端拿到binder对象转化成可操作对象调用服务端上的方法。真正通信的ontransact,和transact只是传递调用的服务端方法的一些信息。

 

第三章:view事件体系。

view的基础知识包括,view的位置参数,坐标系;motionEvent和TouchSlop;手指触摸屏幕会有一系列事件,VelocityTracker,GestureDetector和Scroller。Scroller可以实现弹性滑动,Scroller用来计算view内容所在的位置(随着时间流逝)。再通过view中scrollTo将内容进行定位,不断重绘,实现弹性滑动。

这里分析一下作者自定义的控件HorizontalScrollViewEx,它实现了viewPager水平滑动的效果,然后把listview当作view内容添加进去,拦截水平滑动事件,在onTouchEvent中借助scrollTo进行翻页。至于竖直滑动事件传递给子view,list view。

  public boolean onTouchEvent(MotionEvent event) {
        mVelocityTracker.addMovement(event);
        int x = (int) event.getX();
        int y = (int) event.getY();
        switch (event.getAction()) {
            //view弹性移动期间,传入的down事件view停止
        case MotionEvent.ACTION_DOWN: {
            if (!mScroller.isFinished()) {
                mScroller.abortAnimation();
            }
            break;
        }
        //跟随手指滑动距离,进行相应距离view内容移动
        case MotionEvent.ACTION_MOVE: {
            int deltaX = x - mLastX;
            int deltaY = y - mLastY;
            scrollBy(-deltaX, 0);
            break;
        }
        //手指离开屏幕时,有水平速度方向和没有水平速度方向的情况
        case MotionEvent.ACTION_UP: {
            //view内容左边缘到view左边缘的距离,view左边缘在内容左边缘的右边时为正。
            int scrollX = getScrollX();
            int scrollToChildIndex = scrollX / mChildWidth;
            mVelocityTracker.computeCurrentVelocity(1000);
            float xVelocity = mVelocityTracker.getXVelocity();
            if (Math.abs(xVelocity) >= 50) {
                //有水平速度,根据速度的值对view向左翻页还是向右翻页
                mChildIndex = xVelocity > 0 ? mChildIndex - 1 : mChildIndex + 1;
            } else {
                //没有水平方向速度,根据当前翻页的水平距离超过屏幕一半就翻页(不管开始从哪边翻的)
                mChildIndex = (scrollX + mChildWidth / 2) / mChildWidth;
            }
            mChildIndex = Math.max(0, Math.min(mChildIndex, mChildrenSize - 1));
            //view内容行走的路程,注意开始地点参数是getScrollX()
            int dx = mChildIndex * mChildWidth - scrollX;
            smoothScrollBy(dx, 0);
            mVelocityTracker.clear();
            break;
        }
        default:
            break;
        }

        mLastX = x;
        mLastY = y;
        return true;
    }

 

第四章   view的工作原理

scrollTo、scrollBy方法移动的是View的content,即让View的内容移动,如果在ViewGroup中使用scrollTo、scrollBy方法,那么移动的将是所有子View,但如果在View中使用,那么移动的将是View的内容,例如TextView,content就是它的文本;ImageView,content就是它的drawable对象。

view的显示要经过三个过程,测量,布局,绘制。measureSpec是从上传下的,即子view的measureSpec与父容器的measureSpec以及自身的layoutparam有关。但是父容器的大小并不就是measureSpec存储的大小SpecSize,父容器若是warp_content则还设置大小时,先测量子view大小,最后再测量自身大小。所以measureSpec与view测量有关,但view大小并不等于它。

view的绘制流程是从viewRootImpl开始的,这也跟后面的第八章window章节有关。window是一个抽象的概念,每一个window都对应着一个viewRootImpl和一个view。window和view通过viewRootImpl关联。viewRootImpl中的setView完成两个过程,将view绘制在界面上,还有添加view依附的窗口(这是一个ipc过程,通过类似于添加activity的application的session,session远程调用wms添加窗口。session和applicatioinTread一样都是一个binder对象。)添加window和添加view是两个不同的过程,比如给listview添加子view,这是添加子view的过程,window是已经存在。而添加window时,也会有添加view过程,但是与前者不一样,比如创建一个dialog过程,toast。它相当于在手机上再加一个屏幕,然后在新的屏幕画画,而添加子view还是在原来屏幕上画画。

 

第五章:RemoteView

主要用在通知栏和桌面小部件。它是一个跨进程更新界面。它给我的感觉就是一个存储信息的parcelable对象,并支持binder过程。remoteview中的apply方法是在服务端上调用,其内部是新建view,并将传过来的view信息进行绑定在view上。这里就不详谈了,记住如果要跨进程更新view那么知道可以用remoteview就行。

 

第六章  drawble

大都是用来给view设置背景,并且种类繁多,我原来也只记得bitmapdrawable和shapedrawable。稍微有个印象,反正我这样记住,drawable分为静态背景和动态背景,静态的包括我之前提的两个后面的是动态背景。

 

第七章 安卓动画

安卓动画分为view动画和属性动画。view动画包括四种,平移,缩放,透明,旋转。view动画设置比较简单,可动画xml方式,再通过view中的setanimation方法就可以了,view动画还可以用在LayoutAnimatioin和Activity切换。下面侧重谈一下属性动画。ObjectAnimation,ValueAnimation以及AnimationSet。插值器和估值器,插值器用来计算属性变化的弧度,估值器用来计算改变后属性具体的值。属性动画并不是随便用的,它也是有要求的,要求view提供做属性动画的属性的set和get方法,一般是类来包装对象,间接的为其提供set和get方法。valueAnimation是对值做动画,它本身不作用任何对象,我们可以根据值的变化,对对象做动画。

 

第九章  四大组件工作过程

这一章是重点。它对我们深入理解安卓有很大帮助。AMS非常重要,它是管理四大组件核心,https://www.jianshu.com/p/47eca41428d6,这篇文章讲的很好,简单来说,手机上只有一个AMS处在运行中,每个应用获取它的代理对象,然后与它跨进程通信,在AMS中有维护活动的栈,启动一个活动,需要先跨进程在AMS中“注册”,然后AMS通过applicationTread跨进程,通过应用的activityThread进行前台显示,打个比方,其实他后安卓中的hander有点像,发送信息和信息处理都是hander,但是需要looper去帮助。而activity的开始与显示都是activityTread去做,但也要AMS去帮助。其他组件也是有着同样的道理,都需要AMS作为一个中转器。应用跨进程与AMS通信是通过AMS一个代理对象,AMS与应用通信需要其他binder对象。大概就这样,具体细节还是需要去书上和源码部分观看。

 

第十章 android消息机制

重要是理解hander,messagequeue,looper,这三个都是同等重要的。主要用于把任务切换到指定线程,在安卓中常常用来更新UI,创建一个handler需要looper进行初始化,这要求线程有looper,虽然新建handler没有传参给构造函数,但是threadlocal会在handler内部将looper传给handler。handler在其他线程插入消息给messageque,而指定任务线程通过looper做轮询操作,当有新消息时,通过handler处理,handler有三个方式处理消息,msg的callback,hander的callback,最后handler的handlermassage方法。其实关于主线程也是拥有looper,和handler的,我们用手机时对于一些控件的操作,与它相关性很大。之前面试经常会提到一个问题就是主线程的looper一直做循环,那怎么响应我们的点击等事件。这个问题本身就很有问题,正是因为主线程looper的轮询操作才可以响应我们的事件,如果退出循环,那程序执行完了,就直接关机了,和我们编程的cmd窗口有点像,而要求手机可以和用户交互,那么这个程序是一直循环的。阻塞和程序执行完还是有区别的。

 

第十一章 线程和线程池

AsyncTask,是一个封装很好的轻量级异步任务类可以异步完成任务同时可以更新UI。AsyncTask里面有任务排队线程池和执行任务线程池。execute(多个params)和多个execute(单个params)是不同的,前者肯定会串行执行,后者可能并行。intentservice和handlertread与上一章有关,比较简单,这里提及一下new一个handler如果不传参给构造函数,那么他会默认以当前线程的looper进行初始化。线程池是比较重要的,文中也只要求掌握四种线程池,其实他们都是通过一个类构造的,线程池的调用也比较简单,只需要execute一个runnable对象即可。

 

第十二章  bitmap高效加载和cache

bitmapFactory主要是根据要求的图片的大小得到采样率,得到一个低分辨率的图片再设置给view。关于cache,首先要明白LRU算法。对于LruCache和DiskCache的利用简单掌握即可,对于磁盘操作,并不能像内存一样直接添加缓存,查找缓存,他会复杂一点设计到文件输入输出流,和网络上通信输入输出流类似。章节最后实现的一个imageloader很有意思,同时也让我得到一些启发,关于客户的一些细节操作,比如滑动,都需要考虑是否有性能方面的原因。

 

后面比较简单也不详细再讲了,比较重要的有内寸泄漏,安卓有三种,静态变量,单例模式,属性动画,内存泄漏会造成java垃圾回收器无法gc没用的对象。实质上是由于对象的引用造成要释放的对象的生命周期变得“与天同寿”。

写这篇总结的时候我又回去翻了一下书和看了下代码,收获还是挺多的,同时原来一些不懂的问题也理解了。刚开始看书可以不求甚解,因为有些问题不是当时能解决的,看完一本书再去翻翻它,可以更加深入理解,怪不得一本书读一遍是远远不够的。

2019.2.12记

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值