Android知识点 整理

源码连接


生命周期理一理

1.生命周期

第一个Activity

* onCreate - onStart - onResume   -> onPause
* -> 一、(正常情况走下一个Activity) -> 2onC ->2onStart->2onResume ->1onStop   ---- (这样确保能有一个在前台)
* -> 二、(异常情况横竖切换)->onSaveInstanceState->onstop->ondestroy->onCrete ->onRestroreState->onStart->onResume


2tip
onStart、onResume ---- 是否可见这个角度
onPause、onStop ---- 是否位于前台这个角度


 资源内存不足导致优先级的Activity被杀死
前台Activity ---正在和用户交互的Activity
可见但非前台Activity ----比如Activity弹了一个dialog,导致Activity可见但是位于后台无法和用户交互
后台Activity ----已经被暂停的Activity,比如执行onStop

 防止Activity在旋转时被重新创建  需要 orientation(旋转) || screenSize(防止被重新创建)

 启动模式

1.standard
2.singleTop
3.singleTask   -- 单实例模式
4.singleInstance



任务栈 :  1、前台任务栈  2、后台任务栈


 IPC机制 binder理一理

 1.多进程
 

   <activity android:name=".SecondActivity"
            android:label="@string/app_name"
            android:process=":remote"
            />
        <activity android:name=".ThirdActivity"
            android:label="@string/app_name"
            android:process=":com.hugh.remote"
            />


u0_a522   14878 762   1763400 62220 SyS_epoll_ 0000000000 S com.hugh.basis
u0_a522   15247 762   1760024 57208 SyS_epoll_ 0000000000 S com.hugh.basis:remote
u0_a522   15273 762   1775416 51876 SyS_epoll_ 0000000000 S com.hugh.basis:com.hugh.remote
进程名以 ':'开头的进程属于当前应用的私有进程

 2.Parcelable  和  Serializable

区别 :         平台  、开销  、使用 、效率 、维护

Serializable   java    大     简单  低   难       ------>需要考虑serialID 去序列化和反序列化

Parcelable     android  小    麻烦  高   简单

 3.ICP跨进程的通信方式
1. Bundle(实现Parcelable序列化)  ---只能传输Bundle支持的数据类型,适合四大组件之间的通信
2. 文件读写(注意并发操作,不适合高并发操作)
3.AIDL        -------多AIDL 对 一Service需要用到binder池,主要原理多开一个接口 queryBinder去返回不同的Binder对象,处理不同的操作方法
4.Messanger(其实是对AIDL的封装)
5.ContentProvider(四大组件之一 ,主要提供数据源的CRUD操作)  ---也可以用于一对多的进程通信
6.socket(客户端与服务端监听同一端口) 适用网络数据交换


 4.View 滑动相关
 

 1.               button3.scrollBy(300,200);
 
 2.               ObjectAnimator.ofFloat(button3,"translationX",0,100).setDuration(500).start();
 
 3.               ViewGroup.MarginLayoutParams params = (ViewGroup.MarginLayoutParams) button3.getLayoutParams();
                params.width += 100;
                params.leftMargin += 100;
                button3.requestLayout();



4.1 MeasureSpec

 4.1.1首先理解MeasureSpec,是什么?
1. SpecMode ----测量模式
2. SpecSize ----测量大小

MeasureSpec 是一个32位的int型值,前2位代表测量模式,后30位代表测量大小,


 4.1.2区分MeasureSpec 与layoutParams的关系?
我们不禁要想 MeasureSpec 和layoutParams到底是什么关系呢?具体看源码其实我们可以看到两者的对应关系,根据case: layoutParams来决定
不同的MeasureSpec,
测量模式有一下3种
1 unspecified  这个用于系统内部测量的,父View不对子View进行限制
2 Exactly 这种测量模式意思子类有具体的值,对应我们的 layoutParams match_parent 和具体数值dp
3 at-most 指父元素给定一定的大小,子元素不能超过这个大小,这个对应我们的 layoutParams wrap-content

有了测量模式和测量大小,就能测量出子View具体的大小了
这边知道了大致关系,下面我们就可以看到是怎么通过 layoutParams 得到 MeasureSpec 

4.1.3 区分DecorView 和 普通view(只有DecorView外层直接是窗口)如何得到自身的MeasureSpec?
这里要做个区分 有一个比较特殊的View,他是没有父元素的
1. DecorView
DecorView是Android最外层的View,他本质是一个FrameLayout,他的MeasureSpec 是根据他自身 layoutParams和窗口的大小来决定的

