基础03-Lifecycle

lifeCycle的Observer

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
public interface LifecycleObserver

public interface DefaultLifecycleObserver : LifecycleObserver {
/**
* Notifies that `ON_CREATE` event occurred.
*
*
* This method will be called after the [LifecycleOwner]'s `onCreate`
* method returns.
*
* @param owner the component, whose state was changed
*/
public fun onCreate(owner: LifecycleOwner) {}

/**
* Notifies that `ON_START` event occurred.
*
*
* This method will be called after the [LifecycleOwner]'s `onStart` method returns.
*
* @param owner the component, whose state was changed
*/
public fun onStart(owner: LifecycleOwner) {}

/**
* Notifies that `ON_RESUME` event occurred.
*
*
* This method will be called after the [LifecycleOwner]'s `onResume`
* method returns.
*
* @param owner the component, whose state was changed
*/
public fun onResume(owner: LifecycleOwner) {}

/**
* Notifies that `ON_PAUSE` event occurred.
*
*
* This method will be called before the [LifecycleOwner]'s `onPause` method
* is called.
*
* @param owner the component, whose state was changed
*/
public fun onPause(owner: LifecycleOwner) {}

/**
* Notifies that `ON_STOP` event occurred.
*
*
* This method will be called before the [LifecycleOwner]'s `onStop` method
* is called.
*
* @param owner the component, whose state was changed
*/
public fun onStop(owner: LifecycleOwner) {}

/**
* Notifies that `ON_DESTROY` event occurred.
*
*
* This method will be called before the [LifecycleOwner]'s `onDestroy` method
* is called.
*
* @param owner the component, whose state was changed
*/
public fun onDestroy(owner: LifecycleOwner) {}
}

public fun interface LifecycleEventObserver : LifecycleObserver {
/**
* Called when a state transition event happens.
*
* @param source The source of the event
* @param event The event
*/
public fun onStateChanged(source: LifecycleOwner, event: Lifecycle.Event)
}
  • 可以看到,我们在使用lifecycle.addObserver()时,可以传入LifecycleEventObserverDefaultLifecycleObserver,一个通过event获取当前状态,一个通过不同的回调函数获取当前状态

Activity树

1
2
3
4
5
6
7
8
9
10
11
Activity -- AccountAuthenticatorActivity
|- ActivityGroup -- TabActivity
|- ExpandableListActivity
|- LauncherActivity
|- ListActivity -- PreferenceActivity
|- NativeActivity
|- androidx.core.app.ComponentActivity -- androidx.activity.ComponentActivity -- FragmentActivity -- AppCompatActivity
|- PreviewActivity
|- BootstrapActivity
|- EmptyActivity
|- EmptyFloatingActivity

LifecycleOwner

阅读更多

基础02-viewModel

ViewModel简介

在了解ViewModel之前,我们先来了解一下MVC, MVP, MVVM的发展Difference Between MVC, MVP and MVVM Architecture Pattern in Android

ViewModelStoreOwner

1
2
3
4
5
6
7
interface ViewModelStoreOwner {

/**
* The owned [ViewModelStore]
*/
val viewModelStore: ViewModelStore
}

ViewModelStore

阅读更多

MIUISupermarket移植

VerifyError

1
java.lang.VerifyError: Verifier rejected class com.xiaomi.market.util.UIUtils: void com.xiaomi.market.util.UIUtils.setStatusBarDarkMode(android.app.Activity, boolean) failed to verify: void com.xiaomi.market.util.UIUtils.setStatusBarDarkMode(android.app.Activity, boolean): [0x15] type Undefined unexpected as arg to if-eqz/if-nez (declaration of 'com.xiaomi.market.util.UIUtils' appears in /data/app/~~pH0reBrzyfvMag1T-TAoDw==/com.xiaomi.market-EzZXS_MznmhQs5NCCbvqfA==/base.apk!classes2.dex)
  • 一般出现VerifyError都是因为对smali代码修改,导致无法通过验证。当前遇到过的情况有:
    • 插入代码时无意覆盖了下面会用到的寄存器的值,导致寄存器类型不匹配等问题。
    • 对方法参数类型修改但未修改调用时传入的参数
    • 传递参数时传递了类型不匹配的参数

ClassNotFound

在xiaomi商店中使用了Lmiui/os/Build类,该类继承Landroid/os/Build,且存在于小米系统中,导致类找不到。导致运行时闪退。

对于这类小米系统中才能获取到的类,采用等价替换的方法进行修复。如在Lmiui/os/Build中有:

阅读更多

基础01-Context

大纲

  • Context类
    • 注解
      • 用于标注文件、SharedPreferences、数据库的打开方式的注解
      • 用于标注bindService时,service的flags的注解
      • 用于标注registerReceiver时,receiver的flags的注解
      • 用于标注getService时,servicesName的注解
      • 用于标注createPackageContext、createPackageContextAsUser、createContextAsUser、createApplicationContext时的flags的注解
    • 常量定义
      • 对应上面注解中限制的常量
      • WAL

Context类

Context是抽象类,具体实现在ContextImpl,Application,Service,Activity都直接或间接继承自ContextWrapper,ContextWrapper通过代理的方式调用真正的ContextImpl。

注解

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
/** @hide */
@IntDef(flag = true, prefix = { "MODE_" }, value = {
MODE_PRIVATE,
MODE_WORLD_READABLE,
MODE_WORLD_WRITEABLE,
MODE_APPEND,
})
@Retention(RetentionPolicy.SOURCE)
public @interface FileMode {}

