Android应用的主线程(UI线程)用作更新UI,不可以让主线程做费时操作,否则会出现ANR(App Not Response),一般处理耗时操作时都需要开启一个线程,线程执行结束,发送消息给主线程来更新UI

Read More

使用JSONModel

  1. 创建一个新的Ocjective-C的类并继承JSONModel
  2. 在头文件中声明Json中Keys同名属性
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    @import "JSONModel.h"

    @interface CountryModel : JSONModel

    @property (assign,nonatomic) int id;
    @property (strong,nonatomic) NSString* country;
    @property (strong,nonatomic) NSString* dialCode;
    @property (assign,nonatomic) BOOL isInEurope;

    @end

不需要在.m文件中填写任何东西

解析JSON字符串时

1
2
3
NString* json = ...
NSError* error = nil;
CountryModel* contryModel = [[CountryModel alloc] initWithString:json error:&error];

示例

基础的例子

1
2
3
4
5
{
"id":"123",
"name":"Product name",
"price":12.95
}
1
2
3
4
5
6
7
@interface ProductModel : JSONModel

@property (assign,nonatomic) int id;
@property (strong,nonatomic) NSString* name;
@property (assign,nonatomic) float price;

@end

嵌套类

1
2
3
4
5
6
7
8
9
{
"order_id":104,
"total_price":13.45,
"product":{
"id":"123",
"name":"Product name",
"price":12.34
}
}
1
2
3
4
5
6
7
@interface OrderModel : JSONModel

@property (assign,nonatomic) int order_id;
@property (assign,nonatomic) float total_price;
@property (strong,nonatomic) ProductModel* product;

@end

