实习笔记-16

Android View绘制流程

performTraversals()

获取Surface对象,performMeasure-丈量View树的各个view的大小,performLayout-对整个视图树进行布局,performDraw,对视图树进行绘制
源码解析

  1. 第一阶段,确定activity的宽高
    1
    2
    3
    4
    5
    6
    7
    8
    9
    if(Activity窗口是第一次被请求执行测量、布局和绘制操作){
    if(如果窗口的类型是有状态栏的){
    Activity窗口所需要的宽度和高度就是除了状态栏;
    }else{
    Activity窗口所需要的宽度和高度就是整个屏幕的宽高;
    }
    }else{
    Activity窗口的宽高为frame成员变量中的保存的上一次测量、布局和绘制时的值;
    }

排序

中文按照拼音排序

阅读更多

实习笔记-13

为什么用SurfaceView不用自定义组件

  • 小组件在布局上的局限性
    • 只支持原生控件,且不支持他们的后代
    • 难以动态更新动画
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      FrameLayout
      LinearLayout
      RelativeLayout
      GridLayout

      AnalogClock
      Button
      Chronometer
      ImageButton
      ImageView
      ProgressBar
      TextView
      ViewFlipper
      ListView
      GridView
      StackView
      AdapterViewFlipper
  • 只能显示在某一屏

优化空间

  • 壁纸的操作和部分launcher的操作冲突
  • 只能在右侧,对左撇子不友好
  • 两个wallpaper的drawFrame方法相似,可以进一步抽象

实习笔记-14

更新桌面小组件

  1. Handler更新:只能坚持几秒钟
  2. Service发送广播更新
    1. Service的context从onReceive获取,一切正常。会存在保活的问题,至少30分钟系统才调用onUpdate一次
    2. 使用lateinit保存onUpdate的context,会报错lateinit property mContext has not been initialized
  3. onUpdate暴力递归 点击后无法更新

实习笔记-25

创建型

单例

优点

  • 节省资源
    • 内存
    • 重对象中包含的io,文件指针
  • 调用方便

缺点

  • 适用于昂贵对象,对于轻量对象,为了维护单例造成的同步等开销比创建一个对象更高。得不偿失
  • 不方便mock,(可以把单例对象作为函数参数则可以mock),相较于静态方法更方便(静态方法需要代理的方式mock)
  • 测试时常常并行测试,使用单例会降低效率
    函数式编程,拷贝
    云控,打点 Alex
    静态工具方法,少用,不要有状态,确保永远不会变
阅读更多

实习笔记-24

设备到设备文件传输

如果您的应用以 Android 11 或更高版本为目标平台,您将无法使用 allowBackup 属性停用应用文件的设备到设备迁移。系统会自动启用此功能。

不过,即使您的应用以 Android 11 或更高版本为目标平台,您也可以通过将 allowBackup 属性设为 false 来停用应用文件的云端备份和恢复。

非 SDK 接口限制

相机

媒体 intent 操作需要系统默认相机
从 Android 11 开始,只有预装的系统相机应用可以响应以下 intent 操作:

阅读更多

Kotlin学习笔记——BroadCast

1
#define 小毛驴 xml

收发广播

