曾大稳丶


  • 首页

  • 分类

  • 标签

  • 归档

  • 关于

c基础

发表于 2018-04-02 | 分类于 c/c++ |
字数统计: 5,863字 | 阅读时长 ≈ 29分钟

基本数据类型以及打印

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
void main() {
int i = 100;
double d = 200;
float f = 200;
long l = 200;
short s = 100;
char c = 'D';
// 字符串 char *

printf("i = %d\n" ,i);
printf("d = %lf\n" ,d);
printf("f = %f\n" ,f);
printf("l = %ld\n" ,l);
printf("s = %d\n" ,s);
printf("c = %c\n" ,c);
getchar();//
}

指针

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

// 指针(变量)地址:任何的数据 (变量)都会有地址(住址门牌号)
// &+变量名就是地址
// *+地址就是取值
void main() {
int i = 100;
//获取地址
printf("i的地址是: %p\n", &i);//xxxxxx
printf("i的值是: %d\n", i);//100
//获取地址的值
printf("i的值是: %d\n", *&i);//100

//指针(地址)变量:指针存放(指向)的就是变量的地址
int* p = &i;
//取值
printf("i的值是: %d\n", *p) //100

double d = 200;
double* p1 = &d;


//通过指针修改值
*p = 200;
printf("i的值是: %d\n", i) // 200

getchar();
}

指针为什么要有类型?

指针其实就是一块地址而且值都差不多,为什么要有类型?
1.取值的时候我要知道怎么取?int 4个字节取 double8个字节取
2.取值的偏移?int偏4个字节 double偏8个字节

常量指针 指针常量

1
2
3
常量变量:被常量修饰的变量,不能再次被赋值 (Java)
常量指针:const 在 * 之前,指针的地址是可以被再次赋值的(可以修改的),指针地址上面的值(变量)是不能被修改的,常量指针的常量是不能被改变的。
指针常量:const 在 * 之后,指针的地址是不可以被再次赋值的(不可以修改的),指针地址上面的值(变量)能被修改的,指针常量的指针地址是不能被改变的。

基本数据类型所占字节数

1
2
3
4
5
6
void main() {
printf("int 数据类型所占字节数: %d\n",sizeof(int));//4
printf("double 数据类型所占字节数: %d\n", sizeof(double));//8
printf("char 数据类型所占字节数: %d\n", sizeof(char));//1
getchar();
}

二级指针

1
2
3
4
5
6
7
8
9

void main() {
int num = 142;
int* p = #
int** s_p = &p;
printf("p = %p, s_p = %p", p, s_p);
printf("num = %d ", **s_p); //142
getchar();
}

数组与数组指针

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
//数组与数组指针
void main() {
int arr[] = { 1, 2, 3, 4 };

//arr的值=arr取地址的值 , arr地址的值 = arr[0]的地址的值(首地址) 他们三个是一个地址
printf("arr = %p\n", arr); // arr = 000000137F6FFAA8
printf("arr& = %p\n", &arr);// arr& = 000000137F6FFAA8
printf("arr[0]& = %p\n", &arr[0]);// arr[0]& = 000000137F6FFAA8

//如何获取数组的指针(首地址)
int* arr_p = arr;

printf("%d \n", *arr_p); // 1

//对数组指针++
arr_p++;
printf("%d \n", *arr_p); // 2

arr_p += 2;
printf("%d \n", *arr_p); // 4

arr_p ++;
printf("%d \n", *arr_p); // -858993460 这里因为已经超出数组长度了

//遍历
int arr2[] = { 5, 8, 9, 4 };

// for (i = 0; i < 4; i++) {
// printf("%d\n", arr2[i]);
// }

//注意for循环的写法,要写成下面这个 写成java的那种,可能会造成操作系统(Linux)不一样而编译不了
//c拿不到arr长度
int i = 0;
for (; i < 4; i++) {
printf("%d\n", arr2[i]);
}

//通过指针来循环遍历
int* arr2_p = arr2;
int j = 0;
for (; j < 4; j++) {
arr2_p++;
printf("%d\n", *arr2_p);
}

//数组指定长度
int arr3[4];
int* arr3_p = arr3;
int k = 0;
for (; k < 4; k++) {
*(arr3_p + k) = k*10;
}
k = 0;

for (; k< 4; k++) {
printf("%d\n", arr3_p[k]);
}

getchar();
}

数组指针操作的常用几种方式

1
2
3
4
5
6
7
8
9
10
11
12
13
//数组指针操作的常用几种方式
void main() {
int arr[] = { 1,3,5,7 };
int i = 0;
for (; i < 4; i++) {
//第一种
printf("位置%d的值是:%d\n", i, *(arr + i));
//第二种
printf("位置%d的值是:%d\n", i, arr[i]);
//....
}
getchar();
}

函数指针(回调)

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
//函数指针
void main() {

//方法的返回类型(*方法的名称)(方法的参数)
void(*add_p)(int, int) = add;
// void(*add_p)(int, int) = &add; //这个一样的
//正常调用
add(1, 2);
//指针调用
(*add_p)(1, 2);


opeate(add, 1, 2);
opeate(mins, 1, 2);


getchar();
}

void add(int num1, int num2) {
printf("num1+num2=%d\n", num1 + num2);
}

void mins(int num1, int num2) {
printf("num1-num2=%d\n", num1 - num2);
}

//方法的返回类型(*方法的名称)(方法的参数)
void opeate(void(*method)(int, int), int num1, int num2) {
method(num1, num2);
}

内存开辟

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
#include <stdio.h>
#include <Windows.h>

//静态开辟内存 方法结束会自动回收
void staticlloc() {
int arr[5];
int i = 0;
for (; i < 5; i++) {
arr[i] = i;
printf("%d %p\n", *(arr + i),arr+i);
}
}
//动态开辟内存 方法结束不会自动回收
void dynamiclloc() {
//malloc申请需要的内存返回void* 这里强转成你需要的指针类型
int* arr = (int*)malloc(10 * 1024 * 1024 * sizeof(int));//40M
}

//动态开辟内存 方法结束不会自动回收 手动释放
void dynamiclloc2free() {
//malloc 申请需要的内存返回void* 这里强转成你需要的指针类型
int* arr = (int*)malloc(10 * 1024 * 1024 * sizeof(int));//40M
//手动释放
free(arr);
}



//内存开辟
void main(){
//Stack overflow 栈溢出
// int arr[10*1024*1024];//占用内存?数组大小10M,int占用4字节,40M的内存空间

//c里面有四驱模型
//栈:占用的内存空间大小 ,开辟内存的方式是静态内存开辟 int arr[10*1024*1024],方法结束会自动回收
//堆:占用内存空间最大值 80% ,开辟内存的方式是动态内存开辟,方法结束不会自动回收,需要手动回收

//静态开辟内存,函数结束会自动回收 内存开辟后不可变
/*
//这里运行 内存不会上升,staticlloc()函数结束会自动回收
while (true){
Sleep(100);
staticlloc();
}
*/

//动态内存开辟 内存开辟后可变
/*
//这里运行 内存会持续上升
while (true) {
Sleep(100);
dynamiclloc();
}
*/

//这里运行 内存不会持续上升,因为手动释放了
while (true) {
Sleep(100);
dynamiclloc2free();
}

getchar();
}

内存开辟使用场景

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

#include<stdio.h>
#include<Windows.h>

//使用场景
void main() {
//假设我们现在需要接受用户所输入的数,然后进行排序

int num;
printf("请输入数的个数: ");
//获取用户输入的值
scanf_s("%d",&num);

//定义一个数组来存放用户的数据
//int arr[num]; 静态开辟

int* arr =(int*) malloc(sizeof(int) * num);

int print_num;
int i = 0;
for (; i < num; i++) {
printf("请输入第%d个的值: ", i);
scanf_s("%d", &print_num);
arr[i] = print_num;//arr[i] = *(arr+i);
}

//对arr排序
//....

//回收动态开辟的内存
free(arr);

getchar();
}

改变内存大小

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

//改变内存空间大小
void main() {
int num;
printf("请输入数的个数: \n");
//获取用户输入的值
scanf_s("%d", &num);
int* arr = (int*)malloc(sizeof(int) * num);
printf("arr的指针: %p \n",arr);

int print_num;
int i = 0;
for (; i < num; i++) {
arr[i] = i;//arr[i] = *(arr+i);
}

int new_num;
//在加点内存
printf("请输入新增的个数: \n");
//获取用户输入的值
scanf_s("%d", &new_num);
//改变内存大小空间
int new_size = sizeof(int)* (num + new_num);
//ptr - 指向需要重新分配的内存区域的指针
//new_size - 数组的新大小(字节数)
//tip1. 这里默认new_arr的指针和arr的指针是同一个,后面赋值可以接着后面的赋值
//tip2. 如果连续内存不足的话返回的话可能是新的指针,那么将要全部重新赋值
//tip3. 新增内存有可能会失败(内存被系统占用或者内存不够用了),失败的时候返回的是 NULL
//tip4. realloc的arr 释放的时候也务必要进行判断NULL,释放完我们最好把指针致为NULL
//tip5. 不要反复去释放
int* new_arr =(int*) realloc(arr, new_size);
printf("new_arr的指针: %p \n", new_arr);
if (new_arr) {// if(new_arr!=NULL)
//tip 1. 这里默认new_arr的指针和arr的指针是同一个,后面赋值可以接着后面的赋值
for (; i < num + new_num; i++) {
arr[i] = i;//arr[i] = *(arr+i);
}
//tip 2. 如果连续内存不足的话返回的话可能是新的指针,那么将要全部重新赋值
i = 0;
for (; i < num + new_num; i++) {
arr[i] = i;//arr[i] = *(arr+i);
}

i = 0;
for (; i < num + new_num; i++) {
printf("%d \n", arr[i]);
}
}

getchar();

if (new_arr) {
//这里arr将不手动回收
//free(arr);
free(new_arr);
new_arr = NULL;
}else {
free(arr);
}
getchar();
}

字符串定义

1
2
3
4
5
6
7
8
9
10
11
12
13
14
void main() {
//第一种 字符串数组
char str[] = {'a','b','c','d','\0'};
printf("%s", str);//字符串结尾是 '\0'

//第二种 常用的
const char *str1 = "abcde";
printf("%s", str1);

//区别 前者能修改 后面不能修改
// str[1] = 'x';
// strstr11] = 'x'; //报错
getchar();
}

字符串基本api

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
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>


//自己实现 获取字符串长度
int strlen_(const char *str) {
int len = 0;
while (*str != '\0') {
len++;
str++;
}
return len;
}




//大小写转换
void lower(char* dest,const char* source) {
while (*source!='\0') {
//当前字符串
char ch = *source;
//转完复制给dest
*dest = tolower(ch);
source++;
dest++;
}
*dest = '\0';
}