2.其他View
其他View的 MeasureSpec 根据 '父容器的 MeasureSpec' 和 '自身的layoutParams' 来决定
看下面的代码


   public static int getChildMeasureSpec(int spec, int padding, int childDimension) {
        int specMode = MeasureSpec.getMode(spec);
        int specSize = MeasureSpec.getSize(spec);

        int size = Math.max(0, specSize - padding);

        int resultSize = 0;
        int resultMode = 0;

        switch (specMode) {
        // Parent has imposed an exact size on us
        case MeasureSpec.EXACTLY:
            if (childDimension >= 0) {
                resultSize = childDimension;
                resultMode = MeasureSpec.EXACTLY;
            } else if (childDimension == LayoutParams.MATCH_PARENT) {
                // Child wants to be our size. So be it.
                resultSize = size;
                resultMode = MeasureSpec.EXACTLY;
            } else if (childDimension == LayoutParams.WRAP_CONTENT) {
                // Child wants to determine its own size. It can't be
                // bigger than us.
                resultSize = size;
                resultMode = MeasureSpec.AT_MOST;
            }
            break;
            ……
            }


首先根据 父元素的MeasureSpec 判断,在根据自身的 LayoutParams判断,得出测量模式 和测量大小

 
 4.2View measure layout draw

 measure过程 ,区分最小颗粒View和ViewGroup的测量过程
在整个测量过程当中,会用到我们上面理解的MeasureSpec
measure过程确定View的测量宽、高
measure过程也要分情况看,
1. 如果只有一个原始的View,那么通过 measure方法就完成其测量过程
View 会先调用 onMeasure()方法
 

  setMeasuredDimension(getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec),
                getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec));



接下来看下getDefaultSize(),它会将我们上次搞得 measureSpec的值拿过来
拿到测量模式和测量大小 mode 和 size
 


    public static int getDefaultSize(int size, int measureSpec) {
        int result = size;
        int specMode = MeasureSpec.getMode(measureSpec);
        int specSize = MeasureSpec.getSize(measureSpec);

        switch (specMode) {
        case MeasureSpec.UNSPECIFIED:
            result = size;
            break;
        case MeasureSpec.AT_MOST:
        case MeasureSpec.EXACTLY:
            result = specSize;
            break;
        }
        return result;
    }



getSuggestedMinimumWidth() 是怎么传size的,size分别是宽、高,这里面就用到了我们在布局文件的 mMinwdith和背景图片(drawable)的大小

 

  protected int getSuggestedMinimumWidth() {
        return (mBackground == null) ? mMinWidth : max(mMinWidth, mBackground.getMinimumWidth());
    }



 tip
我们可以看到View的宽高就是由specSize决定,我们在自定义View的时候需要重写onMeasure方法并设置wrap_content时的自身大小,否在在布局中适用
wrap_content就相当于适用 march_parent,这个根据之前的测量模式关系对应能得出结论,具体根据业务需要来控制大小,比如给一个内部的宽高比,通过
调用setMeasureDimension()来完成

2. 如果是一个ViewGroup,除了完成自己的测量过程外,还会遍历去调用所有子元素的measure方法

它提供了一个 measureChildren 方法
 

   protected void measureChildren(int widthMeasureSpec, int heightMeasureSpec) {
        final int size = mChildrenCount;
        final View[] children = mChildren;
        for (int i = 0; i < size; ++i) {
            final View child = children[i];
            if ((child.mViewFlags & VISIBILITY_MASK) != GONE) {
                measureChild(child, widthMeasureSpec, heightMeasureSpec);
            }
        }
    }



measureChild 做的事情主要是取出子元素的 layoutParams,然后在通过getChildMeasureSpec 来创建子元素的 MeasureSpec,接着将MeasureSpec
直接传递给View的 measure方法

//简单来说就是获取子元素的measureSpec 然后让子元素去测量自己,子元素自己去进入measure过程 
 

 protected void measureChild(View child, int parentWidthMeasureSpec,
            int parentHeightMeasureSpec) {
        final LayoutParams lp = child.getLayoutParams();

        final int childWidthMeasureSpec = getChildMeasureSpec(parentWidthMeasureSpec,
                mPaddingLeft + mPaddingRight, lp.width);
        final int childHeightMeasureSpec = getChildMeasureSpec(parentHeightMeasureSpec,
                mPaddingTop + mPaddingBottom, lp.height);

        child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
    }



父元素的onMeasure过程都都有所差异 所以不像View能有一个统一的方法,因为每种的布局方式不同,比如linearLayout 和RelativeLayout
这里简要概括下linearLayout的测量情况

