Android使用总结


##View篇##
###TextView### - 中文标点不能做换行breakpoint,英文标点和空格可以做换行 - TextView的HTML写法 - 1dp = 1 * density px 在默认字体大小时 1sp=1dp - 默认TextSize:14sp
###ImageView###
  • 放大ImageView两种方法:

    1. scaleType:FIT_MATRIX

      imageView.setImageMatrix(matrix);

      可用于实现双手缩放效果

    2. scaleType:FIT_XY

      然后通过改变LayoutParam实现大小改变

  • ImageView默认scaleType:FIT_CENTER

  • scaleType:
    center : 将图片缩放成宽度和View相同,高度截取中间部分
    centerCrop : 高度和View相同,宽度截取中间部分

  • WebP格式

  • setImageURI、setImageDrawable方法

  • ImageView也有setSelected方法,替代Checkbox


###EditText### - 让EditText一进入时失去焦点: 在父View上加 android:focusable="true" android:focusableInTouchMode="true"
###GridLayout### - 设置Item XML android:layout_gravity="fill_horizontal|center_vertical" http://toughcoder.net/blog/2015/11/25/android-tricks-introduct-to-gridlayout/
###ViewStub###
  • 实现蒙层的利器,占用资源小。只能调用inflate一次。

###include### 用法:http://developer.android.com/intl/zh-cn/training/improving-layouts/reusing-layouts.html include指定android:id会覆盖layout中根View的ID,如果layout的最外是merge,则id无效,所以如果include两次同一个merge layout,需要在include外面放一个layout以作区分 include覆盖layout_xxx时要同时覆盖layout_width和layout_height include无法覆盖merge的margin和padding属性 include无法覆盖background属性, 需要写在layout里面 include无法覆盖layout_weight属性, 需要在include外面放一个layout指定weight include无法覆盖padding属性
###ListView###
  • 使用ViewHolder节省findViewById的时间

  • 判断convertView是否为空才inflate view

  • ListView的分页加载

  • 需要顶部、底部均有间距的话可以在代码里通过getPos()来动态设padding

  • android:descendantFocusability属性

  • 让父View的Selector起作用而子View的Selector不起作用:重写ViewGroup的dispatchSetPressed()方法

  • requestDisallowInterceptTouchEvent

  • ListView item最外层margin无效 http://www.cnblogs.com/xitang/p/3677528.html
    item的Height无用,只能通过Padding来确定大小

  • ListView有HeaderView时 onItemClick正确方法
    @Override
    public void onItemClick(AdapterView<?> parent, View v, int position, long id) {
    doSomething(parent.getAdapter().getItem(position));
    }

  • ListView xml设置Divider,还要setDividerHeight才能显示出来,dividerHeight默认是0
    若设置Item间距,可以setDivider(null),setDividerHeight(6dp),使Item之间有6dp的空白
    当ListView有Header的时候,默认有HeaderDivider,否则默认没有HeaderDivider

  • ListView不能调用removeAllViews

     <ListView
     	android:id="@+id/page1_listview"
     	android:layout_width="match_parent"
     	android:layout_height="match_parent"
     	android:layout_above="@id/page1_bottom"
     	android:layout_alignParentTop="true"
     	android:cacheColorHint="#00000000"
     	android:divider="#00000000"
     	android:drawSelectorOnTop="false"
     	android:fadeScrollbars="true"
     	android:footerDividersEnabled="false"
     	android:listSelector="@android:color/transparent"
     	android:paddingLeft="@dimen/ls_password_choose_listview_margin"
     	android:paddingRight="@dimen/ls_password_choose_listview_margin"
     	android:scrollbarStyle="outsideOverlay" />
    

