Android知识点笔记

  1. dispatchMessage() 分发消息三种情况
    1. Message对象的callback不为空(runnable),交给callback处理
    2. handler的callback不为空,交给callback处理(如果你消息自己有callback的话,就会优先执行你的消息的callback)
    3. 前两种都没有的情况下交给handleMessag去处理
  2. Message的Obtain()/recycleUnchecked()

  3. DialogFragment至少重写下面一个方法
    1. onCreateView:自己通过XML定义布局
    2. onCreateDialog:使用系统内置对话框比如AlertDialog
  4. swapCursor vs changeCursor
  5. LayoutAnimation vs LayoutTransition
  6. CursorTreeAdapter的使用简介
  7. 带你看懂LayoutInflater中inflate方法
  8. 自定义View构造函数参数
    1. 一个参数:一般在直接New一个View的时候调用
    2. 两个参数:一般在layout文件中使用的时候会调用,关于它的所有属性(AttributeSet)(包括自定义属性,直接引用的Style资源)都会包含在attrs中传递进来
    3. 三个参数:默认的Style是指它在当前Application或Activity所用的Theme中的默认Style,且只有在明确调用的时候才会生效(AttributeSet未找到则从这里找)
    4. 四个参数:API21的时候才添加上,当第三个参数不生效时才有作用
    5. 优先级从高到低依次是:直接在layout中设置View的XML属性值(AttributeSet)> 设置View的style属性 > defStyleAttr > defStyleRes
  9. Android安全机制分为三层
    1. 最基础的一层,数据分为system和data两个区。其中system是只读的,data用来存放应用自己的数据,这保证了系统数据不会被随意改写
    2. 第二层用来使应用之间的数据相互独立。每个应用都会有一个user id和group id,只有相同的user id才能问它们的数据。通过对apk签名来标识自己。签名和uid构成了双重的保证
    3. 第三个层次就是权限体系
  10. 调用的系统API接口,有3种目录可以给我们写入文件
    1. 应用私有存储(内置存储)不需要申请
      • Context.getFileDir():/data/data/应用包名/files/ 对应着App下清除数据
      • Context.getCacheDir():/data/data/应用包名/cache/ 对应着清除缓存
    2. 应用扩展存储(SD卡)API < 19:需要&API >= 19:不需要
      • Context.getExternalFilesDir():SDCard/Android/data/应用包名/files/
      • Context.getExternalCacheDir():SDCard/Android/data/应用包名/cache/
    3. 公共存储(SD卡)需要申请
      • Environment.getExternalStorageDirectory():SDCard/文件夹名字/
  11. Bitmap 在内存当中占用的大小其实取决于
    1. 色彩格式,eg:如果是 ARGB8888 是像素4个字节,如果是 RGB565 是2个字节
    2. 原始文件存放的资源目录(是 hdpi 还是 xxhdpi 可不能傻傻分不清楚哈)
    3. 目标屏幕的密度(所以同等条件下,红米在资源方面消耗的内存肯定是要小于三星S6的)
  12. 解决屏幕旋转(状态发生变化)状态不能保持的问题
    1. 不好的实践:保存整个Activity使用设置android:configChanges属性,不止是屏幕旋转。比如修改设备默认语言,修改设备默认字体比例等都可会引起配置改变
    2. 已经被弃用的方法(API 13):重写onRetainNonConfigurationInstance()、getLastNonConfigurationInstance()方法
    3. 使用onSaveInstanceState() 、onRestoreInstanceState()进行数据保存与恢复
    4. 推荐的方法:在Retained Fragment中管理对象
      1. 扩展Fragment类,并声明对有状态对象的引用(onAttach引用Activity)
      2. 创建Fragment时调用setRetainInstance(boolean)
      3. 将片段添加到Activity
      4. 当Activity重新启动时,使用FragmentManager检索片段
  13. FragmentTransaction中对Fragment的操作
    • add() & remove()add()会执行onAttach()~onResume()周期,remove() 执行onPause()~onDetach()周期
    • show() & hide():生命周期方法不会执行,仅仅是View显示或者​隐藏,并视情况调用onHiddenChanged()
    • attach() & detach ()onPause()、onDestroyView()会被执行,Fragment的View也会被detach,但不会执行onDestroy()、onDetach()
    • replace():其实就是remove()+add()
  14. TouchEvent事件,低8位表示touch事件的具体动作,比如按下,抬起,滑动,还有多点触控时的按下,抬起,这个和单点是区分开的
    1. getAction:触摸动作的原始32位信息,包括事件的动作,触控点信息
    2. getActionMask:触摸的动作,按下,抬起,滑动,多点按下,多点抬起
    3. getActionIndex:触控点信息
  15. TypedArray中的函数是获取自定义属性的,Resources中的函数是获取android预置属性的
    1. getDimension()是基于当前DisplayMetrics进行转换,获取指定资源id对应的尺寸。函数的返回值是float,像素肯定是int
    2. getDimensionPixelSize()与getDimension()功能类似,不同的是将结果转换为int,并且小数部分四舍五入
    3. getDimensionPixelOffset()功能类似,不同的是将结果转换为int,并且偏移转换(offset)是直接截断小数位,即取整(其实就是把float强制转化为int)
  16. 系统属性SystemProperty
    1. 通过命令adb shell getprop查看手机上所有属性状态值
    2. 属性名称以“ro.”开头,那么这个属性被视为只读属性。一旦设置,属性值不能改变
    3. 属性名称以“persist.”开头,当设置这个属性时,其值也将写入/data/property
    4. 属性名称以“net.”开头,当设置这个属性时,“net.change”属性将会自动设置,以加入到最后修改的属性名
  17. save&saveLayer
    1. save方法可以保存当前的matrix and clip,并且在restore把它恢复,一些平移,旋转,缩放等操作都会影响Canvas的matrix,所以save操作一般可以保存这些信息以及clip信息
    2. saveLayer则强大很多,它相当于另外起一张干净图层,并在上面进行绘制操作,然后在restoreToCount的时候,把刚才所绘制的重新绘制在原本的Canvas上。当时正如所知的那样,它会绘制两次,所以消耗是十分巨大
  18. 代码中获取attr属性的值
    1. 在xml里,我们可以简单的引用attr属性值,例如:
      android:background="?attr/colorPrimary"
      android:minHeight="?attr/actionBarSize"
    2. 代码中获取attr属性值:
    TypedValue typedValue = new TypedValue();
    context.getTheme().resolveAttribute(R.attr.yourAttr, typedValue, true);
     // For string
    typedValue.string
    typedValue.coerceToString()
    // For other data
    typedValue.resourceId
    typedValue.data;
    
  19. Activity启动过程
    Android知识点笔记_第1张图片
    Activity启动过程
  20. SparseArray
    • SparseArray 在某些条件下性能更好,主要是因为它避免了对key的自动装箱,内部是通过两个数组来进行数据存储的,一个存储key,另外一个存储value,但是由于其添加、查找、删除数据都需要先进行一次二分查找,所以在数据量大的情况下性能并不明显,将降低至少50%。
    • 数据量不大,最好在千级以内
    • key必须为int类型,这中情况下的HashMap可以用SparseArray代替:
  21. ArrayMap
    • ArrayMap是一个<key,value>映射的,它设计上更多的是考虑内存的优化,内部是使用两个数组进行数据存储,一个数组记录key的hash值,另外一个数组记录Value值,它和SparseArray一样,也会对key使用二分法进行从小到大排序,在添加、删除、查找数据的时候都是先使用二分查找法得到相应的index,然后通过index来进行添加、查找、删除等操作,所以,应用场景和SparseArray的一样,如果在数据量比较大的情况下,那么它的性能将退化至少50%。
    • 如果key的类型已经确定为int类型,那么使用SparseArray,因为它避免了自动装箱的过程,如果key为long类型,它还提供了一个LongSparseArray来确保key为long类型时的使用
    • 如果key类型为其它的类型(String),则使用ArrayMap
    • 两个数据结构都适合数据量不是特别大的情况
  22. 编译时候加上(据说编译比较快)
     android{
    ...
     tasks.whenTaskAdded { task ->
          if (task.name.contains("lint")
    //如果instant run不生效,把clean这行干掉
                 ||task.name.equals("clean")
              //如果项目中有用到aidl则不可以舍弃这个任务
                 ||task.name.contains("Aidl")
    //用不到测试的时候就可以先关闭
                 ||task.name.contains("mockableAndroidJar")
                 ||task.name.contains("UnitTest")
                 ||task.name.contains("AndroidTest")
    //用不到NDK和JNI的也关闭掉
                 || task.name.contains("Ndk")
                 || task.name.contains("Jni")
         ) {
                      task.enabled = false
         }
       }
    }
    
  23. ExecutorService的关闭方法
    • shutdown():将线程池状态置为SHUTDOWN,并不会立即停止
    • shutdownNow():将线程池状态置为STOP,企图立即停止,事实不一定
    • awaitTermination(): 当前线程阻塞,直到等所有已提交的任务(包括正在跑的和队列中等待的)执行完
  24. Service
    • 启动服务的需要通过 stopSelf() 自行停止,或其他组件调用 stopService()
    • onRebind()方法调用时机:
      • onUnbind()方法返回值为true
      • 启动服务同时和绑定服务,当Activity退出的时候,Service的onUnbind()方法就会被调用
  25. 内容提供着权限有:
    1. 统一读写提供程序级别权限
    2. 单独的读取和写入提供程序级别权限
    3. 路径级别权限
    4. 临时权限
  26. Android 6.0 Marshmallow的运行时权限
    1. 检查系统版本号:对于6.0开始的版本,才需要做运行时的权限检查
    2. 检查申请的权限:checkSelfPermission(Manifest.permission.xxx)
    3. 解释申请的权限:shouldShowRequestPermissionRationale()
    4. 执行申请权限操作:requestPermissions()
    5. 处理权限申请的结果:onRequestPermissionsResult()
  27. Android安全机制
    1. 进程沙箱隔离机制
    2. 应用程序签名机制
    3. 权限声明机制
    4. 访问控制机制
    5. 进程通信机制
  28. android中延迟执行某个任务

    • 倒计时类
      • 用CountDownTimer
    • 延迟类
      • CountDownTimer,可巧妙的将countDownInterval设成和millisInFuture一样,这样就只会调用一次onTick和一次onFinish
      • handler.sendMessageDelayed,可参考CountDownTimer的内部实现,简化一下,个人比较推荐这个
        TimerTask,代码写起来比较乱
        Thread.sleep,感觉这种不太好
    • 定时类
      • 参照延迟类的,自己计算好要延迟多少时间
        handler.sendMessageAtTime
        AlarmManager,适用于定时比较长远的时间,例如闹铃
  29. setBackgroundXXX的用法

    • setBackgroundDrawable 的参数为Drawable对象
    • setBackgroundColor 的参数为Color对象,比如说Color.Red为红色,或Color.rgb(255,0,0)
    • setBackgroundResource 的参数为资源ID,比如说R.drawable.icon
  30. getDimension,getDimensionPixelOffset和getDimensionPixelSize

    • getDimension和getDimensionPixelOffset的功能类似,都是获取某个dimen的值,但是如果单位是dp或sp,则需要将其乘以density
      如果是px,则不乘。并且getDimension返回float,getDimensionPixelOffset返回"下限"的int值.
    • getDimensionPixelSize则不管写的是dp还是sp还是px,都会乘以denstiy,返回"四舍五入"的int值.
  31. 切换Fragment时实现数据保持

    • replace方法会Fragment导致频繁的释放和创建,Fragment比较臃肿或者需要从网络加载数据这样就非常不好
    • instantiateItem从FragmentManager中查找Fragment,找不到就getItem新建一个,setPrimaryItem设置隐藏和显示,最后finishUpdate提交事务
      Fragment fragment = (Fragment) mFragmentPagerAdapter.instantiateItem(mContainer, buttonView.getId());
      mFragmentPagerAdapter.setPrimaryItem(mContainer, 0, fragment);
      mFragmentPagerAdapter.finishUpdate(mContainer);
      
    • 解决切换tab的时候重影现象
      public void setMenuVisibility(boolean menuVisible) {
        super.setMenuVisibility(menuVisible);
        if (this.getView() != null)
          this.getView().setVisibility(menuVisible ? View.VISIBLE : View.GONE);
      }
      
  32. Environment 常用方法

    • getDataDirectory(),获取 Android 数据目录
    • getDownloadCacheDirectory(),获取 Android 下载/缓存内容目录
    • getExternalStorageDirectory(),获取外部存储目录即 SDCard
    • getExternalStorageState(),获取外部存储设备的当前状态
    • getRootDirectory(),获取 Android 的根目录
  33. Scrollview怎么判断是否滑倒顶部底部

    • 滚动到顶部判断:getScrollY() == 0
    • 滚动到底部判断:
      View contentView = getChildAt(0);
      contentView.getMeasuredHeight() <= getScrollY() + getHeight();
      

      其中getChildAt表示得到ScrollView的child View,因为ScrollView只允许一个child view,所以contentView.getMeasuredHeight()表示得到子View的高度, getScrollY()表示得到y轴的滚动距离,getHeight()为scrollView的高度。当getScrollY()达到最大时加上scrollView的高度就的就等于它内容的高度了

  34. Android Fragment嵌套使用存在的一些BUG

    • 当使用Fragment去嵌套另外一些子Fragment的时候,我们需要去管理子Fragment,这时候需要调用ChildFragmentManager去管理这些子Fragment,由此可能产生的Exception主要是:
      java.lang.IllegalStateException: No activity
    • 当我们从一个Activity启动了一个Fragment,然后在这个Fragment中又去实例化了一些子Fragment,在子Fragment中去有返回的启动了另外一个Activity,即通过startActivityForResult方式去启动,这时候造成的现象会是,子Fragment接收不到OnActivityResult,如果在子Fragment中是以getActivity.startActivityForResult方式启动,那么只有Activity会接收到OnActivityResult,如果是以getParentFragment.startActivityForResult方式启动,那么只有父Fragment能接收(此时Activity也能接收),但无论如何子Fragment接收不到OnActivityResult,我们可以通过在子Fragment中以getParentFragment.startActivityForResult的方式来启动,然后在父Fragment中去接收数据,我们需要在子Fragment中提供一个方法,如:getResultData(Object obj),通过父Fragment中的子Fragment实例去调用这个方法,把相应的数据传过去,然后去更新子Fragment
  35. 布局文件后缀

    • swdp,如layout-sw600dp, values-sw600dp,这里的sw代表smallwidth的意思,当你所有屏幕的最小宽度都大于600dp时,屏幕就会自动到带sw600dp后缀的资源文件里去寻找相关资源文件,这里的最小宽度是指屏幕宽高的较小值,每个屏幕都是固定的,不会随着屏幕横向纵向改变而改变
    • wdp 如layout-w600dp, values-w600dp,带这样后缀的资源文件的资源文件制定了屏幕宽度的大于Ndp的情况下使用该资源文件,但它和swdp不同的是,当屏幕横向纵向切换时,屏幕的宽度是变化的,以变化后的宽度来与N相比,看是否使用此资源文件下的资源
    • hdp 如layout-h600dp, values-h600dp,这个后缀的使用方式和wdp一样,随着屏幕横纵向的变化,屏幕高度也会变化,根据变化后的高度值来判断是否使用hdp ,但这种方式很少使用,因为屏幕在纵向上通常能够滚动导致长度变化,不像宽度那样基本固定
  36. Android 手机上获取物理唯一标识码

    • DEVICE_ID:可以同通过TelephonyManager.getDeviceId()获取,它根据不同的手机设备返回IMEI,MEID或者ESN码,但它在使用的过程中会遇到很多问题: 非手机设备、权限、BUG
    • MAC ADDRESS:我们也可以通过手机的Wifi或者蓝牙设备获取MAC ADDRESS作为DEVICE ID,但是并不建议这么做,因为并不是所有的设备都有Wifi,并且,如果Wifi没有打开,那硬件设备无法返回MAC ADDRESS
    • Serial Number:
      在Android 2.3可以通过android.os.Build.SERIAL获取,非手机设备可以通过该接口获取
    • ANDROID_ID:是设备第一次启动时产生和存储的64bit的一个数,当设备被wipe后该数重置
      ANDROID_ID似乎是获取Device ID的一个好选择,但它也有缺陷
    • Installtion ID : UUID通过在程序安装后第一次运行后生成一个ID实现的,但该方式跟设备唯一标识不一样,它会因为不同的应用程序而产生不同的ID,而不是设备唯一ID。因此经常用来标识在某个应用中的唯一ID(即Installtion ID),或者跟踪应用的安装数量
  37. ViewPager取消预加载

    setOffscreenPageLimit()这一个方法是设置预加载的个数,默认为1,但是当你设置为0的时候也会强行将它设置为1

    public void setOffscreenPageLimit(int limit) {
      if (limit < DEFAULT_OFFSCREEN_PAGES) {
          Log.w(TAG, "Requested offscreen page limit " + limit + " too small; defaulting to " +
                  DEFAULT_OFFSCREEN_PAGES);
          limit = DEFAULT_OFFSCREEN_PAGES;
      }
      if (limit != mOffscreenPageLimit) {
          mOffscreenPageLimit = limit;
          populate();
      }
    }
    
  38. attr和styleable的关系

    • attr不依赖于styleable,styleable只是为了方便attr的使用
    • 而通过定义一个styleable,我们可以在R文件里自动生成一个int[],数组里面的int就是定义在styleable里面的attr的id
    • 定义一个declare-styleable,在获取属性的时候为我们自动提供了一个属性数组。此外,我觉得使用declare-styleable的方式有利于我们我们把相关的属性组织起来,有一个分组的概念,属性的使用范围更加明确
  39. 多属性动画

    • 构造多个对象Animator,( Animator可以ValueAnimator、ObjectAnimator和AnimatorSet)然后把它们放在一个AnimatorSet中。
      ObjectAnimator animX = ObjectAnimator.ofFloat(myView, "x", 50f);
      ObjectAnimator animY = ObjectAnimator.ofFloat(myView, "y", 100f);
      AnimatorSet animSetXY = new AnimatorSet();
      animSetXY.playTogether(animX, animY);
      animSetXY.start();
      
    • 用一个ObjectAnimator对象加多个PropertyValuesHolder:
      PropertyValuesHolder pvhX = PropertyValuesHolder.ofFloat("x", 50f);
      PropertyValuesHolder pvhY = PropertyValuesHolder.ofFloat("y", 100f);
      ObjectAnimator.ofPropertyValuesHolder(myView, pvhX, pvyY).start();
      
    • 使用ViewPropertyAnimator
       myView.animate().x(50f).y(100f);
      
    • 用一个ObjectAnimator实例,实现View既可以缩小、又能够淡出(3个属性scaleX,scaleY,alpha)
      public void rotateyAnimRun(final View view)  
      {  
      ObjectAnimator anim = ObjectAnimator//  
          .ofFloat(view, "zhy", 1.0F,  0.0F)//  
          .setDuration(500);//  
      anim.start();  
      anim.addUpdateListener(new AnimatorUpdateListener()  
      {  
      @Override  
      public void onAnimationUpdate(ValueAnimator animation)  
      {  // 获取当前值
          float cVal = (Float) animation.getAnimatedValue();  
          view.setAlpha(cVal);  
          view.setScaleX(cVal);  
          view.setScaleY(cVal);  
        }  
       });  
      }  
      

你可能感兴趣的:(Android知识点笔记)