Skip to content

Commit 22d854d

Browse files
👍新增Android冷门知识点
1 parent 4bab0c1 commit 22d854d

File tree

9 files changed

+523
-0
lines changed

9 files changed

+523
-0
lines changed
Lines changed: 172 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,172 @@
1+
本文转载自:https://zhuanlan.zhihu.com/p/30879859
2+
3+
# 四大组件相关:
4+
5+
1.启动一个Activity,在应用进程至少需要两个Binder线程。
6+
7+
2.启动一个launchMode为singleTask的Activity,它并不一定会运行在新的Activity栈中。
8+
9+
3.两个不同应用的Activity,可以运行在同一个Activity栈中。
10+
11+
4.同一个应用进程中的所有Activity,共享一个WindowSession。
12+
13+
5.弹出一个AlertDialog,不一定需要Activity级别的Context,而且任何地方都有办法弹出一个AlertDialog,只要是在Application的attachBaseContext之后。
14+
15+
下面是一个简单的demo演示:
16+
17+
首先看DemoApplication,然后看Alert类:
18+
19+
> 在Application中初始化:
20+
21+
import android.app.Application;
22+
23+
public class DemoApplication extends Application {
24+
@Override
25+
public void onCreate() {
26+
Alert.alertAnyWhere();
27+
super.onCreate();
28+
}
29+
}
30+
31+
32+
> 下面这个类是对AlertDialog的封装类:
33+
34+
35+
import android.app.AlertDialog;
36+
import android.content.Context;
37+
import android.content.DialogInterface;
38+
import android.os.Build;
39+
import android.os.Handler;
40+
import android.os.Looper;
41+
import android.view.WindowManager;
42+
import java.lang.reflect.Method;
43+
44+
public class Alert {
45+
46+
public static void alertDialog() {
47+
Context mAppContext = null;
48+
try {
49+
Class<?> clazz = Class.forName("android.app.ActivityThread");
50+
Method method = clazz.getDeclaredMethod("currentApplication", new Class[0]);
51+
mAppContext = (Context) method.invoke(null, new Object[0]);
52+
} catch (Throwable e) {
53+
e.printStackTrace();
54+
return;
55+
}
56+
57+
AlertDialog.Builder builder = new AlertDialog.Builder(mAppContext);
58+
builder.setTitle("Hi")
59+
.setMessage("Hello World");
60+
.setPositiveButton("确定", new DialogInterface.OnClickListener() {
61+
@Override
62+
public void onClick(DialogInterface dialog, int which) {
63+
dialog.dismiss();
64+
}
65+
})
66+
.setNegativeButton("取消", new DialogInterface.OnClickListener() {
67+
@Override
68+
public void onClick(DialogInterface dialog, int which) {
69+
}
70+
});
71+
AlertDialog dialog = builder.create();
72+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
73+
dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_TOAST);
74+
} else {
75+
dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_PHONE);
76+
}
77+
dialog.show();
78+
}
79+
80+
81+
private static Handler handler;
82+
83+
public static void alertAnyWhere() {
84+
if (Looper.myLooper() == Looper.getMainLooper()) {
85+
alertDialog();
86+
} else {
87+
if (handler == null) {
88+
handler = new Handler(Looper.getMainLooper());
89+
}
90+
handler.post(new Runnable() {
91+
@Override
92+
public void run() {
93+
alertDialog();
94+
}
95+
});
96+
}
97+
}
98+
99+
}
100+
101+
102+
103+
104+
105+
6.可以通过设置Activity主题android.R.style.Theme_NoDisplay,来启动一个不显示的Activity,在某些需要过渡的地方很实用。
106+
107+
7.Activity、Service、Receiver在没有配置intent-filter的action属性时,exported默认为false,配置了intent-filter的action属性时,exported默认为true。稍有不慎,很可能埋下越权、Intent攻击等安全隐患。
108+
109+
8.当从最近使用应用列表中移除某个App时,四大组件只有Service拥有神奇的onTaskRemoved回调,但是并不一定回调,还与stopWithTask属性等有关。
110+
111+
9.四大组件都运行在主线程,是因为它们在ActityThread中(或Instrumentation)实例化;它们的生命周期也运行在主线程,是因为通过ActivityThread.H将消息从Binder线程发送到主线程,然后执行回调。
112+
113+
10.TaskStackBuilder的出现基本上解决了所有构造Activity回退栈的问题。
114+
115+
11.ContentProvider的onCreate()方法先于Application的onCreate()方法执行,晚于Application的attachBaseContext()方法,所以在ContentProvider的onCreate()时候也是有办法弹出一个AlertDialog的(参考5)。
116+
117+
12.BroadCastReceiver回调onReceive(Context context,Intent intent)中的context类型各种场景相差很大,静态注册的receiver回调的Context都是ReceiverRestrictedContext,动态注册的receiver有可能是Activity或Application。
118+
119+
13.ServiceRecord和BroadcastRecord自身就是Binder。
120+
121+
14.同一个provider组件名,可能对应多个provider。
122+
123+
124+
125+
# Handler、Message相关:
126+
127+
1.MessageQueue.addIdleHandler可以用来在线程空闲的时候,完成某些操作,比较适合那种需要在将来执行操作,却又不知道需要指定多少延迟时间的操作。
128+
129+
2.Message.what尽量不要设置成0,因为postRunnable的方式会生成Message.what为0的消息,如果删除了what为0的Message,也会将runnable方式创建的Message删掉。
130+
131+
3.Handler可以设置同步异步(默认是同步的),他们的区别在于异步不会被Barrier阻塞,而同步会被阻塞。
132+
133+
4.Handler的消息分发流程是如果Message的callback不为空,通过callback处理,如果Handler的mCallback不为空,通过mCallback来处理,如果前两个都为空,才调用handleMessage来处理。在DroidPlugin中,便是利用ActivityThread.H的这一特性,拦截了部分消息,实现Activity的插件化。
134+
135+
5.Java层和Native层Looper、MessageQueue的创建时序,Java层Looper—>Java层MessageQueue—>Native层NativeMessageQueue—>Native层Looper。
136+
137+
6.Java层通过Handler去发送消息,而Native层是通过Looper发消息。
138+
139+
140+
141+
# Window、View相关:
142+
143+
1.硬件加速在Window级只能开不能关,View级只能关不能开。
144+
145+
2.自android2.3删除MidWindow后,PhoneWindow成了Window的唯一实现类。
146+
147+
3.WMS管理Window的过程中涉及4个Binder,应用进程只有ViewRootImpl.W一个Binder服务端。
148+
149+
4.MotionEvent、KeyEvent、DragEvent等具有相似的链式缓存,类似Message。
150+
151+
5.在View的状态保存、恢复过程中,ActionBar中所有View共享一个SparseArray容器,ContentView中所有View共享一个SparseArray容器。当前获取焦点的View会额外存储。
152+
153+
6.设置ViewTreeObserver的系列监听方法需要确保View在attachToWindow之后,否则可能因为add监听和remove监听不是作用于同一个对象而引起内存泄漏等。
154+
155+
156+
157+
# Binder、IPC、进程等相关
158+
159+
1.可以通过文件锁来实现进程间互斥(参考:RePlugin),在处理某些只需要单进程执行的任务时很实用。
160+
161+
2.Binder设计架构中,只有Binder主线程是由本进程主动创建,Binder普通线程都是由Binder驱动根据IPC通信需求被动创建。
162+
163+
3.oneway与非oneway,都需要等待Binder Driver的回应消息(BR_TRANSACTION_COMPLETE),区别在于oneway不用等待BR_REPLY消息。
164+
165+
4.mediaserver和servicemanager的主线程都是binder线程,但system_server的主线程不是Binder线程,system_server主线程的玩法跟应用进程一样。
166+
167+
5.同一个BpBinder可以注册多个死亡回调,但Kernel只允许注册一次死亡通知。
168+
169+
6.应用进程由Zygote进程孵化而来,在它真正成为应用进程之前,系统通过抛异常的方式来清理栈帧,并反射调用ActivityThread的main方法。
170+
171+
7.在Binder通信的过程中,数据是从发起通信进程的用户空间直接写到目标进程内核空间,内核空间的数据释放是由用户空间控制的。
172+