//字符串截取 动态内存开辟 用了需要free ndk使用需要静态开辟
char* substr(const char* str, int startIndex, int endIndex) {
//开辟一个内存来存数据 ndk里面使用静态开辟内存 这里vs编辑器会报错所以动态开辟了
//char* subStr[endIndex - startIndex + 1];
int len = endIndex - startIndex;
//这里要注意free
char* subStr = (char*)malloc(len * sizeof(char) + 1);

//赋值
int i = 0;
str += startIndex;
for (; i < len; i++) {
subStr[i] = *str;
str++;
}

subStr[len] = '\0';//标记字符串结尾,否则printf无法判断结尾
return subStr;
}

const char* replace(const char*oldChar, const char*newChar,const char*source) {
//1. 有没有oldChar
const char* pos = strstr(source, oldChar);
if (!pos) {
return source;
}
//2. 计算新的数组大小
int newArraySize = strlen(source) - strlen(oldChar) + strlen(newChar);
//vs不能这样 as最好用静态的
//char result[newArraySize];
char* result = (char*)malloc(sizeof(char)*newArraySize);
//3. 进行拼接
int startIndex= pos - source;
char* start = substr(source,0, startIndex);
char* end = substr(source, startIndex + strlen(oldChar), strlen(source));

strcpy(result,start);
strcat(result, newChar);
strcat(result, end);

//释放资源
free(start);
free(end);

//全部替换 while或者递归
return replace(oldChar, newChar, result);
}


void main() {
//字符串长度获取
const char *str = "HelloGirl\0";
//#include <string.h>
printf("len = %d \n", strlen(str)); // len = 9
printf("len_ = %d \n", strlen_(str)); // len_ = 9

//字符串转换
const char *intStr = "5";
//#include <stdlib.h>
//int num = 0 如果不能转换为int的就会返回0,后面如果不是数字的会被干掉 “12xxx”-> 12
printf("int num = %d \n", atoi(str));
printf("int num = %d \n", atoi(intStr));//int num = 5


const char *floatStr = "0.012";
//#include <stdlib.h>
//float num = 0.000000 如果不能转换为float的就会返回0.000000,后面如果不是数字的会被干掉 “0.012xx”-> 0.012000
printf("float num = %f \n", atof(str));
printf("float num = %f \n", atof(floatStr));//float num = 0.012000

//strol strod ...

//字符串比较
const char *str1 = "Hello";
const char *str2 = "hello";

//区分大小写比较
int rc = strcmp(str1,str2);
if (rc == 0) {
printf("相等\n");
}else {
printf("不相等\n"); // 不相等
}

//不区分大小写比较
rc = _strcmpi(str1,str2); // c->strcmpi c++->_strcmpi android ndk -> strcasecmp
if (rc == 0) {
printf("相等\n");//相等
}else {
printf("不相等\n");
}

//比较前几个
const char *str11 = "Hello";
const char *str21 = "Hello girl";
rc = strncmp(str11, str21,5);//5->_MaxCount 代表的是比较字符串前几个是否相等
if (rc == 0) {
printf("相等\n");//相等
}
else {
printf("不相等\n");
}

//字符串查找 计算位置
const char *str0 = "Hello";
const char *subStr0 = "e";
const char* s= strstr(str0, subStr0);//返回字符串第一次出现的位置(位置指针),如果没有返回NULL
int pos = s - str0;
if (s) {//代表包含
printf("%s 第一次位置在%d\n ", s, pos);// ello 第一次位置在1
}else {
printf("%s", "没有找到");
}

//copy
const char * strh = "hello";
//char dst[strlen(strh)+1]; //不知道为什么要报错 在as里面可以的
char dst[6];
// error C4996 : 'strcpy' : This function or variable may be unsafe.Consider using strcpy_s instead.To disable deprecation, use _CRT_SECURE_NO_WARNINGS.See online help for details.
strcpy(dst, strh);
printf("%s\n", dst); //hello

//拼接
const char *str001 = "Gril";
strcat(dst,str001);
printf("%s\n", dst); //helloGril

//截取
char *subStr = substr(dst,1,4);
printf("%s\n", subStr); //ell
free(subStr);


//大小写转换
const char *hello = "HELLO";
char helloLower[6];
lower(helloLower, hello);
printf("%s\n", helloLower);//hello

//字符串替换
const char* rs= replace("LL","AA","HELLOLL");
printf("%s", rs); // HEAAOAA
//free(rs);

getchar();
}

结构体 java的class

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
#include <stdio.h>
#include <string.h>

//第一种方式
struct Worker {//定义一个结构体 相当于java的class
char name[10];
int age;
double salary;
};


//第二种方式,可以直接取名字
struct Worker2 {//定义一个结构体 相当于java的class
char name[10];
int age;
double salary;
}zhangsan, lisi = {"李四",25,20};


struct Work{
char name[10];
char grade[10];
};
//第三种方式,结构体的嵌套
struct Worker3{
char name[10];
int age;
double salary;
Work work;
};

//第四种方式,结构体的嵌套,直接在内部定义 java内部类 这种不测了 一样的道理
struct Worker4 {
char name[10];
int age;
double salary;
Work work;
struct Work {
//...
}work;

//struct Work{
// //...
//}work;
};


//第一种方式
void test1() {
// struct Worker worker;//第一种方式没有初始化的情况下,里面的属性都没有初始值的
struct Worker worker = { "张三",25,120 };
printf("name = %s,age = %d ,salary = %lf \n", worker.name, worker.age, worker.salary);//name = 张三,age = 25 ,salary = 120.000000

//赋值
worker.age = 85;
// worker.name = "李四";
strcat_s(worker.name, "李四");
printf("修改之后了name = %s,age = %d ,salary = %lf", worker.name, worker.age, worker.salary);//修改之后了name = 张三李四,age = 85 ,salary = 120.000000
}

//第二种方式
void test2() {
//这种方式有默认的初始值
printf("name = %s,age = %d ,salary = %lf \n", zhangsan.name, zhangsan.age, zhangsan.salary);//name = ,age = 0 ,salary = 0.000000
strcat_s(zhangsan.name, "张三");
zhangsan.age = 50;
printf("修改之后了name = %s,age = %d ,salary = %lf \n", zhangsan.name, zhangsan.age, zhangsan.salary);//修改之后了name = 张三,age = 50 ,salary = 0.000000

printf("name = %s,age = %d ,salary = %lf \n", lisi.name, lisi.age, lisi.salary);// name = 李四,age = 25 ,salary = 0.000000
}

void test3() {
struct Worker3 worker = { "张三",50,10000,{ "Android","mid"}};
//name = 张三,age = 50 ,salary = 10000.000000 ,worker.name = Android,worker.grade = mid
printf("name = %s,age = %d ,salary = %lf ,worker.name = %s,worker.grade = %s \n", worker.name, worker.age, worker.salary, worker.work.name,worker.work.grade);
}


void main() {

// test1();
// test2();
test3();
getchar();
}

结构体指针

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
#include <stdio.h>
#include <string.h>
#include <malloc.h>

struct Worker
{
char name[10];
int age;
};


//第一种方式
void test1()
{
struct Worker worker = { "张三",56 };
Worker* worker_p = &worker;
//结构体一般用worker.name ="" 指针一般用worker_p->name =""
worker_p->age = 24;
strcpy(worker_p->name, "李四");
printf("name = %s,age= %d \n", worker_p->name, worker_p->age);//name = 李四,age= 24

}
//第二种方式 比较常用
void test2() {
Worker *worker_p =(Worker*) malloc(sizeof(Worker));
strcpy(worker_p->name, "李四");
worker_p->age = 24;
printf("name = %s,age= %d \n", worker_p->name, worker_p->age);//name = 李四,age= 24

//释放
if (worker_p) {
free(worker_p);
worker_p = NULL;
}
}

int main() {
// test1();
test2();
getchar();
return 0;
}

结构体内存开辟以及内存计算
内存大小参考

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

#include <stdio.h>
#include <string.h>
#include <malloc.h>

struct Worker
{
char name[10];
int age;

//计算大小:
//1. char name[10] -> sizeof(char) = 1 * 10 =10;
//2. int age -> sizeof(char) = 4 之前的偏移是10,不是4的整数,偏移两个单位到12 然后+4 = 16
//3. 16是 结构体里面基本数据类型最大int 4的整数,所以最终结果为16
};


//静态开辟
void test1() {
Worker worker[10] = { {"张三",35} };//静态开辟
worker[9] = {"lisi",25};

printf("name0 = %s ,age0 = %d \n",worker[0].name,worker[0].age);//name0 = 张三 ,age0 = 35
printf("name9 = %s ,age9 = %d \n",worker[9].name,worker[9].age);//name9 = lisi ,age9 = 25

}

//动态开辟
void test2() {
Worker* worker =(Worker*) malloc(sizeof(Worker) * 10);

strcpy(worker->name,"张三");
worker->age = 25;

printf("name= %s ,age = %d \n",worker->name,worker->age);//name= 张三 ,age = 25


//对第9个数做操作
worker += 9;
strcpy(worker->name, "李四");
worker->age = 35;
printf("name= %s ,age = %d \n", worker->name, worker->age);//name= 李四 ,age = 35

}

//内存怎么计算的?
void test3() {
//计算规则
//1. 每个成员的偏移量都必须是当前成员所占内存大小的整数倍如果不是编译器会在成员之间加上填充字节。
//2. 当所有成员大小计算完毕后,编译器判断当前结构体大小是否是结构体中最宽的成员变量大小的整数倍 如果不是会在最后一个成员后做字节填充。
int size = sizeof(Worker);
printf("size = %d",size);//size = 16
}

struct date //12
{
int year;
int month;
int day;

// 都是4 3*4 = 12;
};
struct student
{
int number;//4
char sex;//1
int gae;//4
char name[10];//10
struct date birthday;//12

//1. int number = 4
//2. char sex; 4+1=5;
//3. int age;之前的偏移量是5,不是int 4字节的整数,所以偏移到8,然后+4 =12
//4. char name[10] 12+10=22
//5. 12+22 = 34
//6. 34不是这里面最大基本数据类型int 4的整数,所以最终结果是36

};

void test4() {
int size = sizeof(date);
printf("date size = %d\n", size);//size = 12

size = sizeof(student);
printf("student size = %d\n", size);//size = 36
}


int main() {
// test1();
// test2();
// test3();
test4();
getchar();
return 0;
}

结构体或结构体指针别名

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
#include <stdio.h>
#include <string.h>
#include <malloc.h>


struct Worker
{
char name[10];
int age;

};


//对结构体指定别名
//别名
typedef Worker Worker_, Person;
void test1() {
Worker_ worker = {"李四",24};
printf("name = %s ,age = %d \n",worker.name,worker.age);//name = 李四 ,age = 24

Person person = { "张三",25 };
printf("name = %s ,age = %d \n ", person.name, person.age);//name = 张三 ,age = 25
}

//对结构体指针指定别名