1. 子元素 measureSpec 去测量 子元素的大小
2. 子元素的宽高得到,父元素再去测量自己




 4.3tips
 一. 因为View的measure过程和Activity的生命周期方法不是同步执行的,因此无法保证Activity执行了onCreate、onStart、onResume 时某个View已经测量
 完毕了,如果View还没有测量完毕,那么获得的宽高就是0,下面有4中方法来解决这个问题。
 
 * 1 在Activity的 onWindowFocusChanged 里去获取
 
 

   @Override
     public void onWindowFocusChanged(boolean hasFocus) {
         super.onWindowFocusChanged(hasFocus);
         if (hasFocus) {
             int width = button.getMeasuredWidth();
             int height = button.getMeasuredHeight();
             Log.e("a", width + "");
             Log.e("a", height + "");
         }
     }



 * 2 view.post(runnable)
 

button.post(new Runnable() {
            @Override
            public void run() {
                int width = button.getMeasuredWidth();
                int height = button.getMeasuredHeight();
                Log.e("b", width + "");
                Log.e("b", height + "");
            }
        });


 
 * 3 ViewTreeObserver
 


    ViewTreeObserver observer = button.getViewTreeObserver();
        observer.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
            @Override
            public void onGlobalLayout() {
                button.getViewTreeObserver().removeOnGlobalLayoutListener(this);
                int width = button.getMeasuredWidth();
                int height = button.getMeasuredHeight();
                Log.e("c", width + "");
                Log.e("c", height + "");
            }
        });



* 4. 如果子View是 wrap-content 或者 具体数值的话

具体的数值
 

       int widthMeasureSpec = View.MeasureSpec.makeMeasureSpec(dip2px(this,100), View.MeasureSpec.EXACTLY);
        int heightMeasureSpec = View.MeasureSpec.makeMeasureSpec(dip2px(this,100), View.MeasureSpec.EXACTLY);
        button.measure(widthMeasureSpec, heightMeasureSpec);


 
 wrap-content
 

  //如果是wrapContent的话
      //   makeMeasureSpec()  传入测量大小 ,测量模式
         int widthMeasureSpec = View.MeasureSpec.makeMeasureSpec((1 << 30) -1, View.MeasureSpec.AT_MOST);
         int heightMeasureSpec = View.MeasureSpec.makeMeasureSpec((1 << 30) -1, View.MeasureSpec.AT_MOST);
         button.measure(widthMeasureSpec, heightMeasureSpec);



layout过程

* layout的作用是ViewGroup用来确定子元素的位置 

ViewGroup提供的抽象方法 强制子类复写

```
  @Override
    protected abstract void onLayout(boolean changed,
            int l, int t, int r, int b);

```

这边一垂直的LinerLayout为例

1. 父元素先完成自己的定位后
2. 再遍历子元素的layout,子元素通过自己的layout方法完成自己的定位
3. 从上往下一层层传递下去,从上先摆好位置,先摆外面 在摆内部。




 draw过程

* 1.绘制背景 background.draw(canvas)
* 2.绘制自己(onDraw)
* 3.绘制children(dispatchDraw)
* 4.绘制装饰(onDrawScrollBars)

View 绘制的过程是通过dispatchDraw来实现的,dispatchDraw会遍历调用所有元素的draw方法,draw的事件就一层层传递了下去。

 tips
如果当前View不想绘制任何内容,可以使用 `setWillNotDraw` 来优化
 自定义View 自定义ViewGroup 参考CircleView 和 HorizontalScrollView


 7Android动画相关

Android动画分为3种
1.View动画
2.帧动画
3.属性动画

 7.1 View动画

* 平移动画   translate
* 缩放动画   scale
* 旋转动画   rotate
* 透明度动画  alpha

这点动画的过程其实就是矩阵变换的过程 
 


        Animation animation = AnimationUtils.loadAnimation(this, R.anim.animation_set);
        mButton.startAnimation(animation);

        AlphaAnimation alphaAnimation = new AlphaAnimation(0,1);
        alphaAnimation.setDuration(2000);
        alphaAnimation.setAnimationListener(new Animation.AnimationListener() {
            @Override
            public void onAnimationStart(Animation animation) {
                //这边可以对整个动画过程做监听
            }

            @Override
            public void onAnimationEnd(Animation animation) {

            }

            @Override
            public void onAnimationRepeat(Animation animation) {

            }
        });
        mButton.startAnimation(alphaAnimation);




7.2 帧动画
帧动画是顺序播放一组预先定义好的图片,类似与电影播放。
 


// frame_animation
<?xml version="1.0" encoding="utf-8"?>
<animation-list xmlns:android="http://schemas.android.com/apk/res/android"
    android:oneshot="false">

    <item
        android:drawable="@drawable/image1"
        android:duration="500" />
    <item
        android:drawable="@drawable/image2"
        android:duration="500" />

    <item
        android:drawable="@drawable/image3"
        android:duration="500" />

</animation-list>




  mButton.setBackgroundResource(R.drawable.frame_animation);
        AnimationDrawable drawable = (AnimationDrawable) mButton.getBackground();
        drawable.start();






 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值