使用场景:Fragment想要向外传递信息

  1. 在Fragment中发送广播
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    class BlankFragment : Fragment() {
    var ctx:Context? = null
    var mPosition:Int = 0
    var mInageId:Int = 0
    var mDesc:String = ""
    var title:String = ""

    val colorNames = listOf<String>("红色","黄色","绿色","青色","蓝色")
    val colors = intArrayOf(Color.RED, Color.YELLOW, Color.GREEN, Color.CYAN, Color.BLUE)
    var mSeq:Int = 0
    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
    ctx = activity
    if (arguments != null) {
    mPosition = arguments!!.getInt("position", 0)
    mInageId = arguments!!.getInt("image_id", 0)
    mDesc = arguments!!.getString("desc")
    title = arguments!!.getString("title")
    }
    val view = inflater.inflate(R.layout.show_info, container, false)

    view.findViewById<ImageView>(R.id.imageView).setImageResource(mInageId)
    view.findViewById<TextView>(R.id.textView).text = mDesc
    view.findViewById<Button>(R.id.se).setOnClickListener {
    ctx!!.selector("选择颜色", colorNames) {
    mSeq = it

    val intent = Intent(BlankFragment.EVENT)
    intent.putExtra("seq", it)
    intent.putExtra("color", colors[it])
    ctx!!.sendBroadcast(intent)//发送广播
    }
    }
    return view
    }

    companion object {
    const val EVENT:String = "changeColor"//const,编译期常量
    fun newInstance(position:Int, image_id:Int, desc:String, title:String) : BlankFragment {

    val fragment = BlankFragment()
    val bundle = Bundle()
    bundle.putInt("position", position)
    bundle.putInt("image_id", image_id)
    bundle.putString("desc", desc)
    bundle.putString("title", title)
    fragment.arguments = bundle
    return fragment
    }
    }
    }
  2. 在要接收广播的页面注册receiver
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    class MainActivity : FragmentActivity(){
    private var BGChangeRecever:myBgChangeRecever? = null
    override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)
    var vp:ViewPager = findViewById(R.id.vp)
    var title: PagerTabStrip = findViewById(R.id.title)

    val pics = arrayOf(R.mipmap.basic, R.mipmap.close, R.mipmap.debug, R.mipmap.edit)
    val list:MutableList<itemInfo> = mutableListOf()
    for (i in pics.indices) {
    list.add(itemInfo((i+1).toString(), pics[i], ((i+1)*(i+1)).toString()))
    }
    vp.adapter = infoPagerAdapter(supportFragmentManager, list)
    vp.currentItem = 0
    }

    public override fun onStart() {
    super.onStart()
    BGChangeRecever = myBgChangeRecever()

    val filiter = IntentFilter(BlankFragment.EVENT)//广播过滤器,过滤掉参数以外的广播
    registerReceiver(BGChangeRecever,filiter)//开始时注册接收器

    }

    public override fun onStop() {
    unregisterReceiver(BGChangeRecever)//结束前注销接收器
    super.onStop()
    }

    private inner class myBgChangeRecever : BroadcastReceiver() {//广播接收器
    override fun onReceive(context: Context?, intent: Intent?) {//接收广播后执行的操作
    if (intent != null) {
    val color = intent.getIntExtra("color", Color.GREEN)
    textView2.setTextColor(color)
    }
    }

    }
    }

接收系统广播

静态注册

阅读更多

Kotlin学习笔记——Button

实现短按长按的方法

调用函数

方法 参数 参数解释 返回值 备注
setOnClickListener lambda表达式 lambda的参数为发生点击动作的View,返回值Unit Unit 相当于override fun onClickListener(v:View)
setOnLongClickListener lambda表达式 lambda的参数为发生点击动作的View,返回值Boolean(true表示这个事件已经消耗完了,false表示事件继续传递,会触发一次短按事件) Unit 相当于override fun onLongClick(v:View):Boolean

例子

1
2
3
4
5
6
7
btn.setOnClickListener {
toast("click")
}
btn.setOnLongClickListener {
toast("Long Click")
true
}

使用内部类

阅读更多

Kotlin学习笔记——Fragment

1
#define 小毛驴 xml

使用方法

Fragment与ViewPager搭配,实现翻页,实现每页多个控件

  1. 写好每个item的小毛驴文件和数据传送类
  2. 继承Fragment类,自定义一个fragment
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    class BlankFragment : Fragment() {
    var ctx:Context? = null
    var mPosition:Int = 0
    var mInageId:Int = 0
    var mDesc:String = ""
    var title:String = ""

    val colorNames = listOf<String>("红色","黄色","绿色","青色","蓝色")
    val colors = intArrayOf(Color.RED, Color.YELLOW, Color.GREEN, Color.CYAN, Color.BLUE)
    var mSeq:Int = 0
    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
    ctx = activity
    if (arguments != null) {
    mPosition = arguments!!.getInt("position", 0)
    mInageId = arguments!!.getInt("image_id", 0)
    mDesc = arguments!!.getString("desc")
    title = arguments!!.getString("title")
    }//获取数据
    val view = inflater.inflate(R.layout.show_info, container, false)

    view.findViewById<ImageView>(R.id.imageView).setImageResource(mInageId)
    view.findViewById<TextView>(R.id.textView).text = mDesc
    //显示数据
    return view
    }

    companion object {
    fun newInstance(position:Int, image_id:Int, desc:String, title:String) : BlankFragment {//调用这个函数,创建新的fragment

    val fragment = BlankFragment()
    val bundle = Bundle()
    bundle.putInt("position", position)
    bundle.putInt("image_id", image_id)
    bundle.putString("desc", desc)
    bundle.putString("title", title)
    fragment.arguments = bundle
    return fragment
    }
    }
    }
  3. ViewPager的适配器
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    class infoPagerAdapter(val fragManger: FragmentManager, val itemList:MutableList<itemInfo>) : FragmentStatePagerAdapter(fragManger) {
    override fun getCount(): Int = itemList.size
    override fun getItem(p0: Int): Fragment {
    val item = itemList[p0]
    return BlankFragment.newInstance(p0, item.pic, item.desc, item.name)
    }

    override fun getPageTitle(position: Int): CharSequence? {
    return itemList[position].name
    }
    }
    4.给ViewPager添加适配器
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    class MainActivity : FragmentActivity(){
    //这个时候,继承的是FragmentActivity
    override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)
    var vp:ViewPager = findViewById(R.id.vp)
    var title: PagerTabStrip = findViewById(R.id.title)
    val list:MutableList<itemInfo> = mutableListOf()
    //省略中间给list赋值的过程
    vp.adapter = infoPagerAdapter(supportFragmentManager, list)
    vp.currentItem = 0
    }
    }