typedef Worker* Worker_P;
void test2() {
Worker_P worker_p =(Worker*)malloc(sizeof(Worker));
worker_p->age = 25;
printf("age = %d \n ", worker_p->age);//age = 25
}


int main() {
//test1();
test2();

getchar();

return 0;
}

联合体定义以及大小计算

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
#include <stdio.h>
#include <string.h>

//定义联合体,和结构体定义一样,联合体只能存在一个属性,这里要么是name,要么是age,设置值以最后为主
//大小计算 取最大值即可,然后判断是否整除该联合体里面最大基本数据类型长度,不够偏移到整除为止。
union Person
{
char name[10];
int age;

//计算: name是10 age是4 找最大值 ,然后10不能整除最大的基本数据类型int 4,所以为12
};

int main() {

//Person person = {"李四"};

Person person;
person.age = 25;
strcpy_s(person.name,"zhangsan");
printf("person.name = %s , person.age = %d\n",person.name,person.age); // person.name = zhangsan , person.age = 1851877498


strcpy_s(person.name, "zhangsan");
person.age = 25;
printf("person.name = %s , person.age = %d\n", person.name, person.age); // person.name =  , person.age = 25


printf("size = %d \n", sizeof(Person));//12

getchar();
return 0;
}

枚举的定义

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <stdio.h>


//枚举的定义 ,如果中途有定义值得话,后面累加,前面还是从0开始
enum CommentType {
TEXT,IMAGE,TEXT_IMAGE
};

void main() {
CommentType commentType = TEXT;
CommentType commentType1 = IMAGE;
CommentType commentType2 = TEXT_IMAGE;
printf("%d , %d , %d",commentType, commentType1, commentType2);//0 , 1 , 2
getchar();
}

文件读写

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
#include <stdio.h>

int main() {
const char * fileName = "C:/Users/Administrator/Desktop/a.txt";
//打开文件 打开方式r,w具体看文档
FILE* afile_p = fopen(fileName,"r");
if (!afile_p) {
printf("文件打开失败!");
getchar();
return -1;
}

//fputs 写入 需要拥有写的模式

char buffer[10];
//缓冲区buffer ,长度10 ,文件指针
while (fgets(buffer, 10, afile_p)) {
printf("%s", buffer);
}
//关闭文件
fclose(afile_p);
getchar();

return 1;
}

文件复制

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
#include <stdio.h>
int main() {
const char * srcFileName = "C:/Users/Administrator/Desktop/ee.png";
const char * copyFileName = "C:/Users/Administrator/Desktop/ee2.png";
//打开文件 打开方式r,w具体看文档
FILE* afile_p = fopen(srcFileName, "rb");
FILE* copyfile_p = fopen(copyFileName, "wb");
if (!afile_p) {
printf("文件打开失败!");
getchar();
return -1;
}

int buffer[512];
int len;
while ((len = fread(buffer, sizeof(int), 512, afile_p))!=0) {
fwrite(buffer, sizeof(int), len, copyfile_p);
// fflush(copyfile_p);
}

//关闭文件
fclose(afile_p);
fclose(copyfile_p);
return 1;
}

获取文件大小

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include <stdio.h>
void main() {
//获取文件大小
const char * srcFileName = "C:/Users/Administrator/Desktop/ee.png";

FILE* afile_p = fopen(srcFileName, "rb");

if (!afile_p) {
printf("文件打开失败!");
getchar();
return;
}


//将文件的指针移动到最后,然后再去计算偏移量
fseek(afile_p,0,SEEK_END);

long fileSize = ftell(afile_p);
printf("原文件大小:%d", fileSize);

fclose(afile_p);
getchar();

}

文件加密解密

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
#include <stdio.h>
//文件加密解密
void main() {
const char * srcFileName = "C:/Users/Administrator/Desktop/ee.png";
const char * encrpyFileName = "C:/Users/Administrator/Desktop/encrpyee.png";

FILE* afile_p = fopen(srcFileName, "rb");
FILE* encrpyfile_p = fopen(encrpyFileName, "wb");
if (!afile_p) {
printf("文件打开失败!");
getchar();
return;
}
//思路,把每一个字节都拿出来,对每一个字节都处理;把某一部分字节拿出来进行处理
// 加密 10^5 异或
// 1010
// ^0101
// 1111
int c;
while ((c = fgetc(afile_p)) != EOF) {
fputc(c^5, encrpyfile_p);
}
fclose(afile_p);
fclose(encrpyfile_p);


//解密 异或
// 1111
// ^0101
// 1010
FILE* encrpySrcFile_p = fopen(encrpyFileName, "rb");
const char * deFileName = "C:/Users/Administrator/Desktop/deee.png";
FILE* defile_p = fopen(deFileName, "wb");
while ((c = fgetc(encrpySrcFile_p)) != EOF) {
fputc(c ^ 5, defile_p);
}
fclose(encrpySrcFile_p);
fclose(defile_p);

}

文件分割

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
#include <stdio.h>
#include <Windows.h>

//类似断点下载
//文件的切割
void main() {
const char * srcFileName = "C:/Users/Administrator/Desktop/ee.png";

FILE* srcFile_p = fopen(srcFileName, "rb");
int file_number = 3;
//二维数组内存开辟
char** file_names =(char**) malloc(sizeof(char*)*file_number);

//进行数组内存开辟
int i = 0;
for ( ; i < file_number; i++) {
file_names[i] =(char*) malloc(sizeof(char)*100);
char *fileName = file_names[i];
sprintf(fileName, "C:/Users/Administrator/Desktop/image%d.png",i);
printf("%s\n", fileName);
}

int file_size = getFileSize(srcFileName);
if (file_size == -1) {
return;
}
int preFileSize = file_size / file_number;
//往切割文件中写入数据

i = 0;
for (; i < file_number; i++) {
FILE* cur_file_p = fopen(file_names[i],"wb");
int start = i * preFileSize;
int end = (i + 1)*preFileSize;
if (i == file_number-1) {
end = file_size;
}
int index = start;
printf("\ni=%d,start=%d,end=%d,name=%s", i, start, end, file_names[i]);
for (; index < end; index++) {
fputc(fgetc(srcFile_p),cur_file_p);
}
fclose(cur_file_p);
// free(file_names[i]);
}

fclose(srcFile_p);
free(file_names);
getchar();
}

Glide v3.7源码分析(3)------GenericRequestBuilder.into(时序图)

发表于 2018-04-01 | 分类于 源码分析 |
字数统计: 0字 | 阅读时长 ≈ 1分钟

image

Glide v3.7源码分析(2)-----RequestManager.load

发表于 2018-03-31 | 分类于 源码分析 |
字数统计: 3,145字 | 阅读时长 ≈ 18分钟

代码如下:

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
private <T> DrawableTypeRequest<T> loadGeneric(Class<T> modelClass) {
//1. 获取streamModelLoader
ModelLoader<T, InputStream> streamModelLoader = Glide.buildStreamModelLoader(modelClass, context);
//2. 获取fileDescriptorModelLoader
ModelLoader<T, ParcelFileDescriptor> fileDescriptorModelLoader =
Glide.buildFileDescriptorModelLoader(modelClass, context);
if (modelClass != null && streamModelLoader == null && fileDescriptorModelLoader == null) {
throw new IllegalArgumentException("Unknown type " + modelClass + ". You must provide a Model of a type for"
+ " which there is a registered ModelLoader, if you are using a custom model, you must first call"
+ " Glide#register with a ModelLoaderFactory for your custom model class");
}

//3. 获取DrawableTypeRequest
return optionsApplier.apply(
new DrawableTypeRequest<T>(modelClass, streamModelLoader, fileDescriptorModelLoader, context,
glide, requestTracker, lifecycle, optionsApplier));
}

public DrawableTypeRequest<String> load(String string) {
//4. load
return (DrawableTypeRequest<String>) fromString().load(string);
}

public DrawableTypeRequest<String> fromString() {
return loadGeneric(String.class);
}

