100天的打卡还剩一周,这段时间对自己提升也很大,英语阅读,算法,也养成了记小知识点、Tips 的习惯,觉得还是要继续坚持下去,后期内容要根据自己的工作内容或者兴趣稍作调整。

Algorithm

655. Print Binary Tree

Print a binary tree in an m*n 2D string array following these rules:

  1. The row number m should be equal to the height of the given binary tree.
  2. The column number n should always be an odd number.
  3. The root node’s value (in string format) should be put in the exactly middle of the first row it can be put. The column and the row where the root node belongs will separate the rest space into two parts (left-bottom part and right-bottom part). You should print the left subtree in the left-bottom part and print the right subtree in the right-bottom part. The left-bottom part and the right-bottom part should have the same size. Even if one subtree is none while the other is not, you don’t need to print anything for the none subtree but still need to leave the space as large as that for the other subtree. However, if two subtrees are none, then you don’t need to leave space for both of them.
  4. Each unused space should contain an empty string "".
  5. Print the subtrees following the same rules.

Example 1:

> Input:
> 1
> /
> 2
> Output:
> [["", "1", ""],
> ["2", "", ""]]
>

这道题目大致意思就是要按二叉树的层级对应转换成数组。最主要的问题就是确定数组的长度,这个长度可以通过二叉树的最大深度去确定,之后利用递归把节点的值赋值到数组中即可。

private List<List<String>> res;
private int resLen;
public List<List<String>> printTree(TreeNode root) {
res = new ArrayList<>();
resLen = getResRowLen(root);
fillRes(root, 0, resLen - 1, 0);
return res;
}

private void fillRes(TreeNode node, int left, int right, int depth) {
if (node == null) {
return;
}
if (res.size() - 1 < depth) {
List<String> rowItem = new ArrayList<>();
for (int i = 0; i < resLen; i++) {
rowItem.add("");
}
res.add(rowItem);
}

int position = (right - left) / 2 + left;
res.get(depth).set(position, node.val + "");
fillRes(node.left, left, position - 1, depth + 1);
fillRes(node.right, position + 1, right, depth + 1);
}

private int getResRowLen(TreeNode node) {
if (node == null) {
return 0;
}
return 2 * Math.max(getResRowLen(node.left), getResRowLen(node.right)) + 1;
}

运行结果

result

Review

Android App Bundle 是一种新的 App 上传方式,而且很大程度上影响了 App 的构建以及组件化设计。和传统 App 构建方式最大的差别是 App Bundle 把构建 APK 所需的转移到了 Google Play上,这样我们可以根据用户差异而构建不同的 APK。

需要在 build.gradle 文件中的 android 块下添加配置:

bundle {
language {
enableSplit = false
}
density {
enableSplit = true
}
abi {
enableSplit = true
}
}

在编译生产 aab 文件以后可以使用 bundleTool进行验证。

  • build APK

    bundletool build-apks --bundle=/Users/joebirch/releases/sample.aab --output=/Users/joebirch/releases/sample.apks
    --ks=/Users/joebirch/some_keystore.jks
    --ks-pass=file:/Users/joebirch/some_keystore.pwd
    --ks-key-alias=SomeAlias
    --key-pass=file:/Users/joebirch/some_key.pwd
  • install APK

    bundletool install-apks --apks=/Users/joebirch/releases/sample.apks
  • 获取机器配置文件(JSON):

    bundletool get-device-spec

    json 配置文件内容如下:

    {
    "supportedAbis": ["arm64-v8a"],
    "supportedLocales": ["en", "es"],
    "screenDensity": 640,
    "sdkVersion": 21
    }
  • 利用配置文件生成特定的 APK

    bundletool extract-apks
    --apks=/Users/joebirch/releases/someApkSet.apks
    --output-dir=/Users/joebirch/releases/device_APK_set.apks
    --device-spec=/Users/joebirch/releases/some_configuraton.json

Dynamic Feature

使用动态 Feature 需要引入 Play-Core包:

implementation 'com.google.android.play:core:1.3.4'

之后在用户使用动态 Feature 时执行下载及加载:

val splitInstallManager = SplitInstallManagerFactory.create(this);
val request = SplitInstallRequest
.newBuilder()
.addModule("someDynamicModule")
.build(); // 从 google play 请求
splitInstallManager
.startInstall(request) // 后台下载:deferInstall()
.addOnSuccessListener { }
.addOnFailureListener { }
.addOnCompleteListener { };
// 下载过程中遇到错误的监听
val stateListener = SplitInstallStateUpdatedListener { state ->
when (state.status()) {
PENDING -> { }
DOWNLOADING -> { }
DOWNLOADED -> { }
INSTALLED -> { }
INSTALLING -> { }
REQUIRES_USER_CONFIRMATION -> { }
FAILED -> { }
CANCELING -> { }
CANCELED -> { }
}
}
splitInstallManager.registerListener(stateListener)
// 卸载
splitInstallManager
.deferredUninstall(listOf("someDynamicModule"))
.addOnSuccessListener { }
.addOnFailureListener { }
.addOnCompleteListener { };

Exploring the Android App Bundle

Tips

  1. Java 中如果某个方法用 synchronize 修饰,则方法内不能使用静态变量,否则会产生线程安全问题;

  2. Android 开启 SQL log:

    adb shell setprop log.tag.SQLiteLog VERBOSE
    adb shell setprop log.tag.SQLiteStatements VERBOSE
    adb shell stop
    adb shell start
  3. 动画加载

    Animation animation = AnimationUtils.loadAnimation(this, R.anim.hyperspace_jump);

Share

公共技术点之 Android 动画基础