###GridView###
 <GridView
    android:id="@+id/gridview"						
    android:layout_width="match_parent"						
    android:layout_height="match_parent"
    android:layout_gravity="center"
    android:background="#e3e3e7"
    android:cacheColorHint="#00000000"
    android:divider="@null"
    android:dividerHeight="0dp"
    android:drawSelectorOnTop="false"
    android:fadingEdge="none"
    android:fadingEdgeLength="0dp"
    android:gravity="center"
    android:horizontalSpacing="0dp"
    android:listSelector="#e3e3e7"
    android:numColumns="2"
    android:overScrollMode="never"
    android:paddingBottom="4dip"
    android:paddingLeft="6dip"
    android:paddingRight="6dip"
    android:paddingTop="4dip"
    android:stretchMode="columnWidth"
/>
  • 防止OOM:使用LRUCache,LessRecentUse

    使用DiskLruCache


###ViewPager### - 默认不允许禁止滑动,需重写onInterceptTouchEvent方法 - 通过onScollListener实现滑条
###Gallery###
  • 配合ImageSwitcher实现画廊效果

###SurfaceView### - setZOrderOnTop... 设置ZOrder
##布局篇##
  • 使用代码硬生成View减少Inflate XML的时间
  • 使用include和merge标签
  • 去掉所有不需要的属性
  • 用hierarchyviewer和layoutopt工具分析

##性能篇##
  • 检测函数耗时:
    使用API检测:StrictMode、Debug.startMethodTracing
    使用工具检测:DDMS、Traceview
  • 软引用、弱引用
  • 使用Byte[]保存Bitmap来突破内存限制
  • 使用Native进程来突破Dalvik虚拟机的内存限制

##内存泄漏篇#
  • 内存泄漏原因:垃圾对象直接或间接地引用到GC Roots导致无法被GC回收。

  • 内存泄漏种类:1.Context泄漏,Activity的引用的生命周期超越了Activity对象的生命周期。

  •           解决方式:不要对Activity的Context长期引用(一个Activity的引用的生存周期应该和Activity的生命周期相同);如果可以的话,尽量使用关于Application的Context来替代和Activity             相关的Context;不要使用静态的Drawable、Bitmap赋予Activity中的View;Activity onDestory时及时回收对象,关闭Cursor,Looper quit,广播接收解注册,清空集合类。
    
  •         2.非静态内部类对象会持有对外部类对象的引用
    
  •          如果一个acitivity的非静态内部类的生命周期不受控制,那么正确的方法是使用一个静态的内部类,并且对它的外部类有一WeakReference,就像在ViewRootImpl中内部类W所做的那样。
    
  •         3.线程问题:对于不是HandlerThread的线程,也应该确保activity消耗后,线程已经终止,可以这样做:在onDestroy时调用mThread.join();
    
  • 分析内存泄露:DDMS、MAT
    http://blog.csdn.net/gemmem/article/details/13017999


###代码篇### - 不使用的方法,不要删除,可以标记为Deprecated - 重写的方法一定要加Override - 一定要注意绘制方面的东西,不要在onDraw()/onTouchEvent()中创建新对象。
##Canvas篇##
###Paint###
   // 抗锯齿,允许机器适配字体间距
   mPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.DEV_KERN_TEXT_FLAG);
   // 防抖动
   mPaint.setDither(true);
   mPaint.setBitmapFilter (true);
   mPaint.setTextSize(40);  //单位是px

###过渡模式Xfermode### - 画不规则形状 - 画遮罩层
###渐变Shader###
  • LinearGradient
    IOS滑动向右解锁效果,水平歌词效果
  • RadialGradient
    渐变透明的圆

###Matrix### 3*3矩阵

--------- | ---------
Translate | 平移变换
Rotate | 旋转变换
Scale | 缩放变换
Skew | 错切变换

http://blog.csdn.net/linmiansheng/article/details/18801947


###关系###
  1. Bitmap:画布
  2. Paint:画笔
  3. Canvas:画笔的操作区
    Canvas的左上点是画笔的基准点。Canvas做Translate做Rotate,画笔的基准点随之变化,但已画上的内容不会再变,不受canvas.restore的影响

###onDraw()###

在onDraw方法里尽量不new对象
清屏:mCanvas.drawColor(Color.TRANSPARENT, Mode.CLEAR);
canvas.drawBitmapMesh:


###双缓存技术### 将不变的内容先画到一个Bitmap上,onDraw里先画这个Bitmap再画变化的内容。 SurfaceView使用了双缓存技术,前后两个Canvas,lockCanvas先画后面Canvas,unlockAndPost把前后交换
###Rotate### canvas默认rotate的中心点是(0,0), 顺时针旋转 canvas每save一次,就往栈里压入一个save状态,每restore一次就把栈顶save的状态取出来,所以restore次数可以<=save次数 http://www.jianshu.com/p/3efa5341abcc http://www.curious-creature.com/2013/12/21/android-recipe-4-path-tracing/
##动画篇## 动画分三种:Animation(Tween Animation)、Animator(Property Animation,3.0以后有)、AnimationDrawable(Frame Animation)。
###Animation### ScaleAnimation和RotateAnimation需要指定中心点。PivotX、PivotY默认是左上点,不论是Absolute、RelativeToSelf还是RelativeToParent 需要设置正确。

继承实现自己的Animation:
变换矩阵:pre是右乘,post是左乘

View animation,它只是改变了View对象绘制的位置,而没有改变View对象本身属性,比如,你有一个Button,坐标(100,100),Width:200,Height:50,而你有一个动画使其变为Width:100,Height:100,你会发现动画过程中触发按钮点击的区域仍是(100,100)-(300,150)。


###Animator配合View和SurfaceView的canvas.draw方法### Animator存在适配风险,在有些手机上回调一直是0,无法使用 与Animation,Animator改变的是对象的实际属性,并且可用于除View外的其他对象 KeyFrame:关键帧,在特定时间处于的状态 TimeInterpolator:插值器,对时间因子进行变换,如默认匀速执行则直接返回该值 TypeEvaluator:估值器,接收由TimeInterpolator传递来的时间因子来计算属性值,然后将该值setAnimatedValue返回给Listener,可以重写该类实现返回的值getAnimatedValue是Point等类型
###ObjectAnimator### [http://www.cnblogs.com/angeldevil/archive/2011/12/02/2271096.html](http://www.cnblogs.com/angeldevil/archive/2011/12/02/2271096.html)

布局动画###

LayoutTranstion
http://www.admin10000.com/document/4926.html


##常用类篇##
###Handler### - 拥有Looper的Thread为LooperThread,LooperThread可以防止过多线程新建;主线程默认有MainLooper,不需要我们生成。 - Handler是对发送、处理、删除、判断Msg的封装。Handler与拥有的Looper处在同一线程。Handler用于线程间通信。 - handleMassage里不要阻塞线程,否则会阻塞Looper,再也无法处理Msg - Msg通过Message.obtain()取出来,不要new Message();类似的Parcel使用Parcel.obtain(); - 使用 `Handler handler = new Handler();` 写法时,
该Handler关联的是new语句所在线程的Looper,如果该线程里没有Looper,就需要
	Looper.prepare();
	Handler handlerInThread = new Handler(); 
	Looper.loop();

 否则会报错。 最后线程退出时别忘记`handlerInThread.getLooper().quit();`
  • Looper.myLooper()方法得到的是调用这句话所在的线程所拥有的Looper
  • HandlerThread是系统封装好的带Looper的Thread
  • runWithScissors方法:在执行完Runnable前阻塞

###AsyncTask### - excute方法在主线程调用,只能调用一次 - AsyncTask的本质是一个静态的线程池,AsyncTask派生出的子类可以实现不同的异步任务,这些任务都是提交到静态的线程池中执行。
##Github篇## GraphView:https://github.com/jjoe64/GraphView
JazzViewPager: https://github.com/jfeinstein10/JazzyViewPager XUtil框架:
##资源篇##
###Selector### - 实现按钮的点击效果
###Style### - 封装TextView、ImageView的样式
###Theme### - 重写系统的Activity Theme,实现闪屏页
	<?xml version="1.0" encoding="utf-8"?>
	<style name="Theme.Splash" parent="@android:style/Theme>
	<item name="android:windowNoTitle">true</item>
	<item name="android:windowBackground>@drawable/splash</item>
	</style>
  • Theme里.自动具有继承关系 如style name="AppTheme.ActionBar.OverlayActionBar"是style name="AppTheme.ActionBar"的子类