流程图如下:
RequestManager.load

  1. buildModelLoader: 根据请求的model和需要解析的model获取到对应的ModelLoader
  • Glide.buildModelLoader()

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12

    public static <T, Y> ModelLoader<T, Y> buildModelLoader(Class<T> modelClass, Class<Y> resourceClass,
    Context context) {
    if (modelClass == null) {
    if (Log.isLoggable(TAG, Log.DEBUG)) {
    Log.d(TAG, "Unable to load null model, setting placeholder only");
    }
    return null;
    }
    //详见【1.1】 Glide.get 详见【1.2】 buildModelLoader
    return Glide.get(context).getLoaderFactory().buildModelLoader(modelClass, resourceClass);
    }
  • 1.1

    • Glide.get():module配置解析,初始化Glide对象
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
public static Glide get(Context context) {
if (glide == null) {
synchronized (Glide.class) {
if (glide == null) {
Context applicationContext = context.getApplicationContext();
//解析Manifest配置的GlideModule 详见【1.1.1】
List<GlideModule> modules = new ManifestParser(applicationContext).parse();

GlideBuilder builder = new GlideBuilder(applicationContext);
//遍历module,完成赋值
for (GlideModule module : modules) {
module.applyOptions(applicationContext, builder);
}
//初始化Glide 详见【1.1.2】
glide = builder.createGlide();
//遍历module,完成注册
for (GlideModule module : modules) {
module.registerComponents(applicationContext, glide);
}
}
}
}

return glide;
}
  • 1.1.1

    • ManifestParser.parser():解析AndroidManifest.xml配置的module
      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
      public List<GlideModule> parse() {
      List<GlideModule> modules = new ArrayList<GlideModule>();
      try {
      ApplicationInfo appInfo = context.getPackageManager().getApplicationInfo(
      context.getPackageName(), PackageManager.GET_META_DATA);
      if (appInfo.metaData != null) {
      for (String key : appInfo.metaData.keySet()) {
      if (GLIDE_MODULE_VALUE.equals(appInfo.metaData.get(key))) {
      modules.add(parseModule(key));
      }
      }
      }
      } catch (PackageManager.NameNotFoundException e) {
      throw new RuntimeException("Unable to find metadata to parse GlideModules", e);
      }

      return modules;
      }

      private static GlideModule parseModule(String className) {
      Class<?> clazz;
      try {
      clazz = Class.forName(className);
      } catch (ClassNotFoundException e) {
      throw new IllegalArgumentException("Unable to find GlideModule implementation", e);
      }

      Object module;
      try {
      //初始化module
      module = clazz.newInstance();
      } catch (InstantiationException e) {
      throw new RuntimeException("Unable to instantiate GlideModule implementation for " + clazz, e);
      } catch (IllegalAccessException e) {
      throw new RuntimeException("Unable to instantiate GlideModule implementation for " + clazz, e);
      }

      if (!(module instanceof GlideModule)) {
      throw new RuntimeException("Expected instanceof GlideModule, but found: " + module);
      }
      return (GlideModule) module;
      }
  • 1.1.2

    • GlideBuilder.createGlide():Glide初始化
      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
      Glide createGlide() {
      if (sourceService == null) {
      //根据cpu获取核心加载数量
      final int cores = Math.max(1, Runtime.getRuntime().availableProcessors());
      //具有优先级顺序的线程池
      sourceService = new FifoPriorityThreadPoolExecutor(cores);
      }
      if (diskCacheService == null) {
      diskCacheService = new FifoPriorityThreadPoolExecutor(1);
      }
      //缓存计算类
      MemorySizeCalculator calculator = new MemorySizeCalculator(context);
      if (bitmapPool == null) {
      if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
      int size = calculator.getBitmapPoolSize();
      //位图池
      bitmapPool = new LruBitmapPool(size);
      } else {
      bitmapPool = new BitmapPoolAdapter();
      }
      }

      //内存缓存
      if (memoryCache == null) {
      memoryCache = new LruResourceCache(calculator.getMemoryCacheSize());
      }

      //磁盘缓存
      if (diskCacheFactory == null) {
      diskCacheFactory = new InternalCacheDiskCacheFactory(context);
      }

      //负责启动request load和管理内存的引擎类
      if (engine == null) {
      engine = new Engine(memoryCache, diskCacheFactory, diskCacheService, sourceService);
      }

      if (decodeFormat == null) {
      //编码格式 默认PREFER_RGB_565
      decodeFormat = DecodeFormat.DEFAULT;
      }

      return new Glide(engine, memoryCache, bitmapPool, context, decodeFormat);
      }

      Glide(Engine engine, MemoryCache memoryCache, BitmapPool bitmapPool, Context context, DecodeFormat decodeFormat) {
      this.engine = engine;
      this.bitmapPool = bitmapPool;
      this.memoryCache = memoryCache;
      this.decodeFormat = decodeFormat;
      //ModelLoader生成工厂类
      loaderFactory = new GenericLoaderFactory(context);
      mainHandler = new Handler(Looper.getMainLooper());

      bitmapPreFiller = new BitmapPreFiller(memoryCache, bitmapPool, decodeFormat);


      //DataLoadProviderRegistry 注册
      dataLoadProviderRegistry = new DataLoadProviderRegistry();

      StreamBitmapDataLoadProvider streamBitmapLoadProvider =
      new StreamBitmapDataLoadProvider(bitmapPool, decodeFormat);
      dataLoadProviderRegistry.register(InputStream.class, Bitmap.class, streamBitmapLoadProvider);

      FileDescriptorBitmapDataLoadProvider fileDescriptorLoadProvider =
      new FileDescriptorBitmapDataLoadProvider(bitmapPool, decodeFormat);
      dataLoadProviderRegistry.register(ParcelFileDescriptor.class, Bitmap.class, fileDescriptorLoadProvider);

      ImageVideoDataLoadProvider imageVideoDataLoadProvider =
      new ImageVideoDataLoadProvider(streamBitmapLoadProvider, fileDescriptorLoadProvider);
      dataLoadProviderRegistry.register(ImageVideoWrapper.class, Bitmap.class, imageVideoDataLoadProvider);

      GifDrawableLoadProvider gifDrawableLoadProvider =
      new GifDrawableLoadProvider(context, bitmapPool);
      dataLoadProviderRegistry.register(InputStream.class, GifDrawable.class, gifDrawableLoadProvider);

      dataLoadProviderRegistry.register(ImageVideoWrapper.class, GifBitmapWrapper.class,
      new ImageVideoGifDrawableLoadProvider(imageVideoDataLoadProvider, gifDrawableLoadProvider, bitmapPool));

      dataLoadProviderRegistry.register(InputStream.class, File.class, new StreamFileDataLoadProvider());

      //GenericLoaderFactory注册
      register(File.class, ParcelFileDescriptor.class, new FileDescriptorFileLoader.Factory());
      register(File.class, InputStream.class, new StreamFileLoader.Factory());
      register(int.class, ParcelFileDescriptor.class, new FileDescriptorResourceLoader.Factory());
      register(int.class, InputStream.class, new StreamResourceLoader.Factory());
      register(Integer.class, ParcelFileDescriptor.class, new FileDescriptorResourceLoader.Factory());
      register(Integer.class, InputStream.class, new StreamResourceLoader.Factory());
      register(String.class, ParcelFileDescriptor.class, new FileDescriptorStringLoader.Factory());
      register(String.class, InputStream.class, new StreamStringLoader.Factory());
      register(Uri.class, ParcelFileDescriptor.class, new FileDescriptorUriLoader.Factory());
      register(Uri.class, InputStream.class, new StreamUriLoader.Factory());
      register(URL.class, InputStream.class, new StreamUrlLoader.Factory());
      register(GlideUrl.class, InputStream.class, new HttpUrlGlideUrlLoader.Factory());
      register(byte[].class, InputStream.class, new StreamByteArrayLoader.Factory());

      //TranscoderRegistry 注册
      transcoderRegistry.register(Bitmap.class, GlideBitmapDrawable.class,
      new GlideBitmapDrawableTranscoder(context.getResources(), bitmapPool));
      transcoderRegistry.register(GifBitmapWrapper.class, GlideDrawable.class,
      new GifBitmapWrapperDrawableTranscoder(
      new GlideBitmapDrawableTranscoder(context.getResources(), bitmapPool)));

      bitmapCenterCrop = new CenterCrop(bitmapPool);
      drawableCenterCrop = new GifBitmapWrapperTransformation(bitmapPool, bitmapCenterCrop);

      bitmapFitCenter = new FitCenter(bitmapPool);
      drawableFitCenter = new GifBitmapWrapperTransformation(bitmapPool, bitmapFitCenter);
      }

      //根据modelClass,resourceClass,ModelLoaderFactory注册到GenericLoaderFactory
      public <T, Y> void register(Class<T> modelClass, Class<Y> resourceClass, ModelLoaderFactory<T, Y> factory) {
      //详见【1.1.3】
      ModelLoaderFactory<T, Y> removed = loaderFactory.register(modelClass, resourceClass, factory);
      if (removed != null) {
      removed.teardown();
      }
      }

可以看到,Glide初始化的时候做了很多的事,初始化了缓存相关的类,任务执行以及缓存管理的引擎,注册了DataLoadProviderRegistry GenericLoaderFactory等等这些。这个时候我们知道了Glide.buildModelLoader()函数里面Glide.get(context).getLoaderFactory()对象为GenericLoaderFactory

  • 1.1.3

    • GenericLoaderFactory.register()
      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
      public synchronized <T, Y> ModelLoaderFactory<T, Y> register(Class<T> modelClass, Class<Y> resourceClass,
      ModelLoaderFactory<T, Y> factory) {
      cachedModelLoaders.clear();

      //modelClassToResourceFactories key为modelClass,值为已resourceClass为key,factory为值得HashMap

      //根据modelClass获取resourceToFactories
      Map<Class/*Y*/, ModelLoaderFactory/*T, Y*/> resourceToFactories = modelClassToResourceFactories.get(modelClass);
      if (resourceToFactories == null) {
      resourceToFactories = new HashMap<Class/*Y*/, ModelLoaderFactory/*T, Y*/>();
      modelClassToResourceFactories.put(modelClass, resourceToFactories);
      }

      ModelLoaderFactory/*T, Y*/ previous = resourceToFactories.put(resourceClass, factory);

      if (previous != null) {
      // This factory may be being used by another model. We don't want to say it has been removed unless we
      // know it has been removed for all models.
      for (Map<Class/*Y*/, ModelLoaderFactory/*T, Y*/> factories : modelClassToResourceFactories.values()) {
      if (factories.containsValue(previous)) {
      previous = null;
      break;
      }
      }
      }

      return previous;
      }
  • 1.2

    • GenericLoaderFactory.buildModelLoader()
      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
      public synchronized <T, Y> ModelLoader<T, Y> buildModelLoader(Class<T> modelClass, Class<Y> resourceClass) {
      //获取缓存的ModelLoader
      ModelLoader<T, Y> result = getCachedLoader(modelClass, resourceClass);
      if (result != null) {
      // We've already tried to create a model loader and can't with the currently registered set of factories,
      // but we can't use null to demonstrate that failure because model loaders that haven't been requested
      // yet will be null in the cache. To avoid this, we use a special signal model loader.
      if (NULL_MODEL_LOADER.equals(result)) {
      return null;
      } else {
      return result;
      }
      }
      //根据 modelClass 和 resourceClass获取对应的ModelLoaderFactory
      final ModelLoaderFactory<T, Y> factory = getFactory(modelClass, resourceClass);
      if (factory != null) {
      //根据ModelLoaderFactory获取到ModelLoader,并将存到缓存,详见【1.2.1】
      result = factory.build(context, this);
      cacheModelLoader(modelClass, resourceClass, result);
      } else {
      // We can't generate a model loader for the given arguments with the currently registered set of factories.
      cacheNullLoader(modelClass, resourceClass);
      }
      return result;
      }


      private <T, Y> ModelLoaderFactory<T, Y> getFactory(Class<T> modelClass, Class<Y> resourceClass) {
      // 在【1.1.2】Glide初始化的时候modelClassToResourceFactories注册对应关系
      Map<Class/*Y*/, ModelLoaderFactory/*T, Y*/> resourceToFactories = modelClassToResourceFactories.get(modelClass);
      ModelLoaderFactory/*T, Y*/ result = null;
      if (resourceToFactories != null) {
      result = resourceToFactories.get(resourceClass);
      }

      if (result == null) {
      for (Class<? super T> registeredModelClass : modelClassToResourceFactories.keySet()) {
      // This accounts for model subclasses, our map only works for exact matches. We should however still
      // match a subclass of a model with a factory for a super class of that model if if there isn't a
      // factory for that particular subclass. Uris are a great example of when this happens, most uris
      // are actually subclasses for Uri, but we'd generally rather load them all with the same factory rather
      // than trying to register for each subclass individually.
      if (registeredModelClass.isAssignableFrom(modelClass)) {
      Map<Class/*Y*/, ModelLoaderFactory/*T, Y*/> currentResourceToFactories =
      modelClassToResourceFactories.get(registeredModelClass);
      if (currentResourceToFactories != null) {
      result = currentResourceToFactories.get(resourceClass);
      if (result != null) {
      break;
      }
      }
      }
      }
      }

      return result;
      }
  • 1.2.1

    • factory.build():根据ModelLoaderFactory获取到ModelLoader,这里用module.class=String.class来举例, 【1.1.2】Glide初始化的时候可知道register(String.class, InputStream.class, new StreamStringLoader.Factory());
    • StreamStringLoader.Factory.build()
      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
      public class StreamStringLoader extends StringLoader<InputStream> implements StreamModelLoader<String> {

      /**
      * The default factory for {@link com.bumptech.glide.load.model.stream.StreamStringLoader}s.
      */
      public static class Factory implements ModelLoaderFactory<String, InputStream> {
      @Override
      public ModelLoader<String, InputStream> build(Context context, GenericLoaderFactory factories) {
      //这里通过`factories.buildModelLoader`来构建一个`module.class=Uri.class`类型的`ModuleLoader`,从【1.1.2】里面可以看到`register(Uri.class, InputStream.class, new StreamUriLoader.Factory());`。`factories.buildModelLoader`详见【1.2】
      return new StreamStringLoader(factories.buildModelLoader(Uri.class, InputStream.class));
      }

      @Override
      public void teardown() {
      // Do nothing.
      }
      }

      public StreamStringLoader(Context context) {
      this(Glide.buildStreamModelLoader(Uri.class, context));
      }

      public StreamStringLoader(ModelLoader<Uri, InputStream> uriLoader) {
      super(uriLoader);
      }
      }


      public class StreamUriLoader extends UriLoader<InputStream> implements StreamModelLoader<Uri> {

      /**
      * THe default factory for {@link com.bumptech.glide.load.model.stream.StreamUriLoader}s.
      */
      public static class Factory implements ModelLoaderFactory<Uri, InputStream> {

      @Override
      public ModelLoader<Uri, InputStream> build(Context context, GenericLoaderFactory factories) {
      //【1.1.2】 register(GlideUrl.class, InputStream.class, new HttpUrlGlideUrlLoader.Factory());
      return new StreamUriLoader(context, factories.buildModelLoader(GlideUrl.class, InputStream.class));
      }

      @Override
      public void teardown() {
      // Do nothing.
      }
      }

      public StreamUriLoader(Context context) {
      this(context, Glide.buildStreamModelLoader(GlideUrl.class, context));
      }

      public StreamUriLoader(Context context, ModelLoader<GlideUrl, InputStream> urlLoader) {
      super(context, urlLoader);
      }

      //...
      }


      public class HttpUrlGlideUrlLoader implements ModelLoader<GlideUrl, InputStream> {

      private final ModelCache<GlideUrl, GlideUrl> modelCache;

      /**
      * The default factory for {@link com.bumptech.glide.load.model.stream.HttpUrlGlideUrlLoader}s.
      */
      public static class Factory implements ModelLoaderFactory<GlideUrl, InputStream> {
      private final ModelCache<GlideUrl, GlideUrl> modelCache = new ModelCache<GlideUrl, GlideUrl>(500);

      @Override
      public ModelLoader<GlideUrl, InputStream> build(Context context, GenericLoaderFactory factories) {
      return new HttpUrlGlideUrlLoader(modelCache);
      }

      @Override
      public void teardown() {
      // Do nothing.
      }
      }

      public HttpUrlGlideUrlLoader() {
      this(null);
      }

      public HttpUrlGlideUrlLoader(ModelCache<GlideUrl, GlideUrl> modelCache) {
      this.modelCache = modelCache;
      }

      @Override
      public DataFetcher<InputStream> getResourceFetcher(GlideUrl model, int width, int height) {
      // GlideUrls memoize parsed URLs so caching them saves a few object instantiations and time spent parsing urls.
      GlideUrl url = model;
      if (modelCache != null) {
      url = modelCache.get(model, 0, 0);
      if (url == null) {
      modelCache.put(model, 0, 0, model);
      url = model;
      }
      }
      return new HttpUrlFetcher(url);
      }
      }

