This is my thrid blog web site.

0%

quickapp 踩坑记 (一) 入门坑与为什么踩这个坑

简介

主要讲了

  • ubuntu + atom 搭建快应用开发环境
  • 调试相关
    • 无法通过wifi调试以及可能原因
    • 由于调试导致的上传失败
  • 通过 adb 调试快应用
  • 闲话:为何入坑

正文

基本配置

我的ubuntu是 18.04,当然这并不重要,应该说我的系统是ubuntu。环境配置就是很正常的安装一些东西就好了。

目前快应用有3个IDE,一个官方的IDE和华为的两个版本的IDE,看上去都是基于VSCODE的,另外他们都没有linux的版本…

官方好像也有推荐使用:

  • sublxxx(一看我名字都记不住就知道我不喜欢用这个)
  • vscode (安装快应用对应的插件)
  • webstorm(好像没有免费版,我就没用了,尊重一下JetBrains)

首先 install node

然后 install atom

配置一下文本编辑工具

打开 atom

–> 菜单栏 Edit

–> 选择 Preferences (window下可能是File->Settings)

–> 点击按钮 Open Config Folder

–> 打开文件 config.cson

配置对ux文件的语法高亮

1
2
3
4
5
6
"*":
core:
customFileTypes:
"text.html.basic": [
"ux"
]

然后随意弄一下UI theme 和 Syntax theme

我的配置完之后是这样子的

然后就算很正常的npm install -g hap-toolkit

可以选择装一个emmet插件辅助自动补全

走起~

关于调试

无法在线更新

一开始的时候遇到过无法在线安装的问题,后来发现不止是快应用,其他用wifi调试的类似开发方式有时也会遇到。这里的其他开发方式指的是 Ionic 的 Ionic DevApp和React Native的Expo。这两者也是在手机上运行了一个’容器’,方便实现热加载,利用chrome dev tool进行调试等。

言归正传,快应用调试的时候运行

1
npm run server

会生成一堆东西:

这里生成ip地址不一定是对应的本机的地址(当然我图中的是正确的)。如果电脑上装了虚拟机/docker/其他容器,这里的服务器地址有可能会是虚拟机的网卡的ip,同时二维码对应的也是虚拟机的ip,这样扫码是不能在线更新的(因为连不上)

如果扫玛一直扫不出来的话,可以考虑换一个命令行终端。比如我之前用Win10的cmd.exe的时候就不像一个二维码(顺手安利一波cmder)。

当然直接手动输入地址也是ok的。

在这里顺带感谢一下在我遇到这个问题时群里通过ip地址看出是虚拟机ip的那个大哥

ps:这个问题在官方支持usb调试之后就与我绝缘了。

无法上传

在调用快应用的系统能力之网络之上传时,有可能会发生这样的错误

代码是这样子的:

1
2
3
4
5
6
7
8
9
10
11
12
13
import request from '@system.request' //正常的导入

/**
* 正常的使用
*/
request.upload({
url : "http://",
files : o.files,
data : o.data,
method:"POST",
success : onSuccess,
fail: onFetchFail
})

这通常是发生在开了调试工具的时候,一边进行调试一边上传就会报错:

1
2
发生了错误: 1000
Stream Closed
处理方法:

这时候只需要拔掉你的usb线,再次上传,一切ok。

其实就是退出调试模式,单纯运行快应用。

如果想要查看上传过程中的log的话可以使用adb。

adb 调试快应用

鉴于快应用开发的应该是前端的同学,可能不太了解adb是什么
adb = Android Debug Bridge ,android开发可能会用得比较多一点。

一般想要配置adb的话,下载一个android sdk tool就好了(把整个androidt stuido下载下来也是可以的),然后配置环境变量,
一般adb是在

1
$ANDROID_SDK_HOME/platform-tools/

这个目录下。

有时候不想打开chrome-dev-tool,只想在命令行查看log,就可以使用

1
2
3
4
console.info('你的log')
// 好像需要console.info()才可以
// console.log()的日志不能被下面的命令抓取
//(记得不清+不想做实验了)

然后在命令行输入:

1
adb logcat | grep JsConsole