###Shape### - 渐变色蒙层,与Drawable相比减少资源消耗
###Layer###
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item>
  <bitmap android:src="@drawable/android_red"
    android:gravity="center" />
</item>
<item android:top="10dp" android:left="10dp">
  <bitmap android:src="@drawable/android_green"
    android:gravity="center" />
</item>
<item android:top="20dp" android:left="20dp">
  <bitmap android:src="@drawable/android_blue"
    android:gravity="center" />
</item>
</layer-list>

###Clip、Scale、Inset###
##网络篇##
###HttpURLConnection### Accept-Encoding: gzip 但是如果启动了响应压缩的功能,HTTP响应头里的Content-Length就会代表着压缩后的长度,这时再使用getContentLength()方法来取出解压后的数据就是错误的了。正确的做法应该是一直调用InputStream.read()方法来读取响应数据,一直到出现-1为止。 Android2.3以后建议使用HttpURLConnection,而不再使用HttpClient Google网络模块框架:Volley OkHttp
###断点续传### ![](//images0.cnblogs.com/blog/532901/201501/282147430506157.png)
##多线程篇##
  • 锁的重入:获得一个锁的同一线程可再次获得该锁
  • 类锁、对象锁、私有锁属于三种类型的锁,不会相互影响,同一类型相互影响
  • 不可变对象一定是线程安全的,封装有助于管理复杂性
  • 锁既保证原子性,又保证可见性;Volatile只保证可见性,不保证自增的原子性
  • 不要在构造方法里使用匿名内部类,会导致This溢出,不能安全发布
  • 线程抛出异常时会释放锁,调用Thread.interrupt()只是改变标志位,对于wait\sleep\join阻塞会立即抛出异常,对于IO阻塞下次IO时抛异常,正确写法是结合Thread.interrupted()作为循环条件;
  • wait()写在While循环里面,防止虚假唤醒;wait、notify作为信号传递,存在信号丢失的风险,而信号量Semaphore不用担心信号丢失。http://blog.csdn.net/sunset108/article/details/38819529
  • Android内部使用的同步机制:Mutex、Condition
  • Timer是单线程实现的,有很多问题,不要使用;使用ScheduledThreadPoolExcutor
  • 同步容器(Vector等)虽是线程安全的,但问题很多,遍历时可能报ConcurrentModificationException,解决方法是遍历时整体加锁;并发容器是线程安全的,便利时Iterator不会报ConcurrentModification Exception,但size()和isEmpty()方法可能返回的是无效数据,不能依赖他们。
  • Bernstein条件
  • ConcurrentHashMap通过降级锁粒度和锁分段提高性能,get方法不需锁是靠Volatile变量实现同步
  • Android 线程间通信:Handler
  • Android 进程间通信:Binder
  • 因为Android UI组件不是线程安全的,所以使用线程封闭,只有主线程能够操作UI。Activity生命周期、按键触摸绘图回调运行在主线程,onReceive()里不要做耗时操作,耗时操作发给Service处理
  • 改变线程优先级必须非常小心。增加一个优先级可加载这个线程执行速度,但是会对其他线程造成负面影响,让他们无法获得CPU资源,从而影响用户体验。

##组件篇##
  • 组件可以通过配置Manifest运行在不同进程,但不同进程拥有不同的ApplicationContext,所以另一进程的组件访问不了这一进程的SharedPreference;
  • Context:环境上下文。提供了应用运行的全局性信息,包括是公有属性和公有方法,各组件和系统服务通信的桥梁。
  • 四大组件默认运行在UI线程中,不要做耗时操作。或者使用异步工具:IntentService、AsyncQueryHandler