StreamStringLoader继承StringLoader,StringLoader里面有一个ModelLoader uriLoader成员变量,当build的时候,这里通过factories.buildModelLoader来构建一个module.class=Uri.class类型的ModuleLoader,从【1.1.2】里面可以看到register(Uri.class, InputStream.class, new StreamUriLoader.Factory());`StreamUriLoader继承UriLoader,它有一个ModelLoader urlLoader成员变量,这个时候也通过factories.buildModelLoader以module.class = GlideUrl.class的方式获取,【1.1.2】register(GlideUrl.class, InputStream.class, new HttpUrlGlideUrlLoader.Factory());`,这里一层一层的获取很是巧妙。

  1. Glide.buildFileDescriptorModelLoader:获取fileDescriptorModelLoader
    1
    2
    3
    4
    5
    public static <T> ModelLoader<T, ParcelFileDescriptor> buildFileDescriptorModelLoader(Class<T> modelClass,
    Context context) {
    //详见【1】
    return buildModelLoader(modelClass, ParcelFileDescriptor.class, context);
    }

这一步和【1】差不多的流程,已module.class = String.class为例子,register(String.class, ParcelFileDescriptor.class, new FileDescriptorStringLoader.Factory());于【1.2.1】类似,也是一层一层的获取,这就不废话了。

  1. 获取DrawableTypeRequest: DrawableTypeRequest继承DrawableRequestBuilder,DrawableRequestBuilder继承GenericRequestBuilder
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    private final OptionsApplier optionsApplier;
    this.optionsApplier = new OptionsApplier();

    //【3.1】 new DrawableTypeRequest
    optionsApplier.apply(
    new DrawableTypeRequest<T>(modelClass, streamModelLoader, fileDescriptorModelLoader, context,
    glide, requestTracker, lifecycle, optionsApplier))

    class OptionsApplier {
    public <A, X extends GenericRequestBuilder<A, ?, ?, ?>> X apply(X builder) {
    //HOOK
    if (options != null) {
    options.apply(builder);
    }
    return builder;
    }
    }

这里获取Request对象的时候,留了一个hook。

  • 3.1

    • new DrawableTypeRequest
      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
      DrawableTypeRequest(Class<ModelType> modelClass, ModelLoader<ModelType, InputStream> streamModelLoader,
      ModelLoader<ModelType, ParcelFileDescriptor> fileDescriptorModelLoader, Context context, Glide glide,
      RequestTracker requestTracker, Lifecycle lifecycle, RequestManager.OptionsApplier optionsApplier) {
      //【3.2】 buildProvider
      super(context, modelClass,
      buildProvider(glide, streamModelLoader, fileDescriptorModelLoader, GifBitmapWrapper.class,
      GlideDrawable.class, null),
      glide, requestTracker, lifecycle);
      this.streamModelLoader = streamModelLoader;
      this.fileDescriptorModelLoader = fileDescriptorModelLoader;
      this.optionsApplier = optionsApplier;
      }


      DrawableRequestBuilder(Context context, Class<ModelType> modelClass,
      LoadProvider<ModelType, ImageVideoWrapper, GifBitmapWrapper, GlideDrawable> loadProvider, Glide glide,
      RequestTracker requestTracker, Lifecycle lifecycle) {
      super(context, modelClass, loadProvider, GlideDrawable.class, glide, requestTracker, lifecycle);
      // Default to animating.
      crossFade();
      }


      GenericRequestBuilder(Context context, Class<ModelType> modelClass,
      LoadProvider<ModelType, DataType, ResourceType, TranscodeType> loadProvider,
      Class<TranscodeType> transcodeClass, Glide glide, RequestTracker requestTracker, Lifecycle lifecycle) {
      this.context = context;
      this.modelClass = modelClass;
      this.transcodeClass = transcodeClass;
      this.glide = glide;
      this.requestTracker = requestTracker;
      this.lifecycle = lifecycle;
      this.loadProvider = loadProvider != null
      ? new ChildLoadProvider<ModelType, DataType, ResourceType, TranscodeType>(loadProvider) : null;

      if (context == null) {
      throw new NullPointerException("Context can't be null");
      }
      if (modelClass != null && loadProvider == null) {
      throw new NullPointerException("LoadProvider must not be null");
      }
      }
  • 3.2

    • buildProvider
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      private static <A, Z, R> FixedLoadProvider<A, ImageVideoWrapper, Z, R> buildProvider(Glide glide,
      ModelLoader<A, InputStream> streamModelLoader,
      ModelLoader<A, ParcelFileDescriptor> fileDescriptorModelLoader, Class<Z> resourceClass,
      Class<R> transcodedClass,
      ResourceTranscoder<Z, R> transcoder) {
      if (streamModelLoader == null && fileDescriptorModelLoader == null) {
      return null;
      }

      if (transcoder == null) {
      //获取ResourceTranscoder详见【3.2.1】 --> GifBitmapWrapperDrawableTranscoder
      transcoder = glide.buildTranscoder(resourceClass, transcodedClass);
      }
      //详见【3.2.2】
      DataLoadProvider<ImageVideoWrapper, Z> dataLoadProvider = glide.buildDataProvider(ImageVideoWrapper.class,
      resourceClass);
      ImageVideoModelLoader<A> modelLoader = new ImageVideoModelLoader<A>(streamModelLoader,
      fileDescriptorModelLoader);
      return new FixedLoadProvider<A, ImageVideoWrapper, Z, R>(modelLoader, transcoder, dataLoadProvider);
      }

这里resourceClass = GifBitmapWrapper.class,transcodedClass = GlideDrawable.class

  • 3.2.1
    • glide.buildTranscoder
      1
      2
      3
      <Z, R> ResourceTranscoder<Z, R> buildTranscoder(Class<Z> decodedClass, Class<R> transcodedClass) {
      return transcoderRegistry.get(decodedClass, transcodedClass);
      }

从【1.1.2】

1
2
3
transcoderRegistry.register(GifBitmapWrapper.class, GlideDrawable.class,
new GifBitmapWrapperDrawableTranscoder(
new GlideBitmapDrawableTranscoder(context.getResources(), bitmapPool)));

获取的transcoder为GifBitmapWrapperDrawableTranscoder

  • 3.2.2
    • glide.buildDataProvider
      1
      2
      3
      <T, Z> DataLoadProvider<T, Z> buildDataProvider(Class<T> dataClass, Class<Z> decodedClass) {
      return dataLoadProviderRegistry.get(dataClass, decodedClass);
      }

这里dataClass = ImageVideoWrapper.class,decodedClass = resourceClass = GifBitmapWrapper.class
从【1.1.2】

1
2
dataLoadProviderRegistry.register(ImageVideoWrapper.class, GifBitmapWrapper.class,
new ImageVideoGifDrawableLoadProvider(imageVideoDataLoadProvider, gifDrawableLoadProvider, bitmapPool));

获取的DataLoadProvider为ImageVideoGifDrawableLoadProvider

  1. DrawableTypeRequest.load
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13

    @Override
    public DrawableRequestBuilder<ModelType> load(ModelType model) {
    super.load(model);
    return this;
    }


    public GenericRequestBuilder<ModelType, DataType, ResourceType, TranscodeType> load(ModelType model) {
    this.model = model;
    isModelSet = true;
    return this;
    }

最后的load就是设置一些moduleType。

总结:

  1. Glide.with获取到RequestManager对象,然后我们通过RequestManager.load根据modelType获取到GenericRequestBuilder对象。
  2. Glide根据modelType生成Request采用了工厂,并且初始化ModuleLoader的时候,里面又包含着另外一个ModuleLoader引用,很是巧妙。具体查看【1.2】
  3. 一个modelType(modelClass)对应多个resourceType(resourceClass),一个resourceType对应一个transcodedType(transcodedClass)
  4. modelType可以理解为请求的类型,String Uri File等;resourceType可以理解为请求的结果形式,比如Stream File等;transcodedType可以理解为图片的转换类型Drawable Bitmap等。