嵌套集合

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
{
"oder_id":104,
"total_price":103.45,
"products" : [
{
"id":"123",
"name":"Product # 1",
"price":12.95
},
{
"id":"137",
"name":"Product # 2",
"price":82.95
}
]
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
@potocol ProductModel
@end

@interface ProductModel : JSONModel

@property (assign,nonatomic) int id;
@property (strong,nonatomic) NSString* name;
@property (assign,nonatomic) float price;

@end

@implementation ProductModel
@end

@interface OrderModel : JSONModel

@property (assign,nonatomic) int order_id;
@property (assign,nonatomic) float tital_price;
@property (strong,nonatomic) NSArray<ProductModel> *products;

@end

@implementation OrderModel
@end

修改Key值

1
2
3
4
5
6
7
8
9
10
11
{
"order_id":104,
"order_details" : [
{
"name":"Product# 1",
"price":{
"usd":12.95
}
}
]
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@interface OrderModel : JSONModel
@property (assign,nonatomic) int id;
@property (assign,nonatomic) float price;
@property (strong,nonatomic) NSString* productName;
@end

@implementation OrderModel

+ (JSONKeyMapper *)keyMapper
{
return [[JSONKeyMapper alloc] initWithDictionary:@{
@"order_id":@"id",
@"order_details.mame":@"productName",
@"order_details.price":@"price"
}];
}
@end

全局改变Key

1
2
3
4
5
6
[JSONModel setGlobalKeyMapper:[
[JSONKeyMapper alloc] initWithDictionary:@{
@"item_id":@"ID",
@"item_name":@"itemName"
}]
];

使用JSON请求

1
2
3
4
5
6
[[JSONHTTPClient requestHeaders] setValue:@"MySecret" forKey:@"AuthorizationToken"];
[JSONHTTPClient postJSONFromURLWithString:@"http://mydomain.com/api"
params:@{@"postParma1":@"valuel"}
completion:^(id json,JSONModelError *err){

}];

JSON文本和Dictionary的转换

1
2
3
4
5
ProductModel* pm = [[ProductModel alloc] initWithString:jsonString error:nil];
pm.name = @"Changed Name";

NSDictionary* dict = [pm toDictionary];
NSString* string = [pm toJSONString];

自定义Date格式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@implementation JSONValueTransformer (CustomTransformer)

- (NSDate *)NSDateFromNSString:(NSString *)string {
NSDateFormatter *formatter = [[NSDatrFormatter alloc] init];
[formatter setDateFormat:APIDateFormat];
return [formatter dateFromString:string];
}

- (NSString *)JSONObjectFromNSDate:(NSDate *)date {
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
[formatter setDateFormat:APIDateFormat];
return [formatter stringFromDate:date];
}

@end
注:关于名字为id的属性,可以使用id命名,而且需要使用NSNumber或者NSString的类型来定义

iOS Application生命周期

AppDelegate

  1. - (BOOL)application:(UIApplication *)applicationwillFinishLaunchingWithOptions:(NSDictionary *)launchOptions
    将要启动
  2. - (BOOL)application:(UIApplication *)applicationdidFinishLaunchingWithOptions:(NSDictionary *)launchOptions
    程序首次完成启动时执行,若直接启动,launchOptions没有数据,若由其他应用启动,launchOptions包含数据
  3. - (void)applicationWillResignActive:(UIApplication *)application
    应用进入后台,程序失去激活(Active)时调用
    需要在此方法中执行下列任务
    • 暂停正在执行的任务
    • 禁止计时器
    • 减少OpenGL ES帧率
    • 若为游戏应暂停游戏
  4. - (void)applicationDidEnterBackground:(UIApplication *)application
    已经进入后台时调用
    • 释放共享资源
    • 保存用户数据
    • 作废计时器
    • 保存足够的程序状态以便一次恢复
  5. - (void)applicationWillEnterForeground:(UIApplication *)application
    从后台进入前台时调用
  6. - (void)applicationDidBecomeActive:(UIApplication *)application
    应用进入激活状态
  7. - (void)applicationWillTerminate:(UIApplication *)application
    应用兼将要退出时调用

    UIController

  • alloc 创建对象
  • init 初始化对象
  • loadView 从nib载入视图
  • viewDidLoad 载入完成
  • viewWillApper 视图出现在屏幕之前
  • viewWillDisapper 渲染完成,显示在屏幕上
  • viewDiddisapper 从屏幕移除之前
  • viewWillUnload 已经从屏幕移除
  • viewDidUnload 载出之前
  • dealloc 被销毁

    Android Activity生命周期

  1. onCreate()
    创建Activity
  2. onStart()
    创建或从后台重新到前台时被调用
  3. onRestart()
    从后台到前台时被调用
  4. onResume()
    创建或者被覆盖、后台重新回到前台时被调用
  5. onPause()
    被覆盖或者锁屏时被调用
  6. onStop()
    退出当前Activity或者跳转到新的Activity时被调用
  7. onDestroy()
    退出Activity时被调用,调用之后Activity就被销毁了
  8. onSaveInstanceState(Budle outState)
    Activity被系统销毁时调用
  9. onRestoreInstanceState(Budle savedInstanceState)
    Activity重建时被调用

    对比

    第一次启动

    iOS:
    1
    2
    3
    4
    5
    - [AppDelegate application:didFinishLaunchingWithOptions:]
    - [ViewController viewDidLoad]
    - [ViewController viewWillAppear:]
    - [AppDelegate applicationDidBecomeActivie:]
    - [ViewController viewDidAppear:]

Android:

1
2
3
onCreate()
onStart()
onResume()

应用进入后台

iOS

1
2
- [AppDelegate applicationWillResignActive:]
- [AppDelegate applicationDidEnterBackground:]

Android

1
2
onPause()
onStop()

应用从后台进入前台

iOS

1
2
- [AppDelegate applicationWillEnterForeground:]
- [AppDelegate applicationDidBecomeActive:]

Android

1
2
onStart()
onResume()

完全退出应用

iOS

1
2
3
4
- [AppDelegate applicationDidEnterBackground:]
- [ViewController viewWillDisappear:]
- [ViewController viewDidDisappear:]
- [AppDelegate applicationWillTerminate:]

Android

1
2
3
onPause()
onStop()
onDestroy()

分析

Android、iOS的生命周期看着大同小异,但是差别还算比较大。
Android的Activity类似iOS中UIApplication + UIViewController。
iOS的应用像是一个全屏展开的窗口,UIApplication负责管理运行状态的生命周期,UIController负责管理视图,视图间靠通知传递数据
Android的App可以理解为ActivityServiceCentent ProviderBroadcastReceiver组成,可视部分主要由Activity组成,Activity要管理运行状态和视图,而且每个Activity的运行状态相对独立,四大组件之间、包括应用之间都可以通过Intent传递数据。


https://github.com/SeniorZhai/BlurAndroid

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
public class Blur{
private static final String TAG = "Blur";

public static Bitmap fastblur(Context context,Bitmap sentBitmap,int radius) {
if (VERSION.SDK_INT > 16) {
Bitmap bitmap = sentBitmap.copy(sentBitmap.getConfig(),true);
final RenderScript rs = RenderScript.create(context);
final Allocation input = Allocation.createFromBitmap(rs,sentBitmap,Allocation.MipmapControl.MIPMAP_NONE,Allocation.USAGE_SCRIPT);
final Allocation output = Allocation.createTyped(rs,input.getType());
final ScriptIntrinsicBlur script = ScriptIntrinsicBlur.create(rs,Element.U8_4(rs));
script.setRadius(radius);
script.setInput(input);
script.forEach(output);
output.copyTo(Bitmap);
return bitmap;
}

Bitmap bitmap = sentBitmap.copy(sentBitmap.getConfig(),true);
if (radius < 1) {
return (null);
}

int w = bitmap.getWith();
int h = bitmap.getHight();

int[] pix = new int[w * h];
bitmap.getPixels(pix,0,w,0,0,w,h);

int wm = w - 1;
int hm = h - 1;
int wh = w * h;
int div = radius + radius + 1;

int r[] = new int[wh];
int g[] = new int[wh];
int b[] = new int[wh];
int rsum,gsum,bsum,x,y,i,p,yp,yi,yw;
int vmin[] = new int[Math.max(w,h)];

int dv[] = new int[256 * divsum];
for (i = 0;i < 256 * divsum;i++) {
dv[i] = (i / divsum);
}

yw = yi = 0;

int[][] stack = new int[div][3];
int stackpointer;
int stackstart;
int[] sir;
int rbs;
int r1 = radius + 1;
int routsum,goutsum,boutsum;
int rinsum,ginsum,binsum;

for (y = 0;y < h;y ++) {
rinsum = ginsum = binsum = routsum = goutsum = boutsum = rsum = gsum = bsum = 0;
for (i = -radius;i < radius; i++) {
p = pix[yi + Math.min(wm,Math.max(i,0))];
sir = stack[i + radius];
sir[0] = (p & 0xff0000) >> 16;
sir[1] = (p & 0x00ff00) >> 8;
sir[2] = (p & 0x0000ff);
rbs = r1 - Math.abs(i);
rsum += sir[0] * rbs;
gsum += sir[1] * rbs;
bsum += sir[2] * rbs;
if (i > 0) {
rinsum += sir[0];
ginsum += sir[1];
binsum += sir[2];
} else {
routsum += sir[0];
goutsum += sir[1];
boutsum += sir[2];
}
}
stackpointer = radius;

for (x = 0; x < w; x++) {
rinsum = ginsum = binsum = routsum = goutsum = boutsum = rsum = gsum = bsum = 0;
yp = -radius * w;
for (i = -radius; i <= radius; i++) {
yi = Math.max(0, yp) + x;

sir = stack[i + radius];

sir[0] = r[yi];
sir[1] = g[yi];
sir[2] = b[yi];

rbs = r1 - Math.abs(i);

rsum += r[yi] * rbs;
gsum += g[yi] * rbs;
bsum += b[yi] * rbs;

if (i > 0) {
rinsum += sir[0];
ginsum += sir[1];
binsum += sir[2];
} else {
routsum += sir[0];
goutsum += sir[1];
boutsum += sir[2];
}

if (i < hm) {
yp += w;
}
}
yi = x;
stackpointer = radius;
for (y = 0; y < h; y++) {
// Preserve alpha channel: ( 0xff000000 & pix[yi] )
pix[yi] = (0xff000000 & pix[yi]) | (dv[rsum] << 16) | (dv[gsum] << 8) | dv[bsum];

rsum -= routsum;
gsum -= goutsum;
bsum -= boutsum;

stackstart = stackpointer - radius + div;
sir = stack[stackstart % div];

routsum -= sir[0];
goutsum -= sir[1];
boutsum -= sir[2];

if (x == 0) {
vmin[y] = Math.min(y + r1, hm) * w;
}
p = x + vmin[y];

sir[0] = r[p];
sir[1] = g[p];
sir[2] = b[p];

rinsum += sir[0];
ginsum += sir[1];
binsum += sir[2];

rsum += rinsum;
gsum += ginsum;
bsum += binsum;

stackpointer = (stackpointer + 1) % div;
sir = stack[stackpointer];

routsum += sir[0];
goutsum += sir[1];
boutsum += sir[2];

rinsum -= sir[0];
ginsum -= sir[1];
binsum -= sir[2];

yi += w;
}
}

Log.e("pix", w + " " + h + " " + pix.length);
bitmap.setPixels(pix, 0, w, 0, 0, w, h);
return (bitmap);
}
}

功能 Mac OSX Win/Linux
单行注释 Cmd + / Ctrl + /
多行注释 Cmd + Alt + / Ctrl + Alt + /
格式化代码 Cmd + Alt + L Ctrl + Alt + L
清除无效包引用 Alt + Control + O Alt + Ctrl + O
查找 Cmd + F Ctrl + F
替换 Cmd + R Ctrl + R
上下移动代码 Alt + Shift + Up/Down Alt + Shift + Up/Down
删除行 Cmd + Delete Ctrl + Y
扩大缩小选中范围 Alt + Up/Down Ctrl + W/Ctrl + Shift + W
快捷生成结构体 Cmd + Alt + T Ctrl + Alt + T
快捷覆写方法 Control + O Ctrl + O
快捷定位到行首/尾 Cmd + Left/Right Ctrl + Left/Right
折叠展开代码块 Cmd + Plus/Minus Ctrl + Plus/Minus
折叠全部代码块 Cmd + Shift + Plus/Minus Ctrl + Shift + Plus/Minus
文件结构 Cmd + F12 Ctrl + F12
查找调用位置 Cmd + option + H Ctrl + Alt + H
大小写转换 Cmd + Shift + U Ctrl + Shift + U
  1. Alt + enter(option + return) 导包,自动修正
  2. Ctrl+X(command + X) 删除行
  3. Ctrl+D(command + D) 复制行
  4. Alt + Ctrl + Enter(option + control + return) 代码补全

Gradle

Gradle以Groovy为基础,面向Java应用,基于DSL语法的自动化构建工具

Gradle基本结构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath 'com.android.tools.build:gradle:1.0.0'
}
}

apply plugin: 'android'
android{
compileSdkVersion 19
buildToolsVersion "19.0.0"
}
  • buildscript{…} 设置脚本的运行环境
  • apply plugin: ‘android’ 设置使用android插件构建项目
  • android{…} 设置编译android项目的参数

任务task执行

通常的任务有

  1. 输出一个项目文件,Android就是打包APK
  2. 运行检查,检查程序的错误,语法等
  3. 执行assemblecheck
  4. 清理项目输出文件

基本的构建定制

支持的配置有

  • minSdkVersion 最小支持sdk版本
  • targetSdkVersion 编译时目标的sdk版本
  • versionCode 程序版本号
  • versionName 程序版本名称
  • applicationId 程序包名
  • package Name for the test application 测试用的程序包名
  • instrumentation test runner 测试用的instrumentation实例
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    android{
    compileSdkVersion 19
    buildToolsVersion "19.0.0"

    defaultConfig{
    versionCode 12
    versionName "2.0"
    minSdkVersion 16
    targetSdkVersion 16
    }
    }

签名配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
android{
signingConfigs {
debug{
storeFile file("debug.keystore")
}

myConfig{
storeFile file("other.keystore")
storePassword "android"
keyAlias "androiddebugkey"
keyPassword "android"
}
}

buildTypes {
foo {
debuggable true
jinDebugBuild true
signingConfig signingConfigs.myConfig
}
}
}

设置代码混淆

1
2
3
4
5
6
7
8
android {
buildTypes{
release {
runProguard true
proguardFile getDefaultProguardFile('poguard-android.txt')
}
}
}

依赖配置

1
2
3
4
dependencies{
compile files('libs/foo.jar') // 单个文件
compile fileTree(dir:'libs',include:['*.jar']) // 多个文件
}

maven仓库

1
2
3
4
5
6
7
8
9
10
11
repostiories {
mavenCentral()
}

dependencies {
complie 'com.google.guava:guava:11.0.2'
}

android {
...
}

  • 类(class) 用来描述具体相同的属性和方法的对象集合
  • 类变量 类内部的公有变量
  • 数据成员 类变量或者实例变量用于处理类及其实例对象的相关的数据
  • 方法重载(override) 父类继承的方法不能满足子类的需求,可以对其进行修改
  • 实例变量 在方法中定义的变量,只作用于当前实例的类
  • 继承 派生类继承基类
  • 实例化 创建一个类的实例
  • 方法 类中定义的函数
  • 对象 通过类定义的数据结构实例

创建类

1
2
3
class ClassName:
'Optional class documentation string' # 类文档字符串
class_suite # 类体
  • getattr(obj,name[,default]):访问对象的属性
  • hasattr(obj,name):检查是否存在一个属性
  • setattr(obj,name,value):设置一个属性,如果不存在会创建一个新的属性
  • delattr(obj,name):删除属性

Python内置类属性

  • __dict__:类的属性(包含一个字典)
  • __doc__:类的文档字符串
  • __name__:类名
  • __module__:类定义所在的模块(类的全名是__main__.className)
  • __base__:类的所有父类构成元素

Python对象销毁

在Python内部记录着所有使用对象各有多少引用,一个内部跟踪变量,称为一个引用计数器
析构函数__del__在对象消逝的时候被调用