adb logcat 是读取手机运行的日志,快应用运行的日志自然也包含在里面。

然后使用 grep JsConsole 进行筛选。之所以用JsConsole,是因为我目测得出快应用引擎(无论是官方的快应用预览器还是厂商自己的快应用引擎) 都是这个tag。

windows同学没有grep命令的话……可以使用windows上支持bash的终端工具。

最近在ubutn上 adb 有时会与 npm run server 冲突,需要关掉其中一个(或者会自动帮你关到其中一个)

一些闲(fei4)话

比起前端开发,我更加熟悉的可能是android端的开发。虽然也大概清楚前端开发是怎么一回事,但是完完整整地用标记语言+js+css开发一个东西的经验并不是很多。所以如有错漏的,不专业的地方(后续会很多)请轻喷。写这篇东西一是为了征文大赛,二是为了顺带梳理一番开发过程中遇到的问题。

同时最近忙成狗的我也没时间看别人的征文,如果有些内容已经有人指出了,如有巧合纯属雷同,啦啦啦啦啦啦。

在年初的时候学长让了解一下快应用和flutter,然后被flutter的语法劝退之后尝试写起了快应用。想着当时微信小程序封测的时候也对小程序浅尝辄止了一番(学校的小团体搞了比赛,赚了个androd高级进阶和鼠标让我甚是高兴,难以忘怀,特此讨打),但是那时候由于种种原因一直在AIDE上写app,也就没机会没能力继续接触。

而去年学校微信小程序比赛搞起来,发现小程序的IDE和开发流程都变了很多。(2333,无意义感慨)

刚好快应用出来,想着有机会从初期接触一个框架,然后了解这个东西是怎么一步步完善起来的,于是决定踩坑。

小米一面

  • 自我介绍
  • 算法
    • 整形重复数组找出出现奇数次的数字
    • (())字符串匹配
    • 二叉树从右看
  • java
    • 权限关键字
    • 进程与线程
  • Android
    • anr 情况,处理
    • 线程,进程
    • app一般有几个进程
    • 常用了解的讲一下
    • 网络请求

iso7层

5层

网络掩码

小米二面

  • 自我介绍
  • 数据库
    • 触发器
    • 事务
  • realm 线程安全吗
  • 事件分发机制
  • 单链表反转
  • 内存回收机制
  • kotlin 好处
  • kotlin 不需要findviewbyid原理
  • Android 源码看过吗
  • 布局
    • LinearLayout
    • RelativeLayout
  • 强引用 弱引用
  • java 内存泄露,处理
  • handler
  • 启动模式
  • 为什么listview要改成recyclerview
  • mvp与mvc区别
  • java怎么new 一个子类
  • 快应用怎么弄mvp

-

Android Context 相关

Context 基本上就是Activity + Service + Application

Class Overview
Interface to global information about an application environment. This is an abstract class whose implementation is provided by the Android system. It allows access to application-specific resources and classes, as well as up-calls for application-level operations such as launching activities, broadcasting and receiving intents, etc.

Context是用于访问应用资源,类同时也进行application层的操作:启动activity广播以及接收广播

api文档上关于

再看看Context相关的子类.因为Context的父类就直接是java.lang.Object了。

Context的子类有

  • ContextWrapper
  • MockContext

Java Interface NavigableMap

  • Map.Entry<K,V> lowerEntry(K key)
  • K lowerKey(K key);
  • Map.Entry<K,V> floorEntry(K key);
  • K floorKey(K key);
  • ceilingEntry
  • ceilingKey
  • higherEntry
  • higherKey
  • firstEntry
  • lastEntry
  • pollFirstEntry
  • pollLastEntry
  • NavigableMap<K,V> descendingMap();
  • NavigableSet navigableKeySet();
  • NavigableSet descendingKeySet();
  • NavigableMap<K,V> subMap(K fromKey, boolean fromInclusive,K toKey, boolean toInclusive);
  • NavigableMap<K,V> headMap(K toKey,boolean inclusive);
  • NavigableMap<K,V> tailMap(K fromKey, boolean inclusive);
  • SortedMap<K,V> subMap(K fromKey, K toKey);
  • SortedMap<K,V> headMap(K toKey);
  • SortedMao<K,V> tailMap(K fromKey);