Glide v3.7源码分析(1)-----Glide.with()

发表于 2018-03-30 | 分类于 源码分析 |
字数统计: 520字 | 阅读时长 ≈ 3分钟

Glide.with()

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
public static RequestManager with(FragmentActivity activity) {
//单例拿到一个RequestManagerRetriever
RequestManagerRetriever retriever = RequestManagerRetriever.get();
return retriever.get(activity);
}



public RequestManager get(FragmentActivity activity) {
if (Util.isOnBackgroundThread()) {
return get(activity.getApplicationContext());
} else {
assertNotDestroyed(activity);
FragmentManager fm = activity.getSupportFragmentManager();
return supportFragmentGet(activity, fm);
}
}


RequestManager supportFragmentGet(Context context, FragmentManager fm) {
//根据TAG拿到SupportRequestManagerFragment 防止第二次重复创建
SupportRequestManagerFragment current = getSupportRequestManagerFragment(fm);
//拿到RequestManager
RequestManager requestManager = current.getRequestManager();
if (requestManager == null) {
requestManager = new RequestManager(context, current.getLifecycle(), current.getRequestManagerTreeNode());
current.setRequestManager(requestManager);
}
return requestManager;
}


SupportRequestManagerFragment getSupportRequestManagerFragment(final FragmentManager fm) {
SupportRequestManagerFragment current = (SupportRequestManagerFragment) fm.findFragmentByTag(FRAGMENT_TAG);
if (current == null) {
current = pendingSupportRequestManagerFragments.get(fm);
if (current == null) {
current = new SupportRequestManagerFragment();
pendingSupportRequestManagerFragments.put(fm, current);
fm.beginTransaction().add(current, FRAGMENT_TAG).commitAllowingStateLoss();
handler.obtainMessage(ID_REMOVE_SUPPORT_FRAGMENT_MANAGER, fm).sendToTarget();
}
}
return current;
}


public class RequestManager implements LifecycleListener {
private final Context context;
private final Lifecycle lifecycle;
private final RequestManagerTreeNode treeNode;
private final RequestTracker requestTracker;
private final Glide glide;
private final OptionsApplier optionsApplier;
private DefaultOptions options;

//RequestManager初始化
public RequestManager(Context context, Lifecycle lifecycle, RequestManagerTreeNode treeNode) {
this(context, lifecycle, treeNode, new RequestTracker(), new ConnectivityMonitorFactory());
}

RequestManager(Context context, final Lifecycle lifecycle, RequestManagerTreeNode treeNode,
RequestTracker requestTracker, ConnectivityMonitorFactory factory) {
this.context = context.getApplicationContext();
this.lifecycle = lifecycle;
this.treeNode = treeNode;
this.requestTracker = requestTracker;
this.glide = Glide.get(context);
this.optionsApplier = new OptionsApplier();

ConnectivityMonitor connectivityMonitor = factory.build(context,
new RequestManagerConnectivityListener(requestTracker));

// If we're the application level request manager, we may be created on a background thread. In that case we
// cannot risk synchronously pausing or resuming requests, so we hack around the issue by delaying adding
// ourselves as a lifecycle listener by posting to the main thread. This should be entirely safe.
if (Util.isOnBackgroundThread()) {
new Handler(Looper.getMainLooper()).post(new Runnable() {
@Override
public void run() {
lifecycle.addListener(RequestManager.this);
}
});
} else {
lifecycle.addListener(this);
}
lifecycle.addListener(connectivityMonitor);
}
//...
}

Glide.with()

总结:

  1. 创建一个Fragment绑定到Activity上面,Fragment调用setRequestManager()进行RequestManager赋值。
  2. Fragment的作用是用于生命周期管理,当我们new Fragment的时候我们一同会new一个ActivityFragmentLifecycle
  3. 当Frament onLowMemory的时候RequestManager会回调onLowMemory回调。
  4. ActivityFragmentLifecycle是使用观察者模式来管理LifecycleListener,当fragment触发生命周期的时候(onStart onStop onDestroy),ActivityFragmentLifecycle将会进行遍历回调。 RequestManager是一个LifecycleListener,当初始化的时候,RequestManager将会被注册到Fragent里面的ActivityFragmentLifecycle进行生命管理。

OpenCv as配置

发表于 2018-03-30 | 分类于 cmake |
字数统计: 751字 | 阅读时长 ≈ 4分钟
  1. 使用opencv4android的java库,这里说下怎么把OpencvManager去除,把
    copy到opencv的javalib里面当so运行就可,调用initDebug初始化即可
    ,目录结构如下:
  1. 根据需要导入对应的动态库以及头文件自己编译so库,主要配置如下
    build.gradle
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
android {
defaultConfig {
externalNativeBuild {
cmake {
arguments "-DANDROID_TOOLCHAIN=clang"
cppFlags "-std=c++11","-frtti", "-fexceptions"
}
}
ndk{
abiFilters 'armeabi-v7a'
}
}
externalNativeBuild {
cmake {
path "CMakeLists.txt"
}
}

}

CMakeLists.txt 注意target_link_libraries顺序。这里libopencv_java3其实已经包括了其他的了,我的理解是用了java3这个后面的动态库就可以不用添加了,我只是把可能用到的全部写了出来,以后好copy。

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
# For more information about using CMake with Android Studio, read the
# documentation: https://d.android.com/studio/projects/add-native-code.html

# Sets the minimum version of CMake required to build the native library.

cmake_minimum_required(VERSION 3.4.1)

set(CMAKE_VERBOSE_MAKEFILE on)
set(libs "${CMAKE_SOURCE_DIR}/src/main/jniLibs")
include_directories(${CMAKE_SOURCE_DIR}/src/main/cpp/include)

add_library(libopencv_java3 SHARED IMPORTED )
set_target_properties(libopencv_java3 PROPERTIES
IMPORTED_LOCATION "${libs}/${ANDROID_ABI}/libopencv_java3.so")

add_library(libopencv_calib3d STATIC IMPORTED )
set_target_properties(libopencv_calib3d PROPERTIES
IMPORTED_LOCATION "${libs}/${ANDROID_ABI}/libopencv_calib3d.a")

add_library(libopencv_core STATIC IMPORTED )
set_target_properties(libopencv_core PROPERTIES
IMPORTED_LOCATION "${libs}/${ANDROID_ABI}/libopencv_core.a")

add_library(libopencv_features2d STATIC IMPORTED )
set_target_properties(libopencv_features2d PROPERTIES
IMPORTED_LOCATION "${libs}/${ANDROID_ABI}/libopencv_features2d.a")

add_library(libopencv_flann STATIC IMPORTED )
set_target_properties(libopencv_flann PROPERTIES
IMPORTED_LOCATION "${libs}/${ANDROID_ABI}/libopencv_flann.a")

add_library(libopencv_highgui STATIC IMPORTED )
set_target_properties(libopencv_highgui PROPERTIES
IMPORTED_LOCATION "${libs}/${ANDROID_ABI}/libopencv_highgui.a")

add_library(libopencv_imgcodecs STATIC IMPORTED )
set_target_properties(libopencv_imgcodecs PROPERTIES
IMPORTED_LOCATION "${libs}/${ANDROID_ABI}/libopencv_imgcodecs.a")

add_library(libopencv_imgproc STATIC IMPORTED )
set_target_properties(libopencv_imgproc PROPERTIES
IMPORTED_LOCATION "${libs}/${ANDROID_ABI}/libopencv_imgproc.a")

add_library(libopencv_ml STATIC IMPORTED )
set_target_properties(libopencv_ml PROPERTIES
IMPORTED_LOCATION "${libs}/${ANDROID_ABI}/libopencv_ml.a")

add_library(libopencv_objdetect STATIC IMPORTED )
set_target_properties(libopencv_objdetect PROPERTIES
IMPORTED_LOCATION "${libs}/${ANDROID_ABI}/libopencv_objdetect.a")

add_library(libopencv_photo STATIC IMPORTED )
set_target_properties(libopencv_photo PROPERTIES
IMPORTED_LOCATION "${libs}/${ANDROID_ABI}/libopencv_photo.a")

add_library(libopencv_shape STATIC IMPORTED )
set_target_properties(libopencv_shape PROPERTIES
IMPORTED_LOCATION "${libs}/${ANDROID_ABI}/libopencv_shape.a")

add_library(libopencv_stitching STATIC IMPORTED )
set_target_properties(libopencv_stitching PROPERTIES
IMPORTED_LOCATION "${libs}/${ANDROID_ABI}/libopencv_stitching.a")

add_library(libopencv_superres STATIC IMPORTED )
set_target_properties(libopencv_superres PROPERTIES
IMPORTED_LOCATION "${libs}/${ANDROID_ABI}/libopencv_superres.a")

add_library(libopencv_video STATIC IMPORTED )
set_target_properties(libopencv_video PROPERTIES
IMPORTED_LOCATION "${libs}/${ANDROID_ABI}/libopencv_video.a")

add_library(libopencv_videoio STATIC IMPORTED )
set_target_properties(libopencv_videoio PROPERTIES
IMPORTED_LOCATION "${libs}/${ANDROID_ABI}/libopencv_videoio.a")

add_library(libopencv_videostab STATIC IMPORTED )
set_target_properties(libopencv_videostab PROPERTIES
IMPORTED_LOCATION "${libs}/${ANDROID_ABI}/libopencv_videostab.a")

add_library(libopencv_ts STATIC IMPORTED )
set_target_properties(libopencv_ts PROPERTIES
IMPORTED_LOCATION "${libs}/${ANDROID_ABI}/libopencv_ts.a")

#set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++11 -fexceptions -frtti")
#支持-std=gnu++11
set(CMAKE_VERBOSE_MAKEFILE on)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++11 -Wall -DGLM_FORCE_SIZE_T_LENGTH")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DGLM_FORCE_RADIANS")

#include_directories(D:/Projects/Android/CLMAndroid/OpenCV-android-sdk/sdk/native/jni/include )
#set(OpenCV_DIR D:/Projects/Android/CLMAndroid/OpenCV-android-sdk/sdk/native/jni)
#find_package(OpenCV REQUIRED)
#target_link_libraries(${OpenCV_LIBS})

add_library( # Sets the name of the library.
native-lib

# Sets the library as a shared library.
SHARED

# Provides a relative path to your source file(s).
# Associated headers in the same location as their source
# file are automatically included.
src/main/cpp/native-lib.cpp )

find_library( # Sets the name of the path variable.
log-lib

# Specifies the name of the NDK library that
# you want CMake to locate.
log)