/** @hide */
@IntDef(flag = true, prefix = { "MODE_" }, value = {
MODE_PRIVATE,
MODE_WORLD_READABLE,
MODE_WORLD_WRITEABLE,
MODE_MULTI_PROCESS,
})
@Retention(RetentionPolicy.SOURCE)
public @interface PreferencesMode {}

/** @hide */
@IntDef(flag = true, prefix = { "MODE_" }, value = {
MODE_PRIVATE,
MODE_WORLD_READABLE,
MODE_WORLD_WRITEABLE,
MODE_ENABLE_WRITE_AHEAD_LOGGING,
MODE_NO_LOCALIZED_COLLATORS,
})
@Retention(RetentionPolicy.SOURCE)
public @interface DatabaseMode {}
阅读更多

01-layout

ID

创建 RelativeLayout 时,请务必为视图对象定义 ID。在相对布局中,同级视图可以定义其相对于通过唯一 ID 引用的另一个同级视图的布局。

findViewById

ID 不必在整个树状结构中具有唯一性,但在您搜索的树状结构部分中必须是唯一的。它通常可能是整个树,因此最好尽可能使其具有唯一性。

  • findViewById是View的方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/**
* Finds the first descendant view with the given ID, the view itself if
* the ID matches {@link #getId()}, or {@code null} if the ID is invalid
* (< 0) or there is no matching view in the hierarchy.
* <p>
* <strong>Note:</strong> In most cases -- depending on compiler support --
* the resulting view is automatically cast to the target class type. If
* the target class type is unconstrained, an explicit cast may be
* necessary.
*
* @param id the ID to search for
* @return a view with given ID if found, or {@code null} otherwise
* @see View#requireViewById(int)
*/
@Nullable
public final <T extends View> T findViewById(@IdRes int id) {
if (id == NO_ID) {
return null;
}
return findViewTraversal(id);
}
阅读更多

git的使用

版本控制发展历史

本地代码版本控制

RCS: 只能保存本地的变化情况,无法协同合作

集中式版本控制

SVN: 远端服务器维护版本,本地不保存代码版本

分布式版本控制

阅读更多

01-Flutter-快速入门实战

flutter

  • everything is a widget

widget

在flutter中,所有看得见的看不见的东西都是widget

目录结构

  • android:
  • ios:
  • lib: dart文件,业务逻辑
  • lib/main.dart: 入口
  • pubspec.yaml: 工程信息以及依赖
阅读更多

22-Gradle

核心概念

  • 项目
    • Gradle项目是一个可以构建的软件,例如应用程序或库。
    • 包括一个根项目和任意数量的子项目
  • 构建脚本
    • 构建脚本向 Gradle 详细介绍了构建项目所需采取的步骤。
    • 每个项目可以包含一个或多个构建脚本。
  • 依赖管理
    • 依赖管理是一种用于声明和解析项目所需的外部资源的自动化技术。
    • 每个项目通常都包含许多外部依赖项,Gradle 将在构建过程中解决这些依赖项。
  • 任务
    • 任务是基本的工作单元,例如编译代码或运行测试。
    • 每个项目都包含在构建脚本或插件中定义的一个或多个任务。
  • 插件
    • 插件用于扩展 Gradle 的功能,并可选择向项目贡献任务。

Gradle 项目结构

文件/目录名称 作用
gradlew/gradlew.bat Gradle 包装脚本
build.gradle(.kts) 项目的 Gradle 构建脚本
settings.gradle(.kts) Gradle 设置文件用于定义根项目名称和子项目
src 项目/子项目的源码、资源

使用gradle/gradlew编译

  • 编译

    1
    ./gradlew build
  • 编译单个任务

    1
    2
    ./gradlew :taskname
    ./gradlew taskname

    编译单个任务以及全部依赖

  • 编译多项目工程中的任务

    1
    2
    ./gradlew :subproject:taskName
    ./gradlew subproject:taskName

    :相当于分隔符,第一个冒号可以省略

  • 清理产物

    1
    ./gradlew clean
  • 执行多个任务

    1
    ./gradlew clean build
阅读更多

gallery

牛客刷题-1

小米2019秋招安卓开发笔试题(B)

21. 最少立方数之和

给出一个数字N(0<N<1000000),将N写成立方数和的形式,求出需要的最少立方数个数。
例如N=17,1+8+8 = 17,最少需要3个立方数,则输出3。
N= 28,1+1+1+1+8+8+8=28, 需要7个立方数,1+27=28,需要2个立方数,所以最少立方数为2,则输出2。

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
import java.util.*;

// 注意类名必须为 Main, 不要有任何 package xxx 信息
public class Main {
private static final List<Integer> cubs;
private static final int cubNum;
static {
cubs = new ArrayList<Integer>();
for(int i = 1; i*i*i <= 1000000; i++) {
cubs.add(i*i*i);
}
cubNum = cubs.size();
}
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
// 注意 hasNext 和 hasNextLine 的区别
while (in.hasNextInt()) { // 注意 while 处理多个 case
int n = in.nextInt();
int index = Collections.binarySearch(cubs, n);
if(index < 0) {
index = -index - 2;
}
if(index < 0) {
throw new RuntimeException("unreachable");
}
int[] dp = new int[n+1];
Arrays.fill(dp, Integer.MAX_VALUE);
dp[0] = 0;
for(int j = 1; j <= index+1; j++) {
for(int i = cubs.get(j-1); i <= n; i++) {
dp[i] = Math.min(dp[i], dp[i - cubs.get(j-1)] + 1);
}
}
System.out.println(dp[n]);
}
}
}

完全背包,从所有立方数里选数,取数目最小的情况

资产包打包

阅读更多