实习笔记-10

读取软件

  • 声明权限
    1
    2
    3
    4
    5
    6
    7
    8
    9
    <uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
    <!-- 对于安卓11开始 -->
    <uses-permission android:name="android.permission.QUERY_ALL_PACKAGES"
    tools:ignore="QueryAllPackagesPermission" />
    <queries>
    <intent>
    <action android:name="android.intent.action.MAIN" />
    </intent>
    </queries>
1
2
3
4
5
val pm = context.applicationContext.packageManager
val installedApplications = pm.getInstalledApplications(0)
installedApplications.forEach {info ->
//handle info
}
  • 该操作比较耗时,在新线程或协程job中执行

获取应用Label(应用名) , 应用图标和应用安装时间

1
2
3
info.loadIcon(pm)
pm.getApplicationLabel(info)
pm.getPackageInfo(name, 0).firstInstallTime
阅读更多

实习笔记-18

协调问题

  1. 需要SceneEvent的Observer(√)
  2. 跳转问题(√):
    1. battery错误跳转到boost,boost错误跳转到boost
    2. MainPageActivity在任务栈中时,点击通知按钮不跳转到功能页面,没有处理onNewIntent
  3. 在什么位置startService(√)

startActivity的过程

  1. 如果intent指明了Component,直接通过component找到ActivityInfo,否则
  2. 如果Intent指定了组件所在包名,通过包名获取ActivityInfo,否则
  3. 通过ActivityIntentResolver等类的queryIntentForPackage进行模糊匹配,如Action,Category

实习笔记-12

PendingIntent认识

  • PendIntent其实是Intent的封装
  • 不是立刻执行某个行为,而是满足某些条件或触发某些事件后才执行指定的行为
  • 我们的 Activity 如果设置了 exported = false其他应用如果使用 Intent 就访问不到这个 Activity,但是使用 PendingIntent 是可以的。
  • 即:PendingIntent将某个动作的触发时机交给其他应用;让那个应用代表自己去执行那个动作(权限都给他)

获取PendingIntent

1
2
3
4
5
getActivity()
getActivities()
getBroadcast()
getService()
getForegroundService()
1
2
3
4
5
参数:
Context - 上下文对象
requestCode - 请求码
Intent - 请求意图用以指明启动类及数据传递
flags -关键标志位
flags
FLAG_CANCEL_CURRENT 先将当前已有的PendingIntent取消,然后重新生成一个PendingIntent对象。
FLAG_NO_CREATE 如果当前系统中不存在相同的PendingIntent对象,系统将返回null,否则返回已有对象
FLAG_ONE_SHOT 该PendingIntent只作用一次。在该PendingIntent对象通过send()方法触发过后,PendingIntent将自动调用cancel()进行销毁,那么如果你再调用send()方法的话,系统将会返回一个SendIntentException。
FLAG_UPDATE_CURRENT 更新之前PendingIntent中的Intent对象数据,例如更新Intent中的Extras
FLAG_IMMUTABLE 创建的PendingIntent是不可变的,使用send方法发送的附加Intent会被忽略
阅读更多

实习笔记-11

Intent Action相关

chooser

可自定义标题,弹出软件选择器

1
2
3
4
5
6
7
8
9
Intent intent = new Intent();
intent.setAction(Intent.ACTION_SEND);
intent.setType("text/plain");
Intent intent2 = new Intent();
intent2.setAction(Intent.ACTION_CHOOSER);
intent2.putExtra(Intent.EXTRA_TITLE, "please selete a app");
//extra intent
intent2.putExtra(Intent.EXTRA_INTENT, intent);
startActivity(intent2);

方便起见,可以使用

1
Intent.createChooser(Intent,CharSequence)
阅读更多

实习笔记-23

MutableLiveData踩坑

使用MutableLiveData的observer对数据进行观察,跳转界面返回后删除list中的元素,出现CurrentModificationException
改用Vector等线程安全的集合

Binder

Binder 与其他IPC的比较

binder 共享内存 Socket
拷贝一次 0 1
C/S模式,易用性高 控制负载,易用性差 C/S开销大
为每个App分配UID 访问接入点是开放的,不安全 访问接入点是开放的,不安全

共享内存 两个mmap,Binder一个mmap

阅读更多

实习笔记-22

LiveData, MutableLiveData

防止暴露子类某些方法

1
2
val name: LiveData<NameBean> get() = _name
private val _name = MutableLiveData<NameBean>()

界面性能优化ViewStub

根据条件判断某些控件显示,某些不显示时,可以使用ViewStub来减少不必要的实例化开销。

android.view.ViewStub,ViewStub 是一个轻量级的View,它一个看不见的,不占布局位置,占用资源非常小的控件。可以为ViewStub指定一个布局,在Inflate布局的时候,只有 ViewStub会被初始化,然后当ViewStub被设置为可见的时候,或是调用了ViewStub.inflate()的时候。

阅读更多

实习笔记-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暴力递归 点击后无法更新

实习笔记-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成员变量中的保存的上一次测量、布局和绘制时的值;
    }

排序

中文按照拼音排序

阅读更多