target_link_libraries(native-lib log
libopencv_java3 libopencv_calib3d libopencv_core libopencv_features2d libopencv_flann libopencv_highgui libopencv_imgcodecs
libopencv_imgproc libopencv_ml libopencv_objdetect libopencv_photo libopencv_shape libopencv_stitching libopencv_superres
libopencv_video libopencv_videoio libopencv_videostab
${log-lib}
)

目录结构:

目录结构

  1. 通过opencv 的源码,重新编译成 Android sdk 库,很复杂,好处就是可以实时的弄到新功能。

zygote篇

发表于 2018-03-29 | 分类于 源码分析 |
字数统计: 599字 | 阅读时长 ≈ 3分钟
  1. Zygote是由init进程通过解析init.zygote.rc文件创建
  2. 调用流程

  1. 初始化系统app
    初始化系统app

初始化应用app
初始化应用app

总结:

  1. 系统应用初始化的时候,先开启系统服务SystemServer,执行SystemServer.main。
  2. 在runSelectLoop开启Os.poll堵塞处理轮训,接收到事件,运行runOnce函数执行应用的初始化。在执行对应的ActivityMain.main。
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

public static void main(String argv[]) {
try {
RuntimeInit.enableDdms(); //开启DDMS功能
SamplingProfilerIntegration.start();
boolean startSystemServer = false;
String socketName = "zygote";
String abiList = null;
for (int i = 1; i < argv.length; i++) {
if ("start-system-server".equals(argv[i])) {
startSystemServer = true;
} else if (argv[i].startsWith(ABI_LIST_ARG)) {
abiList = argv[i].substring(ABI_LIST_ARG.length());
} else if (argv[i].startsWith(SOCKET_NAME_ARG)) {
socketName = argv[i].substring(SOCKET_NAME_ARG.length());
} else {
throw new RuntimeException("Unknown command line argument: " + argv[i]);
}
}
...

registerZygoteSocket(socketName); //为Zygote注册socket
preload(); // 预加载类和资源
SamplingProfilerIntegration.writeZygoteSnapshot();
gcAndFinalize(); //GC操作
if (startSystemServer) {
startSystemServer(abiList, socketName);//启动system_server
}
runSelectLoop(abiList); //进入循环模式
closeServerSocket();
} catch (MethodAndArgsCaller caller) {
caller.run(); //启动system_server中会讲到。
} catch (RuntimeException ex) {
closeServerSocket();
throw ex;
}
}

private static void runSelectLoop(String abiList) throws MethodAndArgsCaller {
ArrayList<FileDescriptor> fds = new ArrayList<FileDescriptor>();
ArrayList<ZygoteConnection> peers = new ArrayList<ZygoteConnection>();
//sServerSocket是socket通信中的服务端,即zygote进程。保存到fds[0]
fds.add(sServerSocket.getFileDescriptor());
peers.add(null);

while (true) {
StructPollfd[] pollFds = new StructPollfd[fds.size()];
for (int i = 0; i < pollFds.length; ++i) {
pollFds[i] = new StructPollfd();
pollFds[i].fd = fds.get(i);
pollFds[i].events = (short) POLLIN;
}
try {
//处理轮询状态,当pollFds有事件到来则往下执行,否则阻塞在这里
Os.poll(pollFds, -1);
} catch (ErrnoException ex) {
...
}

for (int i = pollFds.length - 1; i >= 0; --i) {
//采用I/O多路复用机制,当接收到客户端发出连接请求 或者数据处理请求到来,则往下执行;
// 否则进入continue,跳出本次循环。
if ((pollFds[i].revents & POLLIN) == 0) {
continue;
}
if (i == 0) {
//即fds[0],代表的是sServerSocket,则意味着有客户端连接请求;
// 则创建ZygoteConnection对象,并添加到fds。
ZygoteConnection newPeer = acceptCommandPeer(abiList);
peers.add(newPeer);
fds.add(newPeer.getFileDesciptor()); //添加到fds.
} else {
//i>0,则代表通过socket接收来自对端的数据,并执行相应操作
boolean done = peers.get(i).runOnce();
if (done) {
peers.remove(i);
fds.remove(i); //处理完则从fds中移除该文件描述符
}
}
}
}
}

参考连接:http://gityuan.com/2016/02/13/android-zygote/

startActivity时序图

发表于 2018-03-28 | 分类于 源码分析 |
字数统计: 219字 | 阅读时长 ≈ 1分钟

startActivity时序图

lauchModle 检测: ActivityStarter.startActivityUnchecked()

绕过AndroidManifest检测:

  1. 瞒天过海:使用代理Activity替换原来的Activity
    拿到ActivityManagerNative里面的IActivityManager对象动态代理拦截startActivity函数,获取原来的srcIntent,重新new一个代理Activity的newIntent,newIntent.putExtra(EXTRA_ORIGIN_INTENT,originIntent),然后用newIntent替换原来的srcIntent
  2. 借尸还魂: 在Activity实例化之前(laucherActivity的时候),判断intent里面有没有EXTRA_ORIGIN_INTENT字段,如果有的话取出来替换即可
    拿到ActivityThread对象里面的Handler对象mH,然后拿到new一个Handler的callback,然后适进去,在这个callback里面处理自己的回归需求。(设置callback的原因是因为我们只处理lauchActivy,不影响其他的操作)。
    这里注意AppCompatActivity需要兼容,先拿到ActivityThread里面的IPackageManager,然后动态代理拦截getActivityInfo()函数的ComponentName替换为代理Activity的ComponentName

startActivity解析

插件化绕过AndroidManifest检测

Zygote孵化应用进程

bindService时序图

发表于 2018-03-28 | 分类于 源码分析 |
字数统计: 0字 | 阅读时长 ≈ 1分钟

手写 ButterKnife BindView

发表于 2018-03-27 | 分类于 源码分析 |
字数统计: 2,092字 | 阅读时长 ≈ 11分钟

先建三个module,分别为Butterknife ButterKnife-Annotions ButterKnife-compiler,其中butterknife为Android Module其余的都是Java Module
。

ButterKnife-Annotions:提供注解。
ButterKnife-compiler: 依赖ButterKnife-Annotions,生成代码的module。
Butterknife:应用直接使用的库。

Butterknife-Annotions添加注解

1
2
3
4
5
@Retention(CLASS)
@Target(FIELD)
public @interface BindView {
int value();
}

ButterKnife-compiler添加依赖

1
2
3
4
5
6
dependencies {
implementation fileTree(include: ['*.jar'], dir: 'libs')
implementation 'com.google.auto.service:auto-service:1.0-rc3'
implementation 'com.squareup:javapoet:1.9.0'
implementation project(':ButterKnife-Annotions')
}

写一个生成代码的类ButterKnifeProcessor继承AbstractProcessor

1
2
3
4
5
6
public class ButterKnifeProcessor extends AbstractProcessor {
@Override
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
return false;
}
}

我们的步骤是:

  1. 添加注解@AutoService(Processor.class)
  2. 确定好我们需要生成代码的JAVA版本
  3. 确定生成代码
  4. 生成代码
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
import com.zzw.butterknife_annotions.BindView;

import java.lang.annotation.Annotation;
import java.util.LinkedHashSet;
import java.util.Set;

import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.RoundEnvironment;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.TypeElement;

//1. 添加注解 @AutoService(Processor.class)
@AutoService(Processor.class)
public class ButterKnifeProcessor extends AbstractProcessor {

//2. 指定处理的版本 >1.7

@Override
public SourceVersion getSupportedSourceVersion() {
//最高版本
return SourceVersion.latestSupported();
}

//3. 指定处理的注解
@Override
public Set<String> getSupportedAnnotationTypes() {
Set<String> types = new LinkedHashSet<>();
for (Class<? extends Annotation> annotation : getSupportedAnnotations()) {
types.add(annotation.getCanonicalName());
}
return types;
}

//4. 在这执行生成类
@Override
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
return false;
}


private Set<Class<? extends Annotation>> getSupportedAnnotations() {
Set<Class<? extends Annotation>> annotations = new LinkedHashSet<>();
annotations.add(BindView.class);
return annotations;
}
}

我们确定一下这个环境编译是否是正确的
Butterknife里面添加ButterKnife-compiler依赖

1
api project(':ButterKnife-compiler')

app添加Butterknife依赖和compiler生成代码依赖

1
2
implementation project(':Butterknife')
annotationProcessor project(':ButterKnife-compiler')

在app的MainActivity添加注解

1
2
3

@BindView(R.id.text_view)
TextView textView;

这个时候运行程序报错了提示

1
2
3
4
5
6
7
8
9
10
11
C:\Users\Swartz\Desktop\githubdemo\AptDemo\ButterKnife-compiler\src\main\java\com\zzw\butterknife_compiler\ButterKnifeProcessor.java
Error:(21, 20) 错误: 编码GBK的不可映射字符
Error:(25, 12) 错误: 编码GBK的不可映射字符
Error:(25, 17) 错误: 编码GBK的不可映射字符
Error:(29, 20) 错误: 编码GBK的不可映射字符
Error:(39, 20) 错误: 编码GBK的不可映射字符
Error:Execution failed for task ':Butterknife:javaPreCompileDebug'.
> Annotation processors must be explicitly declared now. The following dependencies on the compile classpath are found to contain annotation processor. Please add them to the annotationProcessor configuration.
- ButterKnife-compiler.jar (project :ButterKnife-compiler)
Alternatively, set android.defaultConfig.javaCompileOptions.annotationProcessorOptions.includeCompileClasspath = true to continue with previous behavior. Note that this option is deprecated and will be removed in the future.
See https://developer.android.com/r/tools/annotation-processor-error-message.html for more details.

这个是因为我们在ButterKnifeProcessor这个类使用了中文,所以我们在ButterKnife-compiler中指定编码集

1
2
3
tasks.withType(JavaCompile){
options.encoding='UTF-8'
}

这个时候我们在ButterKnifeProcessor里面process函数添加打印

1
System.out.print("11111");

然后随便修改一下MainActivity的代码,重新编译在Gradle Console里面就可以看到打印了。这里需要修改MainActivity代码是因为我们是编译时生成,as为了节省时间是重新编译修改了的类,如果不修改的话可以能会不编译。

环境ok了,这下我们就需要重点放在生成代码这块了,这块又分为以下步骤:

  1. 因为这getSupportedAnnotationTypes添加的所有注解都会走到process函数,所以我们要将注解按照类来分离。比如AActivity对应那些有那些注解,BActivity里面有那些注解。
  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
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

package com.zzw.butterknife_compiler;

import com.google.auto.service.AutoService;
import com.squareup.javapoet.ClassName;
import com.squareup.javapoet.JavaFile;
import com.squareup.javapoet.MethodSpec;
import com.squareup.javapoet.TypeSpec;
import com.zzw.butterknife_annotions.BindView;

import java.io.IOException;
import java.lang.annotation.Annotation;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.Filer;
import javax.annotation.processing.ProcessingEnvironment;
import javax.annotation.processing.Processor;
import javax.annotation.processing.RoundEnvironment;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.Element;
import javax.lang.model.element.Modifier;
import javax.lang.model.element.TypeElement;
import javax.lang.model.util.Elements;


