Skip to content

Commit

Permalink
👍新增Android冷门知识点
Browse files Browse the repository at this point in the history
  • Loading branch information
AweiLoveAndroid committed Mar 20, 2018
1 parent 4bab0c1 commit 22d854d
Show file tree
Hide file tree
Showing 9 changed files with 523 additions and 0 deletions.
172 changes: 172 additions & 0 deletions Android中的冷门知识点汇总/Android中的冷门知识汇总.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
本文转载自:https://zhuanlan.zhihu.com/p/30879859

# 四大组件相关:

1.启动一个Activity,在应用进程至少需要两个Binder线程。

2.启动一个launchMode为singleTask的Activity,它并不一定会运行在新的Activity栈中。

3.两个不同应用的Activity,可以运行在同一个Activity栈中。

4.同一个应用进程中的所有Activity,共享一个WindowSession。

5.弹出一个AlertDialog,不一定需要Activity级别的Context,而且任何地方都有办法弹出一个AlertDialog,只要是在Application的attachBaseContext之后。

下面是一个简单的demo演示:

首先看DemoApplication,然后看Alert类:

> 在Application中初始化:
import android.app.Application;

public class DemoApplication extends Application {
@Override
public void onCreate() {
Alert.alertAnyWhere();
super.onCreate();
}
}


> 下面这个类是对AlertDialog的封装类:

import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.os.Build;
import android.os.Handler;
import android.os.Looper;
import android.view.WindowManager;
import java.lang.reflect.Method;

public class Alert {

public static void alertDialog() {
Context mAppContext = null;
try {
Class<?> clazz = Class.forName("android.app.ActivityThread");
Method method = clazz.getDeclaredMethod("currentApplication", new Class[0]);
mAppContext = (Context) method.invoke(null, new Object[0]);
} catch (Throwable e) {
e.printStackTrace();
return;
}

AlertDialog.Builder builder = new AlertDialog.Builder(mAppContext);
builder.setTitle("Hi")
.setMessage("Hello World");
.setPositiveButton("确定", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
}
})
.setNegativeButton("取消", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
}
});
AlertDialog dialog = builder.create();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_TOAST);
} else {
dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_PHONE);
}
dialog.show();
}


private static Handler handler;

public static void alertAnyWhere() {
if (Looper.myLooper() == Looper.getMainLooper()) {
alertDialog();
} else {
if (handler == null) {
handler = new Handler(Looper.getMainLooper());
}
handler.post(new Runnable() {
@Override
public void run() {
alertDialog();
}
});
}
}

}





6.可以通过设置Activity主题android.R.style.Theme_NoDisplay,来启动一个不显示的Activity,在某些需要过渡的地方很实用。

7.Activity、Service、Receiver在没有配置intent-filter的action属性时,exported默认为false,配置了intent-filter的action属性时,exported默认为true。稍有不慎,很可能埋下越权、Intent攻击等安全隐患。

8.当从最近使用应用列表中移除某个App时,四大组件只有Service拥有神奇的onTaskRemoved回调,但是并不一定回调,还与stopWithTask属性等有关。

9.四大组件都运行在主线程,是因为它们在ActityThread中(或Instrumentation)实例化;它们的生命周期也运行在主线程,是因为通过ActivityThread.H将消息从Binder线程发送到主线程,然后执行回调。

10.TaskStackBuilder的出现基本上解决了所有构造Activity回退栈的问题。

11.ContentProvider的onCreate()方法先于Application的onCreate()方法执行,晚于Application的attachBaseContext()方法,所以在ContentProvider的onCreate()时候也是有办法弹出一个AlertDialog的(参考5)。

12.BroadCastReceiver回调onReceive(Context context,Intent intent)中的context类型各种场景相差很大,静态注册的receiver回调的Context都是ReceiverRestrictedContext,动态注册的receiver有可能是Activity或Application。

13.ServiceRecord和BroadcastRecord自身就是Binder。

14.同一个provider组件名,可能对应多个provider。



# Handler、Message相关:

1.MessageQueue.addIdleHandler可以用来在线程空闲的时候,完成某些操作,比较适合那种需要在将来执行操作,却又不知道需要指定多少延迟时间的操作。

2.Message.what尽量不要设置成0,因为postRunnable的方式会生成Message.what为0的消息,如果删除了what为0的Message,也会将runnable方式创建的Message删掉。

3.Handler可以设置同步异步(默认是同步的),他们的区别在于异步不会被Barrier阻塞,而同步会被阻塞。

4.Handler的消息分发流程是如果Message的callback不为空,通过callback处理,如果Handler的mCallback不为空,通过mCallback来处理,如果前两个都为空,才调用handleMessage来处理。在DroidPlugin中,便是利用ActivityThread.H的这一特性,拦截了部分消息,实现Activity的插件化。

5.Java层和Native层Looper、MessageQueue的创建时序,Java层Looper—>Java层MessageQueue—>Native层NativeMessageQueue—>Native层Looper。

6.Java层通过Handler去发送消息,而Native层是通过Looper发消息。



# Window、View相关:

1.硬件加速在Window级只能开不能关,View级只能关不能开。

2.自android2.3删除MidWindow后,PhoneWindow成了Window的唯一实现类。

3.WMS管理Window的过程中涉及4个Binder,应用进程只有ViewRootImpl.W一个Binder服务端。

4.MotionEvent、KeyEvent、DragEvent等具有相似的链式缓存,类似Message。

5.在View的状态保存、恢复过程中,ActionBar中所有View共享一个SparseArray容器,ContentView中所有View共享一个SparseArray容器。当前获取焦点的View会额外存储。

6.设置ViewTreeObserver的系列监听方法需要确保View在attachToWindow之后,否则可能因为add监听和remove监听不是作用于同一个对象而引起内存泄漏等。



# Binder、IPC、进程等相关

1.可以通过文件锁来实现进程间互斥(参考:RePlugin),在处理某些只需要单进程执行的任务时很实用。

2.Binder设计架构中,只有Binder主线程是由本进程主动创建,Binder普通线程都是由Binder驱动根据IPC通信需求被动创建。

3.oneway与非oneway,都需要等待Binder Driver的回应消息(BR_TRANSACTION_COMPLETE),区别在于oneway不用等待BR_REPLY消息。

4.mediaserver和servicemanager的主线程都是binder线程,但system_server的主线程不是Binder线程,system_server主线程的玩法跟应用进程一样。

5.同一个BpBinder可以注册多个死亡回调,但Kernel只允许注册一次死亡通知。

6.应用进程由Zygote进程孵化而来,在它真正成为应用进程之前,系统通过抛异常的方式来清理栈帧,并反射调用ActivityThread的main方法。

7.在Binder通信的过程中,数据是从发起通信进程的用户空间直接写到目标进程内核空间,内核空间的数据释放是由用户空间控制的。

Empty file.
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@