Java Interface SortedMap

extends Map

方法

就只有这几个方法,然后就没有内容了

  • Comparator<? super K> comparator();
  • SortedMap<K,V> subMap(K fromKey,K toKey);
  • SortedMap<K,V> headMap(K toKey);
  • SortedMap<K,V> tailMap(K fromKey);
  • K firstKey();
  • K lastKey();
  • Set keySet();
  • Collection values();
  • Set<Map.Entry<K,V>> entrySet();

HashMap

Java AbstractMap

介绍了AbstractMap内的方法和静态方法的实现,内部还有两个静态内部类SImpleEntry,SimpleImmutableEntry暂时不讨论

##构造方法

空的构造方法,

size

通过entrySet获取一个Set<Map.Entry<K,V>>,然后调用Set的size方法

isEmpty

调用size(), 看看size是否为零

containsKey

调用entrySet() 获取Set,调用Set.iterator()获取一个迭代器,使用这个迭代器进行遍历查询
需要注意的是,在方法内部使用了if语句,通过Object key是否为空来确定使用 == null 还是 equals 来进行判断是否匹配

containsValue

同上

get

同上,只不过匹配到了对应的key之后使用Entry.getValue来取出value

put

未实现

remove

同样使用迭代器获取到正确的键值对Entry。
然后如果Entry的值不为空,则调用迭代器的remove把该键值对去掉,
然后返回value

putAll

for循环遍历传入的参数map.entrySet(),然后put(key,value)

clear

调用entrySet().clear()

Set keySet

transient

Collecion values;

transient

keySet()

获取keySet,
如果keySet为空,则new一个AbstractSet{
iterator <-> entrySet.iterator()

size <-> AbstractMap.this.size()
isEmpty<-> AbstractMap.this.isEmpty()
clear <-> AbstractMap.this.clear()
contains <-> AbstractMap.this.containsKey()
}
返回Set

values

原理同上
返回Collection

entrySet

abstract

equals

如果o == this 返回true
如果类型不是Map ,返回false
强制类型转换Object o 为Map o
如果size结果不一致,返回false
迭代器遍历this.entrySet().iterator();
只要o内包含this内所有键值对且一致,则相等
(看代码的话好像不考虑o内部有更多的数据)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
try {
Iterator<Entry<K,V>> i = entrySet().iterator();
while (i.hasNext()) {
Entry<K,V> e = i.next();
K key = e.getKey();
V value = e.getValue();
if (value == null) {
if (!(m.get(key)==null && m.containsKey(key)))
return false;
} else {
if (!value.equals(m.get(key)))
return false;
}
}
} catch (ClassCastException unused) {
return false;
} catch (NullPointerException unused) {
return false;
}

hashCode

迭代器遍历,返回值为所有Entry的hashCode的返回值

toString

没仔细看

clone

throws CloneNotSupportedException
super.clone(),
然后把结果的keySet和values设为null
然后返回

静态方法

eq

现根据是否都为null判断,再调用equals

静态内部类

SimpleEntry

SimpleImmutableEntry

Java Interface Map

Map

Map.java内部可以分成4个部分

  • 逻辑上Map接口需要实现的方法
  • 作为数据结构应该实现的方法
  • 默认实现的方法
  • Map.Entry

逻辑上Map接口需要实现的方法

  • size 大小
  • isEmpty 是否为空
  • containsKey 是否包含有某个键
  • containsValue 是否包含有某个值
  • get 取
  • put 放
  • remove 移除
  • putAll 全部放
  • clear 清楚
  • Set keySet 获取所有键
  • Collection values 获取所有值
  • Set<Map.Entry<K,V>> entrySet 获取所有entry

作为数据结构应该实现的方法

  • boolean equals(Object o)
  • int hashCode

