实习笔记-8

组件merge

类名.()的写法

1
2
3
4
5
6
7
8
9
inline fun AppCompatActivity.fragmentTransaction(block: FragmentTransaction.() -> Unit): Boolean {
kotlin.runCatching {
val t = supportFragmentManager.beginTransaction()
block.invoke(t)
t.commitNowAllowingStateLoss()
return true
}
return false
}
1
2
3
4
/* 新的协程job */
fun newWorkerThreadCoroutineJob(block: suspend CoroutineScope.() -> Unit): Job {
return GlobalScope.launch(context = Dispatchers.IO, block = block)
}

android-job庫

阅读更多

实习笔记-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(应用名) , 应用图标和应用安装时间

阅读更多

实习笔记-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)
阅读更多

实习笔记-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会被忽略
阅读更多

实习笔记-17

协调问题

  1. outsideLauncher

安卓中的单例模式

  • LayoutInflator也是一个SystemService
  • SYSTEM_SERVICE_FETCHERS是一个hashMap,保存ServiceName->ServiceFetcher的单例
  • ServiceFetctor是一个接口,定义了 T getService(ContextImpl ctx);

安卓中的Builder模式

  • 隔离getter,setter,在对象生成时对成员变量配置,生成后屏蔽
  • dialog
阅读更多

实习笔记-19

SlidingPaneLayout

windowSizeClass – 屏幕布局决策

ActivityEmbedding

Box With Constraints – 不同展示内容决策

Custom Layout – 不同方式布局

阅读更多

实习笔记-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

实习笔记-20

App真正的入口

ActivityThread 中的main方法,一个应用程序对应一个ActivityThread对象,Zygote孵化出一个进程后,就会执行main方法

  • 准备Looper和消息队列
  • thread.attach()方法绑定到ActivityManagerService中

attach方法

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
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
private void attach(boolean system, long startSeq) {
sCurrentActivityThread = this;
mConfigurationController = new ConfigurationController(this);
mSystemThread = system;
if (!system) {
android.ddm.DdmHandleAppName.setAppName("<pre-initialized>",
UserHandle.myUserId());
RuntimeInit.setApplicationObject(mAppThread.asBinder());
final IActivityManager mgr = ActivityManager.getService();
try {
mgr.attachApplication(mAppThread, startSeq);
//
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
}
// Watch for getting close to heap limit.
BinderInternal.addGcWatcher(new Runnable() {
@Override public void run() {
if (!mSomeActivitiesChanged) {
return;
}
Runtime runtime = Runtime.getRuntime();
long dalvikMax = runtime.maxMemory();
long dalvikUsed = runtime.totalMemory() - runtime.freeMemory();
if (dalvikUsed > ((3*dalvikMax)/4)) {
if (DEBUG_MEMORY_TRIM) Slog.d(TAG, "Dalvik max=" + (dalvikMax/1024)
+ " total=" + (runtime.totalMemory()/1024)
+ " used=" + (dalvikUsed/1024));
mSomeActivitiesChanged = false;
try {
ActivityTaskManager.getService().releaseSomeActivities(mAppThread);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
}
});
} else {
// Don't set application object here -- if the system crashes,
// we can't display an alert, we just want to die die die.
android.ddm.DdmHandleAppName.setAppName("system_process",
UserHandle.myUserId());
try {
mInstrumentation = new Instrumentation();
mInstrumentation.basicInit(this);
ContextImpl context = ContextImpl.createAppContext(
this, getSystemContext().mPackageInfo);
mInitialApplication = context.mPackageInfo.makeApplication(true, null);
mInitialApplication.onCreate();
} catch (Exception e) {
throw new RuntimeException(
"Unable to instantiate Application():" + e.toString(), e);
}
}

ViewRootImpl.ConfigChangedCallback configChangedCallback = (Configuration globalConfig) -> {
synchronized (mResourcesManager) {
// TODO (b/135719017): Temporary log for debugging IME service.
if (Build.IS_DEBUGGABLE && mHasImeComponent) {
Log.d(TAG, "ViewRootImpl.ConfigChangedCallback for IME, "
+ "config=" + globalConfig);
}

// We need to apply this change to the resources immediately, because upon returning
// the view hierarchy will be informed about it.
if (mResourcesManager.applyConfigurationToResources(globalConfig,
null /* compat */,
mInitialApplication.getResources().getDisplayAdjustments())) {
mConfigurationController.updateLocaleListFromAppContext(
mInitialApplication.getApplicationContext());

// This actually changed the resources! Tell everyone about it.
final Configuration updatedConfig =
mConfigurationController.updatePendingConfiguration(globalConfig);
if (updatedConfig != null) {
sendMessage(H.CONFIGURATION_CHANGED, globalConfig);
mPendingConfiguration = updatedConfig;
}
}
}
};
ViewRootImpl.addConfigCallback(configChangedCallback);
}