public class BinaryTreeDemo {

public static void main(String[] args){

}

public boolean specialPath(Node *pRoot,Node *pNode,vector<int> &v){
if(pRoot==NULL){
return false;
}
v.push_back(pRoot->m_value);
boolean found=false;
if(pRoot==pNode){//还是比较指针稳妥,节点值有可能重复
for(int i=0;i<v.size();i++){
cout<<v[i]<<" ";
}
cout<<endl;
return true;
}
if(!found && pRoot->m_pLeft){
found=specialPath(pRoot->m_pLeft,pNode,v);
}

//一旦左子树中找到节点,就不需要再遍历右子树
if(!found && pRoot->m_pRight){
found=specialPath(pRoot->m_pRight,pNode,v);
}
if(!found){
v.pop_back();
}
return found;
}

class Node{
Node m_pLeft;
Node m_pRight;
int m_value;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@

/**
* 冒泡排序demo
*/
public class BubbleSortDemo{

/**
* 冒泡排序方式1
*/
public void bubbleSort(int[] score){
for(int i =0;i < score.length - 1;i++) {
for(int j = 0;j < score.length - 1-i;j++) { // j开始等于0
if(score[j] < score[j+1]) {
int temp = score[j];
score[j] = score[j+1];
score[j+1] = temp;
}
}
}
}

/**
* 冒泡排序方式2
* 倒着遍历
*/
public void bubbleSort2(int[] score){
for(int i =0;i < score.length - 1;i++){
for(int j = (score.length - 2);j >= 0;j--){
if(score[j] < score[j+1]){
int temp = score[j];
score[j] = score[j+1];
score[j+1] = temp;
}
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@

/**
* 快速排序demo
* 使用二叉树的原理去解决:
*
* 堆是一颗被完全填满的二叉树,有可能的例外是在底层,底层上的元素从左到右填入。
这样的树称为完全二叉树。
*
* 堆的性质:
比如我们想找出最大元,因为最大元在根上,
而且任意子树也是一个堆,那么任意节点就应该大于它的所有后裔。
*/
public class HeapSort2Demo{

public static void main(String[] args) {
int a[] = { 51, 46, 20, 18, 65, 97, 82, 30, 77, 50 };
heapSort(a);
System.out.println(Arrays.toString(a));
}

/**
* 堆排序
*
* @param ts
*/
public static <T extends Comparable<? super T>> void heapSort(T[] ts) {

// 通过下虑,将数组初始化成一个堆。
for (int length = ts.length, i = length / 2 - 1; i >= 0; i--)
percDown(ts, i, length);

// 对具有堆性质的数组排序
for (int len = ts.length - 1; len >= 0; len--) {
// 将最大元[0]删除,即放到堆尾,堆尾元素放到最大元位置
swap(ts, len);
// 对最大元位置元素 下虑
percDown(ts, 0, len);
}
}

/**
* 下虑 找出最大元
* @param ts
* @param index
* @param length
*/
private static <T extends Comparable<? super T>> void percDown(T[] ts, int i, int length) {

T temp = ts[i];// 待调整最大元位置元素

for (int child = leftChild(i); child < length; i = child, child = leftChild(i)) {

// 判断有右儿子&&右儿子>左儿子
if (child + 1 != length && ts[child + 1].compareTo(ts[child]) > 0) {
child++;
}
// 最大儿子跟父比较
if (temp.compareTo(ts[child]) < 0){
ts[i] = ts[child];
}
else {
break;
}
}

ts[i] = temp;// 放到正确位置
}

/**
* 堆尾、堆首互换
* @param ts
* @param index
*/
private static <T extends Comparable<? super T>> void swap(T[] ts, int index) {
T temp = ts[index];
ts[index] = ts[0];
ts[0] = temp;
}

/**
* 左儿子位置
* @param i
* @return
*/
private static int leftChild(int i) {
return i * 2 + 1;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@

/**
* 快速排序demo
*/
public class HeapSortDemo{

public static void main(String[] args) {
int a[] = { 51, 46, 20, 18, 65, 97, 82, 30, 77, 50 };
heapSort(a);
System.out.println(Arrays.toString(a));
}

/**
* 堆排序
*/
public static void heapSort(int[] a) {
int i;
for (i = a.length / 2 - 1; i >= 0; i--) {// 构建一个大顶堆
adjustHeap(a, i, a.length - 1);
}
for (i = a.length - 1; i >= 0; i--) {// 将堆顶记录和当前未经排序子序列的最后一个记录交换
int temp = a[0];
a[0] = a[i];
a[i] = temp;
adjustHeap(a, 0, i - 1);// 将a中前i-1个记录重新调整为大顶堆
}
}


/**
* 构建大顶堆
*/
private static void adjustHeap(int[] a, int i, int len) {
int temp, j;
temp = a[i];
for (j = 2 * i; j < len; j *= 2) {// 沿关键字较大的孩子结点向下筛选
if (j < len && a[j] < a[j + 1]){
++j; // j为关键字中较大记录的下标
}
if (temp >= a[j]){
break;
}
a[i] = a[j];
i = j;
}
a[i] = temp;
}

}
Loading

0 comments on commit 22d854d

Please sign in to comment.