默认方法

  • getOrDefault 从一个键获取一个值,如果没有值,则默认返回
    • 先get ,如果没有就返回默认值,有则返回get到的值
  • forEach 遍历一个map,
    • 用到了BiConsumer
    • 先判断遍历执行的action是否为空,然后通过entrySet获取键值对,然后从键值对拿到key和value,传给action
  • replaceAll
    • 用了BiFunction
    • 遍历一遍entrySet()然后将取到的key,value作为参数给function.apply之后,将结果赋值给value,然后最后entry.setValue
  • putIfAbsent 如果对应的key的value是空的话,就赋值,否则不赋值
  • remove 移除
    • 如果 传入的value和通过key取得的value不一致 则 返回 false, 不移除
    • 如果 通过key取得的value为空,同时map内部不包含该key,也返回false不移除
    • 其他情况 remove(key) ,return true
  • replace 三个参数
    • 同上,remove改为put(key,newValue)
  • replace 两个参数
    • 只要通过key获取到的value不为空或者key在目标map中存在,就可以将传入的value替换到对应的key中
  • computeIfAbsent 如果key对应的value == null, 则对key做处理后 的结果作为value传入
    • 如果 value!= null 或者function的结果==null,则不改变,并返回value
    • 返回的value有可能为空
  • computeIfPresent 如果key对应的value不为空,则处理并将结果传入,其他同上
  • compute 不讲道理,直接将key处理一遍,然后传入到value
  • merge
    • 如果key中已有值,则对oldvalue与newvalue一起处理,然后返回值作为newvalue,否则将传入的value作为newvalue
    • 如果最终newvalue为空,则移除key,否则将newvalue作为新的value传入

Map.Entry

Map.Entry是一个键值对,有简单的

  • getKey
  • getValue
  • setValue
  • equals
  • hashCode
    这些方法,已经内部已经实现了静态的比较方法。
  • comparingByKey 以自然顺序比较
  • comparingByValue 以自然顺序比较
  • comparingByKey 自定义Comparator
  • comparingByValue 自定义 Comparator