//1. 添加注解 @AutoService(Processor.class)
@AutoService(Processor.class)
public class ButterKnifeProcessor extends AbstractProcessor {
//决定生成的文件在哪个文件夹
private Filer mFiler;
//决定生成的生成包名用
private Elements mElementUtils;

@Override
public synchronized void init(ProcessingEnvironment processingEnv) {
super.init(processingEnv);
mFiler = processingEnv.getFiler();
mElementUtils = processingEnv.getElementUtils();
}


//2. 指定处理的版本 >1.7

@Override
public SourceVersion getSupportedSourceVersion() {
//最高版本
return SourceVersion.latestSupported();
}

//3. 指定处理的注解
@Override
public Set<String> getSupportedAnnotationTypes() {
Set<String> types = new LinkedHashSet<>();
for (Class<? extends Annotation> annotation : getSupportedAnnotations()) {
types.add(annotation.getCanonicalName());
}
return types;
}

//4. 在这执行生成类
@Override
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
//4.1 注解分类
//拿到所有的注解标记的元素
Set<? extends Element> elements= roundEnv.getElementsAnnotatedWith(BindView.class);
//分类集合
Map<Element , List<Element>> elementMap= new LinkedHashMap<>();
//进行分类
for (Element element : elements) {
//拿到属于哪个类
Element enclosingElement = element.getEnclosingElement();
List<Element> viewBindElements = elementMap.get(enclosingElement);
if(viewBindElements ==null){
viewBindElements = new ArrayList<>();
elementMap.put(enclosingElement,viewBindElements);
}
viewBindElements.add(element);
}
//4.2 生成代码
for (Map.Entry<Element,List<Element>> entry : elementMap.entrySet()) {
Element enclosingElement = entry.getKey();
List<Element> viewBindElements = entry.getValue();

//类信息
// public final class xxxActivity_ViewBinding implements Unbinder
final String activityNameStr = enclosingElement.getSimpleName().toString();
ClassName activityClassName = ClassName.bestGuess(activityNameStr);
TypeSpec.Builder classBuilder = TypeSpec.classBuilder( activityNameStr +"_ViewBinding")
.addModifiers(Modifier.FINAL,Modifier.PUBLIC)
//添加实现
.addSuperinterface(ClassName.get("com.zzw.butterknife","Unbinder"))
//添加属性
.addField(activityClassName,"target",Modifier.PRIVATE);

//方法信息
//实现unbinder方法
MethodSpec.Builder unbindMethodBuilder = MethodSpec.methodBuilder("unbind")
.addAnnotation(Override.class)
.addModifiers(Modifier.PUBLIC);

unbindMethodBuilder.addStatement("$T target = this.target",activityClassName);
unbindMethodBuilder.addStatement("if (target == null) throw new IllegalStateException(\"Bindings already cleared.\");");

//构造函数
MethodSpec.Builder constructorMethodBuilder = MethodSpec.constructorBuilder()
.addModifiers(Modifier.PUBLIC)
.addParameter(activityClassName,"target");
constructorMethodBuilder.addStatement("this.target = target");


//findViewById
for (Element viewBindElement : viewBindElements) {
//target.textView1 = Utils.findViewById(target,R.id.text_view1);
String filedName = viewBindElement.getSimpleName().toString();
ClassName utilsClassName = ClassName.get("com.zzw.butterknife","Utils");
int resId = viewBindElement.getAnnotation(BindView.class).value();
constructorMethodBuilder.addStatement("target.$L = $T.findViewById(target,$L)",filedName,utilsClassName,resId);

unbindMethodBuilder.addStatement("target.$L = null" ,filedName);
}


//添加构造函数到类里面
classBuilder.addMethod(constructorMethodBuilder.build());
//添加unbinder方法到类里面
classBuilder.addMethod(unbindMethodBuilder.build());

try {
//拿到包名
String packageName =mElementUtils.getPackageOf(enclosingElement).getQualifiedName().toString();
JavaFile.builder(packageName,classBuilder.build())
.addFileComment("butterknife 自动生成")//注释
.build()
.writeTo(mFiler);
} catch (IOException e) {
e.printStackTrace();
System.out.print("异常");
}
}
return false;
}


private Set<Class<? extends Annotation>> getSupportedAnnotations() {
Set<Class<? extends Annotation>> annotations = new LinkedHashSet<>();
annotations.add(BindView.class);
return annotations;
}
}

生成的代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// butterknife 自动生成
package com.zzw.app;

import com.zzw.butterknife.Unbinder;
import com.zzw.butterknife.Utils;
import java.lang.Override;

public final class MainActivity_ViewBinding implements Unbinder {
private MainActivity target;

public MainActivity_ViewBinding(MainActivity target) {
this.target = target;
target.textView1 = Utils.findViewById(target,2131165301);
target.textView2 = Utils.findViewById(target,2131165302);
}

@Override
public void unbind() {
MainActivity target = this.target;
if (target == null) throw new IllegalStateException("Bindings already cleared.");;
target.textView1 = null;
target.textView2 = null;
}
}

我们可以自动生成代码了,这个时候我们可以通过这个来实现findViewById
我们在Butterknife module里面建Butterknife这个类

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
package com.zzw.butterknife;

import android.app.Activity;

import java.lang.reflect.Constructor;

/**
* Des:
* Created by zzw on 2018/1/29.
*/

public class Butterknife {

public static Unbinder bind(Activity activity){
//xxxActivity_ViewBinding viewBinding = new xxxActivity_ViewBinding(activity);
try{
Class<? extends Unbinder> bindClass= (Class<? extends Unbinder>) Class.forName(activity.getClass().getName()+"_ViewBinding");
Constructor<? extends Unbinder> bindConstructor= bindClass.getDeclaredConstructor(activity.getClass());
return bindConstructor.newInstance(activity);
}catch (Exception e){
e.printStackTrace();
return Unbinder.EMPTY;
}
}
}

MainActivity

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
package com.zzw.app;

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.widget.TextView;

import com.zzw.aptdemo.R;
import com.zzw.butterknife.Butterknife;
import com.zzw.butterknife.Unbinder;
import com.zzw.butterknife_annotions.BindView;

public class MainActivity extends AppCompatActivity {


@BindView(R.id.text_view1)
TextView textView1;
@BindView(R.id.text_view2)
TextView textView2;

private Unbinder mUnbinder;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mUnbinder = Butterknife.bind(this);

textView1.setText("你好 大哥");
}

@Override
protected void onDestroy() {
super.onDestroy();
mUnbinder.unbind();
}
}

该文中Butterknife module用到的类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import android.support.annotation.UiThread;

/**
* Des:
* Created by zzw on 2018/1/29.
*/

public interface Unbinder {
@UiThread
void unbind();

Unbinder EMPTY = new Unbinder() {
@Override public void unbind() { }
};
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package com.zzw.butterknife;

import android.app.Activity;
import android.view.View;

/**
* Des:
* Created by zzw on 2018/1/29.
*/

public class Utils {
public static <T extends View>T findViewById(Activity activity,int viewId){
return activity.findViewById(viewId);
}
}

手写 Parcelable 序列化和反序列化的具体过程

发表于 2018-03-26 | 分类于 源码分析 |
字数统计: 514字 | 阅读时长 ≈ 3分钟
1
2
3
4
5
6
binder 和 socket 通信的区别有哪些 :
binder 共享内存,Soket需要copy内存
Socket 远程,本地低速(zygote)


Serializable 和 Parcelable 之间的区别: (io流,共享内存)

Parcelable 序列化和反序列化的具体过程

Parcel.kt

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
package zzw.com.testparcel

public class Parcel {

companion object {
// Used to load the 'native-lib' library on application startup.
init {
System.loadLibrary("native-lib")
}
}

private var mNativePtr: Long = 0

init {
mNativePtr = nativeCreate()
}


fun writeInt(value: Int) {
nativeWriteInt(mNativePtr, value)
}

fun readInt(): Int {
return nativeReadInt(mNativePtr)
}

fun setDataPosition(pos: Int) {
nativeSetDataPosition(mNativePtr, pos)
}

private external fun nativeCreate(): Long
private external fun nativeSetDataPosition(nativePtr: Long, pos: Int)

private external fun nativeWriteInt(nativePtr: Long, value: Int)
private external fun nativeReadInt(nativePtr: Long): Int


}

native-lib.cpp

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
#include <jni.h>
#include <stdlib.h>
#include <string>


class Parcel {
char *mData;//共享内存首地址
int mDataPos = 0;//当前指针位置
public:
Parcel() {
mData = (char *) malloc(1024);
}

void writeInt(jint value) {
*reinterpret_cast<int *>(mData + mDataPos) = value;
mDataPos += sizeof(int);
}

void setDataPosition(jint i) {
mDataPos = i;
}

jint readInt() {
int result = *reinterpret_cast<int *>(mData + mDataPos);
mDataPos += sizeof(int);
return result;
}
};


extern "C" JNIEXPORT jlong
JNICALL
Java_zzw_com_testparcel_Parcel_nativeCreate(
JNIEnv *env,
jobject /* this */) {

return reinterpret_cast<jlong>(new Parcel());
}




extern "C" JNIEXPORT void
JNICALL
Java_zzw_com_testparcel_Parcel_nativeWriteInt(
JNIEnv *env,
jobject, jlong ptr, jint value) {
Parcel *parcel = reinterpret_cast<Parcel *>(ptr);
parcel->writeInt(value);
}

extern "C" JNIEXPORT void
JNICALL
Java_zzw_com_testparcel_Parcel_nativeSetDataPosition(
JNIEnv *env,
jobject, jlong ptr, jint pos) {
Parcel *parcel = reinterpret_cast<Parcel *>(ptr);
parcel->setDataPosition(pos);

}

extern "C" JNIEXPORT jint
JNICALL
Java_zzw_com_testparcel_Parcel_nativeReadInt(
JNIEnv *env,
jobject, jlong ptr) {
Parcel *parcel = reinterpret_cast<Parcel *>(ptr);
return parcel->readInt();
}

MainActivity.kt

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
package zzw.com.testparcel

import android.support.v7.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
import kotlinx.android.synthetic.main.activity_main.*

class MainActivity : AppCompatActivity() {

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)

var parcel = Parcel()

parcel.writeInt(5)
parcel.writeInt(10)

parcel.setDataPosition(0)

var num1 = parcel.readInt()
var num2 = parcel.readInt()

Log.e("zzz", "num1 =$num1 num2=$num2 ")
}

}

writeString分为两节,会先把长度存着,然后后面跟着具体的数据

1…456…8
曾大稳丶

曾大稳丶

80 日志
11 分类
20 标签
© 2018 — 2019 曾大稳丶
由 Hexo 强力驱动
|
主题 — NexT.Mist v5.1.4
访问人数 人 总访问量 次