Android开发遇到的坑汇总/Android开发遇到的坑.md

Whitespace-only changes.
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
2+
3+
public class BinaryTreeDemo {
4+
5+
public static void main(String[] args){
6+
7+
}
8+
9+
public boolean specialPath(Node *pRoot,Node *pNode,vector<int> &v){
10+
if(pRoot==NULL){
11+
return false;
12+
}
13+
v.push_back(pRoot->m_value);
14+
boolean found=false;
15+
if(pRoot==pNode){//还是比较指针稳妥,节点值有可能重复
16+
for(int i=0;i<v.size();i++){
17+
cout<<v[i]<<" ";
18+
}
19+
cout<<endl;
20+
return true;
21+
}
22+
if(!found && pRoot->m_pLeft){
23+
found=specialPath(pRoot->m_pLeft,pNode,v);
24+
}
25+
26+
//一旦左子树中找到节点,就不需要再遍历右子树
27+
if(!found && pRoot->m_pRight){
28+
found=specialPath(pRoot->m_pRight,pNode,v);
29+
}
30+
if(!found){
31+
v.pop_back();
32+
}
33+
return found;
34+
}
35+
36+
class Node{
37+
Node m_pLeft;
38+
Node m_pRight;
39+
int m_value;
40+
}
41+
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
2+
/**
3+
* 冒泡排序demo
4+
*/
5+
public class BubbleSortDemo{
6+
7+
/**
8+
* 冒泡排序方式1
9+
*/
10+
public void bubbleSort(int[] score){
11+
for(int i =0;i < score.length - 1;i++) {
12+
for(int j = 0;j < score.length - 1-i;j++) { // j开始等于0
13+
if(score[j] < score[j+1]) {
14+
int temp = score[j];
15+
score[j] = score[j+1];
16+
score[j+1] = temp;
17+
}
18+
}
19+
}
20+
}
21+
22+
/**
23+
* 冒泡排序方式2
24+
* 倒着遍历
25+
*/
26+
public void bubbleSort2(int[] score){
27+
for(int i =0;i < score.length - 1;i++){
28+
for(int j = (score.length - 2);j >= 0;j--){
29+
if(score[j] < score[j+1]){
30+
int temp = score[j];
31+
score[j] = score[j+1];
32+
score[j+1] = temp;
33+
}
34+
}
35+
}
36+
}
37+
}
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
2+
/**
3+
* 快速排序demo
4+
* 使用二叉树的原理去解决:
5+
*
6+
* 堆是一颗被完全填满的二叉树,有可能的例外是在底层,底层上的元素从左到右填入。
7+
这样的树称为完全二叉树。
8+
*
9+
* 堆的性质:
10+
比如我们想找出最大元,因为最大元在根上,
11+
而且任意子树也是一个堆,那么任意节点就应该大于它的所有后裔。
12+
*/
13+
public class HeapSort2Demo{
14+
15+
public static void main(String[] args) {
16+
int a[] = { 51, 46, 20, 18, 65, 97, 82, 30, 77, 50 };
17+
heapSort(a);
18+
System.out.println(Arrays.toString(a));
19+
}
20+
21+
/**
22+
* 堆排序
23+
*
24+
* @param ts
25+
*/
26+
public static <T extends Comparable<? super T>> void heapSort(T[] ts) {
27+
28+
// 通过下虑,将数组初始化成一个堆。
29+
for (int length = ts.length, i = length / 2 - 1; i >= 0; i--)
30+
percDown(ts, i, length);
31+
32+
// 对具有堆性质的数组排序
33+
for (int len = ts.length - 1; len >= 0; len--) {
34+
// 将最大元[0]删除,即放到堆尾,堆尾元素放到最大元位置
35+
swap(ts, len);
36+
// 对最大元位置元素 下虑
37+
percDown(ts, 0, len);
38+
}
39+
}
40+
41+
/**
42+
* 下虑 找出最大元
43+
* @param ts
44+
* @param index
45+
* @param length
46+
*/
47+
private static <T extends Comparable<? super T>> void percDown(T[] ts, int i, int length) {
48+
49+
T temp = ts[i];// 待调整最大元位置元素
50+
51+
for (int child = leftChild(i); child < length; i = child, child = leftChild(i)) {
52+
53+
// 判断有右儿子&&右儿子>左儿子
54+
if (child + 1 != length && ts[child + 1].compareTo(ts[child]) > 0) {
55+
child++;
56+
}
57+
// 最大儿子跟父比较
58+
if (temp.compareTo(ts[child]) < 0){
59+
ts[i] = ts[child];
60+
}
61+
else {
62+
break;
63+
}
64+
}
65+
66+
ts[i] = temp;// 放到正确位置
67+
}
68+
69+
/**
70+
* 堆尾、堆首互换
71+
* @param ts
72+
* @param index
73+
*/
74+
private static <T extends Comparable<? super T>> void swap(T[] ts, int index) {
75+
T temp = ts[index];
76+
ts[index] = ts[0];
77+
ts[0] = temp;
78+
}
79+
80+
/**
81+
* 左儿子位置
82+
* @param i
83+
* @return
84+
*/
85+
private static int leftChild(int i) {
86+
return i * 2 + 1;
87+
}
88+
89+
}
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
2+
/**
3+
* 快速排序demo
4+
*/
5+
public class HeapSortDemo{
6+
7+
public static void main(String[] args) {
8+
int a[] = { 51, 46, 20, 18, 65, 97, 82, 30, 77, 50 };
9+
heapSort(a);
10+
System.out.println(Arrays.toString(a));
11+
}
12+
13+
/**
14+
* 堆排序
15+
*/
16+
public static void heapSort(int[] a) {
17+
int i;
18+
for (i = a.length / 2 - 1; i >= 0; i--) {// 构建一个大顶堆
19+
adjustHeap(a, i, a.length - 1);
20+
}
21+
for (i = a.length - 1; i >= 0; i--) {// 将堆顶记录和当前未经排序子序列的最后一个记录交换
22+
int temp = a[0];
23+
a[0] = a[i];
24+
a[i] = temp;
25+
adjustHeap(a, 0, i - 1);// 将a中前i-1个记录重新调整为大顶堆
26+
}
27+
}
28+
29+
30+
/**
31+
* 构建大顶堆
32+
*/
33+
private static void adjustHeap(int[] a, int i, int len) {
34+
int temp, j;
35+
temp = a[i];
36+
for (j = 2 * i; j < len; j *= 2) {// 沿关键字较大的孩子结点向下筛选
37+
if (j < len && a[j] < a[j + 1]){
38+
++j; // j为关键字中较大记录的下标
39+
}
40+
if (temp >= a[j]){
41+
break;
42+
}
43+
a[i] = a[j];
44+
i = j;
45+
}
46+
a[i] = temp;
47+
}
48+
49+
}

0 commit comments

Comments
 (0)