Kotlin学习笔记——GridView

Kotlin学习笔记——GridView

1
#define 小毛驴 xml

使用方法

  1. 设计好界面
  2. 新建一个小毛驴文件,这个小毛驴文件是GridView中,每一个Item的界面布局文件
  3. (可选)编写一个数据类,用来保存每个item中的数据,用data class可以很方便
  4. 编写一个继承BaseAdapter适配器的类
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    class GridAdapter(private val context: Context, private val strList:MutableList<myItems>, private val background:Int) : BaseAdapter() {
    override fun getView(position: Int, convertView: View?, parent: ViewGroup?): View {
    var view = convertView
    val holder:ViewHolder
    if (convertView == null) {
    view = LayoutInflater.from(context).inflate(R.layout.item, null)
    //我猜这个函数的作用是指定这个类所对应的小毛驴文件
    holder = ViewHolder()
    holder.myLayout = view.findViewById<LinearLayout>(R.id.all)
    holder.desc = view.findViewById<TextView>(R.id.textView)
    holder.pic = view.findViewById<ImageView>(R.id.imageView)
    view.tag = holder
    } else {
    holder = (view?.tag) as ViewHolder
    }
    //以上是固定格式
    val myItem = strList[position]
    //传进来的数据数组,适配器根据数组大小反复调用这个函数构造ViewList
    //position是当前位置,对应数组下标
    //holder.myLayout.setBackgroundColor(background)
    holder.desc.text = myItem.desc
    holder.pic.setImageResource(myItem.image)
    //以上是自定义每个控件的显示内容
    return view!!
    }

    override fun getItem(position: Int): Any = strList[position]
    override fun getItemId(position: Int): Long = position.toLong()
    override fun getCount(): Int = strList.size

    inner class ViewHolder {
    lateinit var myLayout:LinearLayout
    lateinit var desc: TextView
    lateinit var pic: ImageView
    }
    }
  5. 如果编写了数据类(起了一个c++结构体的作用,因为数组只能传递一个),创建对应的List并且赋值
  6. 给GridView添加适配器
    1
    2
    3
    4
    5
    6
    7
    8
    9
    var grid:GridView = findViewById(R.id.panel)
    var pics = arrayOf(R.mipmap.a, R.mipmap.b, R.mipmap.c, R.mipmap.d, R.mipmap.e, R.mipmap.f, R.mipmap.g, R.mipmap.h)
    var descs = arrayOf("超级大帅哥刘甜甜", "刘甜甜最喜欢的大明星周周", "刘甜甜最喜欢的性感裸男", "刘甜甜最想养的橘猫", "还是超级大帅哥刘甜甜", "刘甜甜最喜欢的动画人物米奇", "还是刘甜甜最喜欢的动画人物米奇", "用来凑数的发际线哥")
    var data:MutableList<myItems> = mutableListOf()
    for (i in pics.indices) {
    data.add(myItems(descs[i], pics[i]))
    }
    grid.adapter = GridAdapter(this, data, Color.GRAY)
    grid.numColumns = 2//设置列数