source

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
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
public Interface Map<K,V>{
int size();

boolean isEmpty();

boolean constainsKey(Object key);

boolean containsValue(Object value);

V get(Object key);

V put(Object key,Object value);

V remove(Object key);

void putAll(Map<? extends K, ? extends V> m);

void clear();

Set<K> keySet();

Collection<V> values();

Set<Map.Entry<K,V>> entrySet();

Interface Entry<K,V> {
K getKey();

V getValue();

V setValue(V value);

boolean equals(Object o);

int hashCode();

public static <K extends Comparable<? super K> ,V> Comparator<Map.Entry<K,V> comparingByKey(){
return (Comparator<Map.Entry<K,V>> & Serializable) (c1,c2)->c1.getKey().compareTo(c2.getKey());
}

public static <K,V extends Comparable <? super V>> Comparator<Map.Entry<K,V>> comparingByValue(){
return (Comparator<Map.Entry<K,V>> & Serializable) (c1,c2) -> c1.getValue().compareTo(c2.getValue());
}

public static <K,V> Comparator<Map.Entry<K,V>> comparingByKey(Comparator<? super K> cmp){
Objects.requireNonNull(cmp);
return (Comparator<Map.Entry<K,V>> & Serializable)(c1,c2) -> cmp.compare(c1.getKey(),c2.getKey());
}

public static <K,V> Comparator<Map.Entry<K,V>> comparingByValue(Comparator<? super V> cmp){
Objects.requireNonNull(cmp);
return (Comparator<Map.Entry<K,V>> & Serializable)(c1,c2)->cmp.compare(c1.getValue(), c2.getValue());
}
}

boolean equals (Object o);

int hashCode();

default V getOrDefault(Object key , V defaultValue){
V v;
return (((v = get(key)) != null) || constainsKey(key))
? v
: defaultValue;
}

default void forEach(BiConsumer<? super K, ? super V> action){
Objects.requireNonNull(action);
for(Map.Entry<K,V> entry :entrySet()){
K k;
V v;
try{
k = entry.getKey();
v = entry.getValue();
} catch (IllegalStateException ise){
throw new ConcurrentModificationException(ise);
}

action.accept(k,v);
}
}

default void replaceAll(BiFunction<? super K, ? super V, ? extends V> function){
Objects.requireNonNull(function);
for(Map.Entry<K,V> entry : entrySet()){
K k;
V v;
try {
k = entry.getKey();
v = entry.getValue();
} catch (IllegalStateException ise){
throw new ConcurrentModificationException(ise);
}

v = function.apply(k,v);

try{
entry.setValue(v);
} catch(IllegalStateException ise){
throw new ConcurrentModificationException(ise);
}
}
}

default V putIfAbsent(K key, V value){
V v = get(key);
if( v== null){
v = put(key,value);
}

return v;
}

default boolean remove(Object key,Object value){
Object vurValue = get(key);
if(!Objects.equals(curValue ,value) ||
(curValue == null && !constainsKey(key)){
return false;
}
remove(key);
return true;
}

default boolean replace(K key,V oldValue, V newValue){
Object curValue = get(key);
if( !Objects.equals(curValue,oldValue) ||
(curValue == null && !containsKey(key))){
return false;
}

put(key,newValue);
return true;
}

default V replace(K key, V value){
V curValue;
if(((curValue = get(key)) != null) || containsKey(key)){
curValue = put(key,value);
}
return curValue
}

default V computeIfAbsent(K key, Function<? super K, ? extends V> mappingFunction){
Objects.requireNonNull(mappingFunction);
V v;
if((v = get(key)) == null ){
V newValue
if((newValue = mappingFunction.apply(key)) != null) {
put(key, newValue);
return newValue;
}
}

return v;
}

default V computeIfPresent(K key,
BiFunction<? super K , ? super V, ? extends V> remappingFunction){
V oldValue;
if((oldValue = get(key)) != null){
V newValue = remappingFunction.apply(key,oldValue);
if(newValue != null){
put(key,newValue);
return newValue;
} else {
remove(key);
return null;
}
}
}

default V compute(K key,BiFunction<? super K, ? super V , ? extends V> remappingFunction){
Objects.requireNonNull(remappingFunction);

V newValue = remappingFunction.apply(key,oldValue);
if(newValue == null){
if(oldValue != null || containsKey(key)){
remove(key);
return null;
} else {
return null;
}
} else {
put(key,newValue);
return newValue;
}
}

default V merge(K key, V value, BiFunction<? super V, ? super V, ? extends V> remappingFunction){
Objects.requireNonNull(remappingFunction);
Objects.requireNonNull(value);

V oldValue = get(key);
V newValue = (oldValue == null ?) value : remappingFunction.apply(oldValue,value);

if(newValue == null){
remove(key);
} else {
put(key,newValue);
}

return newValue;
}
}

4

4.2

4.2.1 信道容量定义

(2) 信道的信息传输率

  • 如果信源商为H(X),希望在信道输出端接收的信息量就是X(X),由于干扰的存在,一般只能接收到I(X:Y).
  • 输出端Y往往只能获得关于输入x的部分信息,这是由于平均互信息性质决定的:I(X:Y) <= H(X)
  • I(X:Y) 是

(3)信道容量

  • 信道容量C,
  • 单位时间的信道容量C_t^2

(4)结论

  • C与C_t

4.2.2 几种特殊离散信道的信道容量

离散无噪信道信道容量

  • 具有一一对应关系的信道(无损信道)

    • 信道矩阵
      • 对应关系
        • 已知X后,Y没有不确定性
      • C = maxI(X:Y)= maxH(x)=log_2 n (bit/符号)
  • 具有扩展性性能的信道

  • 具有归并性能的无噪信道

    • n>m,输入x的符号集个数大于输出y的符号集个数

Java LinkedList

LinkedList内部有3个transient 变量 分别是

1
2
3
transient int size = 0;
transient Node<E> first;
transient Node<E> last;

想来first与last应该就是头尾结点了.

LinkedList.Node

Node 是一个静态内部类,保存了前后结点和本身的item的信息

源码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class LinkedList<E> extends AbstractSequentialList<E> implements List<E>. Deque<E>, Cloneable, java.io.Serializable{

private static class Node<E> {
E item;
Node<E> next;
Node<E> prev;

Node(Node<E> pre,E element,Node<E> next){
this.item = element;
this.next = next;
this.prev = pre;
}
}
}