作者Stephen Kochan
很牛x,
C语言----UNIX,这些就不多说了。
Brad J.Cox在20世纪80年代早期设计了Objective-C语言,它以一种叫做SmallTalk-80的语言为基础。
SmallTalk-80可以参考:
http://en.wikipedia.org/wiki/Smalltalk
http://zh.wikipedia.org/wiki/Smalltalk
Objective-C在C语言的基础上加了一层,这意味着对C进行了扩展,从而创造出一门新的程序设计语言,支持面向对象,即对象的创建和操作。
C语言可以参考:
http://en.wikipedia.org/wiki/C_(programming_language)
http://zh.wikipedia.org/wiki/C%E8%AF%AD%E8%A8%80
Objective-C可以参考:
http://en.wikipedia.org/wiki/Objective-C
http://zh.wikipedia.org/wiki/Objective-C
这几点主要说明Objective-C是从哪些语言演化而来的。概括的说主要基于SmallTalk-80的一些特性和C语言的实现,最后自己又进化了一些。
1994年,NeXT计算机公司和Sun公司联合发布了一个针对NEXTSTEP系统的标准规范,名为OPENSTEP。这个系统作为基础,苹果做了OS X发行版本,这个版本的开发环境的版本被苹果公司成为Cocoa。
这个主要介绍了OS X是从NEXTSTEP系统来的。开发环境叫Cocoa。
当iPhone于2007年发布时,起初,苹果公司不欢迎第三方应用程序开发。只允许他们开发基于Web的应用。最后开发人员非常不满,于是苹果公司不久之后就宣布,开发人员能够为iPhone开发所谓的本机应用。也就是我们所说的native应用。
这里主要说iOS应用开发不是一开始就有的,也是经历一定曲折后才出现的。
最后作者告诉我们:学习Objective-C之前没必要完整的学习C语言。毕竟C是面向过程的,看多了反而会让你误入歧途学不好Objective-C。Objective-C只是C语言的扩展,关键是它是面向对象的。所以要养成良好的面向对象的程序设计风格。
最后的忠告:“无图无真相”,学习计算机语言也是这样的,强烈建议运行每一个程序(必须一个字母一个字母的敲一遍)。
上面大部分是书作者自己的思想,我来说说我的吧,我从汇编写代码开始、C语言、C++、Java、ASP、JSP、Perl、Python、Shell等等,面向对象的,面向过程的,面向测试的,编译执行的,解释执行的,脚本了。基本上大部分都经历了。
个人经验而言,语言,主要还是一种工具,但这种工具总会有一套自己的生态或者思想以及开发环境,还有应用场景。没有那么多孰好孰坏的。分清场合和用途,去选择一种适合的语言去做。
刚开始看Objective-C的时候,挺别扭的,就像第一次接触MacBook Pro的OS X系统一样。慢慢习惯就好了。
只要你努力,一般没有什么学不会的问题,只是说学的快慢和学的深浅,应用的娴熟和高超等会有些个体差异而已。
我会将我的整个学习过程和大家一起共同分享。
好了,努力吧,骚年。和我一起学习Objective-C。
一、Handler的定义:
主要接受子线程发送的数据, 并用此数据配合主线程更新UI.
解释: 当应用程序启动时,Android首先会开启一个主线程 (也就是UI线程) , 主线程为管理界面中的UI控件,进行事件分发, 比如说, 你要是点击一个 Button, Android会分发事件到Button上,来响应你的操作。 如果此时需要一个耗时的操作,例如: 联网读取数据,或者读取本地较大的一个文件的时候,你不能把这些操作放在主线程中,如果你放在主线程中的话,界面会出现假死现象, 如果5秒钟还没有完成的话,会收到Android系统的一个错误提示 "强制关闭". 这个时候我们需要把这些耗时的操作,放在一个子线程中,因为子线程涉及到UI更新,Android主线程是线程不安全的,也就是说,更新UI只能在主线程中更新,子线程中操作是危险的.
这个时候,Handler就出现了来解决这个复杂的问题,由于Handler运行在主线程中(UI线程中),它与子线程可以通过Message对象来传递数据,这个时候,Handler就承担着接受子线程传过来的(子线程用sedMessage()方法传弟)Message对象,(里面包含数据) , 把这些消息放入主线程队列中,配合主线程进行更新UI。
二、Handler一些特点
handler可以分发Message对象和Runnable对象到主线程中, 每个Handler实例,都会绑定到创建他的线程中(一般是位于主线程),
它有两个作用: (1): 安排消息或Runnable 在某个主线程中某个地方执行, (2)安排一个动作在不同的线程中执行
Handler中分发消息的一些方法
post(Runnable)
postAtTime(Runnable,long)
postDelayed(Runnable long)
sendEmptyMessage(int)
sendMessage(Message)
sendMessageAtTime(Message,long)
sendMessageDelayed(Message,long)
以上post类方法允许你排列一个Runnable对象到主线程队列中,
sendMessage类方法, 允许你安排一个带数据的Message对象到队列中,等待更新.
三、Handler实例
(1) 子类需要继承Handler类,并重写handleMessage(Message msg) 方法, 用于接受线程数据
以下为一个实例,它实现的功能为 : 通过线程修改界面Button的内容
2 Button button;
3 MyHandler myHandler;
4
5 protected void onCreate(Bundle savedInstanceState) {
6 super.onCreate(savedInstanceState);
7 setContentView(R.layout.handlertest);
8
9 button = (Button) findViewById(R.id.button);
10 myHandler = new MyHandler();
11 // 当创建一个新的Handler实例时, 它会绑定到当前线程和消息的队列中,开始分发数据
12 // Handler有两个作用, (1) : 定时执行Message和Runnalbe 对象
13 // (2): 让一个动作,在不同的线程中执行.
14
15 // 它安排消息,用以下方法
16 // post(Runnable)
17 // postAtTime(Runnable,long)
18 // postDelayed(Runnable,long)
19 // sendEmptyMessage(int)
20 // sendMessage(Message);
21 // sendMessageAtTime(Message,long)
22 // sendMessageDelayed(Message,long)
23
24 // 以上方法以 post开头的允许你处理Runnable对象
25 //sendMessage()允许你处理Message对象(Message里可以包含数据,)
26
27 MyThread m = new MyThread();
28 new Thread(m).start();
29 }
30
31 /**
32 * 接受消息,处理消息 ,此Handler会与当前主线程一块运行
33 * */
34
35 class MyHandler extends Handler {
36 public MyHandler() {
37 }
38
39 public MyHandler(Looper L) {
40 super(L);
41 }
42
43 // 子类必须重写此方法,接受数据
44 @Override
45 public void handleMessage(Message msg) {
46 // TODO Auto-generated method stub
47 Log.d("MyHandler", "handleMessage......");
48 super.handleMessage(msg);
49 // 此处可以更新UI
50 Bundle b = msg.getData();
51 String color = b.getString("color");
52 MyHandlerActivity.this.button.append(color);
53
54 }
55 }
56
57 class MyThread implements Runnable {
58 public void run() {
59
60 try {
61 Thread.sleep(10000);
62 } catch (InterruptedException e) {
63 // TODO Auto-generated catch block
64 e.printStackTrace();
65 }
66
67 Log.d("thread.......", "mThread........");
68 Message msg = new Message();
69 Bundle b = new Bundle();// 存放数据
70 b.putString("color", "我的");
71 msg.setData(b);
72
73 MyHandlerActivity.this.myHandler.sendMessage(msg); // 向Handler发送消息,更新UI
74
75 }
76 }
77
经常看到Android的消息用法大概为:
Looper.prepare()
Looper.myLooper();
xxxHandler = new Handler() {
handleMessage(Message msg){...}
};
Looper.loop();
刚开始搞不清楚状况, 根据名字完全看不出有什么关系的两个类,到底如何进行消息传递呢? 只是知道就这么用就没问题的, 应该不少人跟我一样吧.
如然有兴趣来解刨一下吧.
Looper.prepare(); 里面有一句 sThreadLocal.set(new Looper());
这里就new 了一个Looper了, 然后放到ThreadLocal里面, 这是个线程数据共享的一个类.
private Looper() {
mQueue = new MessageQueue();
mRun = true;
mThread = Thread.currentThread();
}
在这里面就传递了当前的工作线程的信息,并且new了一个message queue,就是消息队列嘛, 用来接收消息的容器.
public static Looper myLooper() {
return sThreadLocal.get();
}
这个函数就返回了上面创建的那个new Looper();
public Handler() {
...
mLooper = Looper.myLooper();
mQueue = mLooper.mQueue;
...
}
在这里就把当前线程的Looper赋给Handler了, 这就发生关系了.
可能有同学还会有疑问, 上面是两个类的不同的语句Looper.myLooper();怎么得到的是同一个呢?
那就分析一下吧;
在Looper类里面有个全局的静态容器
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
再进入ThreadLocal类里面看
public void set(T value) {
Thread currentThread = Thread.currentThread();
Values values = values(currentThread);
if (values == null) {
values = initializeValues(currentThread);
}
values.put(this, value);
}
在这里就把当前的线程的相关信息设进去了.
看看get()函数;
public T get() {
// Optimized for the fast path.
Thread currentThread = Thread.currentThread();
Values values = values(currentThread);
if (values != null) {
Object[] table = values.table;
int index = hash & values.mask;
if (this.reference == table[index]) {
return (T) table[index + 1];
}
} else {
values = initializeValues(currentThread);
}
return (T) values.getAfterMiss(this);
}
再这里就返回了当前线程的相关信息.
因为ThreadLocal是个模板容器, 声明为ThreadLocal<T>
在Looper中声明为ThreadLocal<Looper> , 所以 T == Looper .
简单的翻译一下上面的get()和set()吧;
public void set(Looper value) {
values.put(this, value);
}
public void Looper get() {
return values.get(this);
}
这样就很清晰了, 关系就是这么发生的. 回头梳理一下吧.
Looper.prepare()
Looper.myLooper();
xxxHandler = new Handler(){ handleMessage(Message msg){...} };
Looper.loop();
等价于
Looper.prepare() { sThreadLocal.set(currentThread, new Looper(); }
Looper.myLooper() { sThreadLocal.get(currentThread) }
new Handle(){
...
mLooper = sThreadLocal.get(currentThread);
mQueue = mLooper.mQueue;
...}
关系发生了,这时候就可以通过Message进行通信了, 这就不多说了.