###Activity### - 在Manifest里配置android:configChanges="orientation|screenSize"并重写onConfigurationChanged方法实现横竖屏切换,此时不会调用onSaveInstanceState - 按Home键或者旋转屏幕,会在onPause后调用onSaveInstanceState,onResume前调用onRestoreInstanceState。默认系统回收Activity,会遍历View树保存状态,可以自定义View的setSaveEnable。 - 旋转屏幕后,如果调用setContentView(main.xml),会根据目录自动匹配同名的垂直、水平两个main.xml
###Service### - Service与Thread没有关系,Service意义是运行在后台,不可见,而默认不具有单独的线程 - Service需要注意生命周期。通过context.startService启动的默认是不会结束自己的,可以调service.stopSelf()或者外部调context.stopService来结束;bindService启动的,调用者都挂掉,Service走到onDestory,或者绑定者都调用了unbindService,此时Service走到onDestroy;先start后bind的Service,生命周期和start的(大致)相同,unbindService之后也不会结束;IntentService不用stopSelf();不能在广播接收器里bindService,只能startService;如果bind的是Activity,如果Activity stop了,Service可能不再执行,直到Activity resume - 拥有前台服务的进程为前台进程,优先级最高; - 前台服务通知的隐藏:再启动一个具有相同ID的前台服务,再关闭此服务,则通知消失 - 如果是跟页面相关的服务可以通过activity.bindService实现,如果是全局的服务,则用Application.bindService更佳。 - onBind方法只运行一次,绑定多个客户时返回已生成的Binder - onRebind - 服务分为本地(Local)服务和远程(Remote)服务:绑定服务使用bindService。远程服务通信的快速实现使用AIDL。 - 绑定Service可以分为三种形式:Binder(绑定本地服务)、Messager(简单)、AIDL(可操作性大) - 三种方式的区别: 本地Binder:onBind方法返回一个IBinder对象,该对象应当继承系统Binder,通信操作实现在Binder子类里;返回的IBinder对象类型转换成子类Binder即可操作。注意这种方式并没有使用Binder的跨进程逻辑。 public class MyBinder extends Binder { public BindService getService() { return BindService.this; } } 远程AIDL:通信操作定义在AIDL文件中,自动生成XXX.Stub,服务端须实现该XXX.Stub,并在onBind方法里返回该对象;返回的IBinder对象需要通过asInterface(iBinder)方法获得本地代理对象才可操作 `private final IKeyguardService.Stub mBinder = new IKeyguardService.Stub()`
远程Messager: @Override public IBinder onBind(Intent intent) { Log.e(TAG, "onBind"); return mMessenger.getBinder(); } 后两者可参考APi Demos中的RemoteService和MessengerService - 进程间双向通信:Messager\AIDL+RemoteCallbackList Messenger把所有client的请求放入一个请求队列,而AIDL允许同一时间处理多个client的请求,这就需要server端做同步处理。此外,如果使用Messenger的话,不能直接访问 service的方法。 [http://www.eoeandroid.com/blog-739414-38493.html](http://www.eoeandroid.com/blog-739414-38493.html) [http://vaero.blog.51cto.com/4350852/1188608](http://vaero.blog.51cto.com/4350852/1188608) - AIDL:接口描述语言,保证客户端/服务端接口的一致性,尤其简化了多个通信方法问题。如果没有AIDL,你就得自己写Transact方法,AIDL是对Client与Server通信代码的自动实现机制 [http://android.blog.51cto.com/268543/537684/](http://android.blog.51cto.com/268543/537684/) - AIDL关键字:in out oneway,所有异常均不会发给调用者 - AIDL标准写法参考系统的KeyguardService - AIDL 支持的数据类型划分为四类,第一类是 Java 编程语言中的基本类型,第二类包括 String、List、Map 和 CharSequence,第三类是其他 AIDL 生成的 interface,第四类是实现了 Parcelable 接口的自定义类。 其中,除了第一类外,其他三类在使用时均需要特别小心。 使用第二类时,首先需要明白这些类不需要 import,是内嵌的。其次注意在使用 List 和 Map 此二者容器类时,需注意其元素必须得是 AIDL 支持的数据类型,List 可支持泛型,但是 Map 不支持,同时另外一端负责接收的具体的类里则必须是 ArrayList 和 HashMap。 使用第三、四类时,需要留意它们都是需要 import 的,但是前者传递时,传递的是 reference,而后者则是 value。 - AIDL只能传递Java的基本数据类型、字符串、List或Map等。那么如果我想传递一个自定义的类该怎么办呢?这就必须要让这个类去实现Parcelable接口,并且要给这个类也定义一个同名的AIDL文件。 - 使用Binder进程间是同步不是异步的,所以耗时进程间通信放在子线程里。服务主动回调客户端:RemoteCallbackList,注意回调回来不是主线程。 - 因为Android限制进程的内存空间,故可以通过多进程来间接增加内存空间
###BroadcastReceiver### - 有序广播 - LocalBroadcastManager:广播只在本程序内传递
###ContentProvider### - CursorWindow - ContentResolver - Loader
##源码篇## - 带有Locked的函数,表示提醒我们必须注意保证这些函数的线程安全 - IXXX继承自IInterface且有Stub内部类的是AIDL自动生成的文件;带有IXXXManager、IXXXService的类,表示某项跨进程通信服务的本地代理对象,如IActivityManager、IKeyguardService,外面可能包一层XXXManager、XXXServiceWrapper,通过它们可以直接操作远程Server - AMS\WMS本身不是Service,是Binder,因为这两个服务能保证始终运行,并且注册到了ServiceManager里,所以无须挂载在Service上
###启动### - 开机:Zygote进程fork出SystemServer进程,启动SystemServer main()函数,所有系统服务运行在SystemServer进程中 - 应用的启动:SystemServer通过Socket与Zygote进程通信,Fork出子进程,启动ActivityThread main()函数 - WatchDog:不断检查ActivityManagerService等系统服务是否死锁
###按键事件### - 按键事件**父View**优先处理,Touch事件**子View**优先处理;
- 按键事件先发给有Focus的View,如果该View没有处理再交由Activity处理,如果都没有处理再交由WMS处理。
Home键、长按Menu键默认被PhoneWindowManager拦截了,不传给APP。
###ViewRoot### - 实现Handler,绘制界面、处理按键,View类的getHandler得到的就是ViewRoot;
- 新版本为ViewRootImpl,不再是Handler,内部有个成员为ViewRootHandler - ViewRoot是View树的管理者,mView成员指向View树的根,它的核心人物是与WMS通信 - 每个Activity对应一个Window、WindowManager、DecorView、ViewRoot;
requestFeather(NoTitle)要放在setContentView之前因为setContentView就把DecorView生成好了。 - ViewRoot的工作机制:不管是内部还是外部的请求,ViewRoot把消息入队后再依次处理 - ViewRoot的遍历时机:第一次添加View、外部事件(触摸事件、按键事件)、内部事件(View.requestLayout、View.invalidate等主动请求遍历) - View.invalidate:“使无效”,引起重绘过程,只能在主线程调用,否则用postInvalidate - View遍历过程:measure、layout、draw - ViewParent:View的父亲,可能是ViewGroup或者ViewRoot
###onSizeChanged()### - 该方法在View Layout阶段会调用,默认系统是什么也没干,我们可以重写该方法判断输入法弹出、状态栏划下等事件
###ContextImpl### - getSystemService可能与远端Service发生通信,只是获得一个本地进程对象,比如WindowManagerImpl
###Binder### - 1) 用驱动程序来推进进程间的通信方式 2) 通过共享内存来提高性能 3) 为进程请求分配每个进程的线程池,每个应用进程默认启动两个binder服务线程 4) 针对系统中的对象引入了引用技术和跨进程的对象引用映射 5) 进程间同步调用 - Binder采用的是c/s架构,client通过代理完成对server的调用 - 强弱指针:保存对象的引用计数,可以设置模式通过哪种指针控制对象的生命周期 - 系统为每个进程维护一个存放交互线程的线程池。这些交互线程用于派送所有从另外进程发来的IPC调用。例如:当一个IPC从进程A发到进程B,A中那个发出调用的线程(这个应该不在线程池中)就阻塞在transact()中了。进程B中的交互线程池中的一个线程接收了这个调用,它调用Binder.onTransact(),完成后用一个Parcel来做为结果返回。然后进程A中的那个等待的线程在收到返回的Parcel后得以继续执行。实际上,另一个进程看起来就像是当前进程的一个线程,但不是当前进程创建的。 - ServiceManager.getService方法返回的是BpBinder在Java层的实现BinderProxy - 观察远程对象的存亡:linktoDeath() unlinkToDeath() - 系统Binder注册在ServiceManager上,或挂靠在Service上 - 匿名Binder Server:不直接注册在ServiceManager上,客户端通过另一个能找到的Server来找到该Server。典型的如WindowSession。 - getCallingPid

通过反射与系统Server进行通信:
方法1:对于注册在ServiceManager里的Server,直接获得IBinder
拷贝系统IWindowManager.aidl

  // 获得ServiceManager类
  Class<?> ServiceManager = Class
					.forName("android.os.ServiceManager");
  // 获得ServiceManager的getService方法
  Method getService = ServiceManager.getMethod("getService",
					java.lang.String.class);
  //  调用getService获取RemoteService
  Object oRemoteService = getService.invoke(null, "window");
  // 获得代理,就可以WindowManagerService通信了
  IWindowManager iwm = IWindowManager.Stub.asInterface((IBinder) oRemoteService);

方法2:对于没有注册在ServiceManager里的Server,通过绑定Service获得IBinder
拷贝系统IKeyguardService.aidl

    Intent intent = new Intent();
	intent.setClassName("com.android.keyguard",
			"com.android.keyguard.KeyguardService");

	if (!bindService(intent, mKeyguardConnection, Context.BIND_AUTO_CREATE)) {
		Log.v(TAG, "*** Keyguard: can't bind to ");
	} else {
		Log.v(TAG, "*** Keyguard started");
	}

private final ServiceConnection mKeyguardConnection = new ServiceConnection() {
		@Override
		public void onServiceConnected(ComponentName name, IBinder service) {
			Log.v(TAG, "*** Keyguard connected (yay!)");
			try {
				//转换为代理,就可以与KeyguardService通信了
                iks = (IKeyguardService) IKeyguardService.Stub
					.asInterface(service);
				Log.v(TAG, "iks:" + iks);
			} catch (Exception e) {
				e.printStackTrace();
			}
		}

		@Override
		public void onServiceDisconnected(ComponentName name) {
		}

	};

###AMS篇### - AMS是通过ActivityStack和其他数据结构来记录、管理、查询Activity等组件的系统服务 - ActivityStack: - LaunchMode:Standard、SingleTop、SingleTask、SingleInstance Intent中的Launch Flag优先于Manifest里配置的Launch Flag Standard:没有任何附加属性 SingleTop:栈顶不能出现两个相同的Activity,被启动的Activity在栈顶则调用onNewIntent SingleTask:永远位于taskAffinity与配置相同的Task中;如果该Task不存在,则新建一个Task并使该Activity位于栈底;如果Task存在,则将Activity压入到这个Task栈顶,不位于栈底;如果Activity已存在,则清掉位于栈中该Activity上方的所有Activity,调用Activity的onNewIntent方法 SingleIntance:永远独占一个Task SingleTask和SingleInstance均只有一个实例 - taskAffinity:每个Activity都有,默认是包名 - taskAffinity和SingleTask配合使用 - QQ在锁屏上弹消息的实现方式:在被启动的Activity的onCreate增加 getWindow().addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED | WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD | WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON | WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON); 再通过KeyguardManager来dismissKeyguard - startActivityForResult的结果无法跨越Task传递,当被启动的Activity是SingleTask的时候,会直接返回Result_Cancel - android:allowTaskReparenting:系统应用经常使用此标志,机制较复杂,慎用 - android:noHistory,android:excludeFromRecents="true":用于启动页,将不被显示在近期应用列表中 - Intent.FLAG_ACTIVITY_TASK_ON_HOME:新启动的Activity会放在LauncherTask中,这样它返回时就是Launcher - 判断进程在后台:process.importance != IMPORTANCE_FOREGROUND && process.importance != IMPORTANCE_VISIBLE;
###WMS篇### - WMS负责全局的窗口管理,全局的事件管理派发 - 如何与WMS通信? WindowManagerGlobal类
    public static IWindowManager getWindowManagerService() {
        synchronized (WindowManagerGlobal.class) {
        if (sWindowManagerService == null) {
            sWindowManagerService = IWindowManager.Stub.asInterface(
            ServiceManager.getService("window"));
        }
        return sWindowManagerService;
      }
    }
  • WMS里的WindowManagerPolicy mPolicy是PhoneWindowManager
  • WindowSession:每个客户的请求都发送到Wms会增加它的负担,故Wms提供出了一个匿名Session Server为客户端处理琐碎事务
  • Window:窗口的抽象概念,拥有WindowManager和AppToken,View要放在Window上
  • WindowManager:与Context有关,实现类是WindowManagerImpl,不直接与Wms通信
  • WindowManagerGlobal:与Context无关,维护全局,拥有mViews、mRoots、mParams三个数组
  • Add View过程:WindowManagerGlobal:new ViewRootImpl.setView-> ViewRootImpl:mWindowSession.addToDisplay->Session:mService.addWindow->WMS:addWindow
    之后的关键步骤:PhoneWindowManager:checkAddPermission 确定加系统Window所需的权限
    wms靠检测IWindow来避免重复添加
    WindowState:观察IWindow的死亡状态
  • 在客户端用Window来表示状态,在服务端用WindowState来表示
  • 非Activity添加View和Activity添加View的区别是Activity有DecorView,且Activity添加的窗口有appWindowToken
  • 全屏的两种方式:getWindow.addFlags和view.setSystemUI,后者能添加Listener从而判断StatusBar是否再次显示
  • getWindow().addFlags隐藏状态栏流程:PhoneWindow:addFlags>Activity:onWindowAttributesChanged>WindowManagerImpl:updateViewLayout >WindowManagerGlobal:updateViewLayout>View:setLayoutParams>ViewRootImpl:performTraversals>WMS:relayoutWindow>PhoneWindowManager:finishPostLayoutPolicyLw>BarController:setBarShowingLw>WindowState:hideLw
  • WindowManager.LayoutParams是ViewGroup.LayoutParams的子类
  • 窗口类型:ApplicationWindow 1-99 SubWindow 1000-1999 System Window:2000-2999
  • 窗口映射的上下顺序:不完全取决于窗口类型值的大小,参照PhoneWindowManager里的windowTypeToLayerLw,在这里数值相同的后添加的在上方
  • 一般应用添加的窗口类型是Type_Base_Application,值为1
  • 当ViewRootImpl在peformTravelsals时,如果发现是第一次执行该函数、或者窗口的可见性、大小等属性发生了变化,就会调用WMS的relayoutWindow
  • setSystemUiVisibility:Android4.0部分为Hide,可以直接用数字值设置
  • PopupWindow需要借助于瞄点对象的Window来确定位置,所以他的初始化放在view.post()里。

Activity、AMS、WMS关系###

http://blog.csdn.net/jinzhuojun/article/details/37737439


###Dialog### - PresentationState - RecentApplicationsDialog
###API### - StatusBarHeight:android.internal.R.dimen.status_bar_height - NavigationBarHeight:com.android.internal.R.dimen.navigation_bar_height_landscape - 透明状态栏并且使内容显示在状态栏之下: 代码里:getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS); Theme里: ``
###安全篇###
  • 防止反编译:1.Dex加密,如360 2.改变默认的Android目录结构,res变成R,如QQ
  • Activity劫持:后台扫描包名,启动伪装的和被劫持一个样子的Activity
posted @ 2015-01-28 21:07  XTANMY  阅读(549)  评论(0编辑  收藏  举报