<<Thinking in Android Architecture>>
前言:身为Android程序员,多思考才有自主的思考体系,才能逐渐成为架轻就熟的架构设计师。从今天开始,让高老师带您一起来动动脑,思考Android架构,探索许多程序员忽略的部分,却是晋升架构师必要的关键知识点。例如,本文的主题:Android UI的<单线程程序>概念,就是许多程序员,没有深入思考过的议题,一直在脑海里模糊不清,就很难成为称职的架构师了,因为这是系统稳定的必要环节。
1. Android UI的<单线程程序>概念
----单线程程序意谓着两个(或多个)线程不能共享对象或变量值。Android的UI是单线程程序的环境。UI控件(如Button等)都是由UI线程所创建,内部攸关于UI显示的属性或变量都只有UI线程才能存取(Access)之,别的线程并不能去存取之。例如下图里的View类别体系,都只限于UI线程才能去执行它们的onDraw()函数,因为它会实际更动到UI的属性。
![Thinking-A-01.png wKioL1Mnp36jUrO6AAEesKyBLN4883.jpg](http://s3.51cto.com/wyfs02/M02/22/CA/wKioL1Mnp36jUrO6AAEesKyBLN4883.jpg)
例如,请看一个Android代码:
public class myActivity extends Activity
implements OnClickListener {
private Button ibtn;
@Override protected void onCreate(Bundle icicle) {
super.onCreate(icicle);
ibtn = new Button(this);
//…………….
}
// 其它函数
}
由于UI线程来执行onCreate()函数,诞生了Button对象,因而只限UI线程能去存取该对象里攸关UI的属性,其它线程不能去碰它们。
2. 单线程可避开”线程安全“问题
线程安全问题就是如何避免不同线程之间,可能会相互干扰的问题。虽然两个线程几乎同时先后执行一个类别里的(可能不同)函数,只要不共享对象、或共享变量(例如Android的UI单线程环境),就不会产生干扰现象,也就没有线程安全问题。换句话说,如果各自使用自己的对象或变量(即不共享对象或变量),就不会干扰到别线程执行的正确性了。例如下述范例:
class Task2{
private int count;
public void init(){ count =0; }
public void f1() {
for(inti=0; i<3; i++) {
count++;
try {
Thread.sleep(10);
} catch(InterruptedException e) {e.printStackTrace(); }
System.out.println(Thread.currentThread().getName()+
"'s count: " + count);
}}
}
class Task implements Runnable {
public void run() {
Task2 ta2 = new Task2();
ta2.init(); ta2.f1();
}}
public class JMain {
public static voidmain(String[] args) {
Task ta = new Task();
Thread t1 = new Thread( ta, "A");
Thread t2 = new Thread( ta, "B");
t1.start();
t2.start();
System.out.println("Waiting...");
}}
这里,t1和t2线程共享主线程所诞生的ta对象,但是各自诞生了Task2类别之对象。两者各自使用自己的对象(即不共享对象或变量),就不会干扰到别线程的数据。所以输出正确的结果:
Waiting...
B's count: 1
A's count: 1
B's count: 2
A's count: 2
B's count: 3
A's count: 3
3. SurfaceView与非UI线程
View控件是由UI 线程(主线程)所执行。如果需要去迅速更新UI画面或者UI画图需要较长时间(避免阻塞主线程),就使用SurfaceView。它可以由背景线程(background thead)来执行,而View只能由UI(主)线程执行画面显示或更新。
![Thinking-02.png wKioL1MnqovSnEFAAACRGNKBdeM209.jpg](http://s3.51cto.com/wyfs02/M02/22/CA/wKioL1MnqovSnEFAAACRGNKBdeM209.jpg)
在SurfaceView里,非UI线程可以去碰触UI显示,例如将图形绘制于Surface画布上。这SurfaceView内含高效率的rendering机制,能让背景线程快速更新surface的内容,适合演示动画(animation)。
![Thinking-03.png wKiom1MnqtmwL_ufAACMFkkZ1H0988.jpg](http://s3.51cto.com/wyfs02/M01/22/C9/wKiom1MnqtmwL_ufAACMFkkZ1H0988.jpg)
4. 线程安全的化解之例
运用<Android UI的单线程环境>概念。View是一个单线程的类;其意味着:此类的开发者心中意图只让有一个线程来执行这个类的代码(如函数调用)。
![Thinking-04.png wKiom1MnqwuCWAliAAB0awHq_fI981.jpg](http://s3.51cto.com/wyfs02/M02/22/C9/wKiom1MnqwuCWAliAAB0awHq_fI981.jpg)
当App开发者撰写子类时,覆写onDraw()时,是被UI线程调用的。UI线程执行子类的onDraw()时,可能会调用基类的函数而间接使用到基类的数据。为了确保满足基类开发者的预设前题(即单线程),子类的开发者,就不宜使用小线程去调用基类的函数了。
![Thinking-05.png wKiom1MnqyGDLzMZAAC1NtcS8C0968.jpg](http://s3.51cto.com/wyfs02/M00/22/C9/wKiom1MnqyGDLzMZAAC1NtcS8C0968.jpg)
然而,不宜使用小线程去调用基类的函数,并不意味着,不能用小线程去执行子类的函数。只要小线程不去调用基类函数就行了。例如:
![Thinking-06.png wKiom1Mnq16Co1DGAACec_OVJls897.jpg](http://s3.51cto.com/wyfs02/M01/22/C9/wKiom1Mnq16Co1DGAACec_OVJls897.jpg)
这是可以的,因为小线程并没有去调用基类函数,不会有共享基类数据之虞。反之,下图就违反<UI单线程程序>的规则了:
![Thinking-07.png wKiom1Mnq3yAB5JnAACmGEOGZuU439.jpg](http://s3.51cto.com/wyfs02/M02/22/C9/wKiom1Mnq3yAB5JnAACmGEOGZuU439.jpg)
上图是小线程直接存取(Access)基类数据,有可能产生线程冲突。下图里,因调用基类函数而间接存取基类数据,也有可能产生线程冲突。所以都是违规的。
![Thinking-08.png wKioL1Mnq3GB3XCGAACt4xtXId0001.jpg](http://s3.51cto.com/wyfs02/M01/22/CB/wKioL1Mnq3GB3XCGAACt4xtXId0001.jpg)
因此,由于View类开发者心怀<单线程>,则View类的Client开发者就不宜让多线程去执行View的代码。
~ END ~
ee ee
【思考Android技术】
請參考: Android从程序员到架构师之路课程(在线视频学习)
请进入:ADT架构师学苑
1 0