前言:Android平臺的核心是C/C++,爲了吸引更多App開發者來使用它,就在C/C++之上,增添一層Java框架,這框架的基類一方面提供接口(即抽像函數)來支持App開發者撰寫子類。這項接口的幕後,隱藏了默認函數(Default Function)及其複雜代碼,讓App開發者只要撰寫簡單的子類,就能繼承而調用這些默認函數,藉由簡單的接口調用,就能輕易叫出複雜的默認行爲(Default Behavior)。html
抽象類的焦點在於抽象函數,它們的實做指令部份都是從缺的。因此該抽象類的子類『必須』補足這個欠缺,才能成爲一個具體類。這抽像函數是基類與子類二者相遇的地方,也就成爲二者的接口,又稱爲基類的API。不過,在上述文章裏,偏重於API的角色及其設計要點。但並未碰觸到應用開發者的心理層面:爲什麼應用開發者願意來使用框架及其API呢? 也就是說,框架開發者必須關心如何去吸引應用開發者來使用框架及其API。其解答之一是:在基類裏提供默認行爲。java
1. 基類接口隱藏了默認函數android
剛纔提過了,抽象類裏的抽象函數,其實做指令部份都是從缺的。因此該抽象類的子類『必須』補足這個欠缺,才能成爲一個具體類。可知,子類開發者的負擔是蠻重的,框架設計能夠透過默認行吸引應用子類開發者。想想,若是將一些默認(Default)的實做部份加到抽象類裏,則其子類就可選擇要不要修正這個默認實做部份,這樣能夠減輕子類開發者的負擔。例以下述之範例: 程序員
其程序代碼以下:canvas
/* Shape.java */架構
import java.awt.Color;app
import java.awt.Graphics; 框架
public abstract class Shape {ide
Graphics m_gr;函數
public Shape(Graphics gr) { m_gr = gr; }
public void onPaint(){
// drawing background
m_gr.setColor(Color.black);
m_gr.fillRect(10,30, 200,100);
}
public void paint() {
onPaint();
}}
/* Bird.java */
import java.awt.Color;
import java.awt.Graphics;
public class Bird extends Shape {
Graphics m_gr;
public Bird(Graphics gr) {
super(gr);
m_gr = gr;
}
public void onPaint(){
super.onPaint();
// drawing a bird
m_gr.setColor(Color.cyan);
m_gr.drawArc(30,80,90,110,40,100);
m_gr.drawArc(88,93,90,100,40,80);
m_gr.setColor(Color.white);
m_gr.drawArc(30,55,90,150,35,75);
m_gr.drawArc(90,80,90,90,40,80);
}}
/* JMain.java */
import java.awt.Graphics;
import javax.swing.JFrame;
import javax.swing.JPanel;
class JP extends JPanel {
public void paintComponent(Graphics gr){
super.paintComponents(gr);
Shape bird = new Bird(gr);
bird.paint();
}}
public class JMain extends JFrame{
public JMain(){
setTitle("");
setSize(350, 250);
}
public static void main(String[] args) {
JMain frm = new JMain();
JP panel = new JP();
frm.add(panel);
frm.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frm.setVisible(true);
}}
此程序畫出兩隻海鷗以下圖:
其中的抽象類Shape的paint()和onPaint()函數都含有默認的實做指令。具體類Bird的設計者選擇以下:
不覆寫(即不修正)paint()函數。直接使用默認行爲,因此減輕了負擔。
覆寫(即修正)onPaint()函數。重用(Reuse)了默認行爲,也減輕了部分的負擔。
此程序執行時,主程序的指令:bird.paint()呼叫子類Bird的paint(),可是Bird並無paint()函數,因而採用基類Shape的默認paint()函數。此默認函數呼叫onPaint(),就反向呼叫了子類的onPaint()。請注意,是基類paint()呼叫子類的onPaint();並非基類onPaint()來呼叫子類的onPaint()。反而是子類onPaint()呼叫基類的onPaint()。[歡迎光臨 高煥堂 網頁: http://www.cnblogs.com/myEIT/ ]
2. Android框架的默認函數之例
Android是應用框架,而在抽象類裏擺上一些默認行爲又是應用框架的主要技倆,因此Android裏不只含有各式各樣的抽象類,並且也有各式各樣的默認行爲。例如在View基類(或稱抽象類)裏就定義了onDraw()函數。Button又從View類繼承而獲得onDraw()函數。最後,咱們還能夠撰寫新類去繼承Button類,仍然繼承而得onDraw()函數。在這個繼承體系裏的每一層級皆可覆寫這繼承而來的onDraw()函數,造成默認行爲了。例以下述的範例程序:
2.1 操做情境
此程序一開始,畫面出現兩個按鈕以下:
若是按下<Exit>按鈕,程序就結束了。
2.2 撰寫步驟
Step-1: 創建Android項目:Fx02。
Step-2: 撰寫Activity的子類:ac01,其程序代碼以下:
/* ac01.java */
package com.misoo.pkaz;
import android.app.Activity;
import android.graphics.Color;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.LinearLayout;
public class ac01 extends Activity implements OnClickListener {
private okButton ok_btn;
private exitButton exit_btn;
@Override public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
LinearLayout layout = new LinearLayout(this);
layout.setOrientation(LinearLayout.VERTICAL);
ok_btn = new okButton(this);
ok_btn.setOnClickListener(this);
LinearLayout.LayoutParams param =
new LinearLayout.LayoutParams(ok_btn.get_width(),
ok_btn.get_height());
layout.addView(ok_btn, param);
exit_btn = new exitButton(this); exit_btn.setOnClickListener(this);
exit_btn.setText("Exit"); exit_btn.setTextColor(Color.BLUE);
exit_btn.setTextSize(25); exit_btn.setBackgroundResource(R.drawable.icon2);
LinearLayout.LayoutParams param2 =
new LinearLayout.LayoutParams(80, 55);
param2.topMargin = 5; param2.leftMargin = 5;
layout.addView(exit_btn, param2);
setContentView(layout);
}
public void onClick(View v) {
if(v == ok_btn) setTitle("OK");
else if(v == exit_btn) finish();
}}
Step-3: 撰寫Button的子類:okButton,其程序代碼以下:
/* okButton.java */
package com.misoo.pkaz;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.widget.Button;
public class okButton extends Button{
public okButton(Context ctx){
super(ctx); super.setText(" K");
super.setTextSize(30); super.setTextColor(Color.RED);
}
@Override protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
Paint pa = new Paint();
pa.setColor(Color.YELLOW);
canvas.drawCircle(30, 25, 17, pa);
pa.setColor(Color.RED);
canvas.drawCircle(30, 25, 15, pa);
pa.setColor(Color.YELLOW);
canvas.drawCircle(30, 25, 12, pa);
}
public int get_width(){ return 90; }
public int get_height(){ return 60; }
}
Step-4: 撰寫Button的子類:exitButton,其程序代碼以下:
/* exitButton.java */
package com.misoo.pkaz;
import android.content.Context;
import android.graphics.Canvas;
import android.widget.Button;
public class exitButton extends Button {
public exitButton(Context ctx){ super(ctx); }
@Override protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
}}
2.3 說明:
1) 咱們在撰寫okButton類時,面對Button的默認行爲,可重複利用(Reuse)它,也能夠不用它。
2) 因之,咱們有三種選擇:
並不覆寫onDraw()函數。這表示onDraw()函數的默認行爲適合於okButton類,直接繼承Button基類的onDraw()函數就好了。
徹底覆蓋掉基類的默認行爲。這表示onDraw()函數的默認行爲不適合於okButton類,並且不想去重複利用(Reuse)它。
重複利用(Reuse)它,而且修正它。呼叫基類的默認行爲(如畫出圖畫的背景),在增添新的行爲,達到修正默認行爲之目的。
3) 例如,okButton類採起上述的第(三)種作法。既呼叫默認的行爲繪出一個白色按鈕,並且本身畫出彩色的圖案。
4) 再如,exitButton類採起上述的第(一)種作法。雖然表面上有覆寫的形式,但也只是呼叫基類的默認行爲而已。因此,exitButton的onDraw()函數是多餘的、可刪去之。
3. Android的<IoC + 默認函數>
Android是應用框架,不但在抽象類裏擺上一些默認行爲,並且能進行反向呼叫具體類的覆寫函數。抽象類、默認行爲和反向呼叫是應用框架的主要元素,因此Android裏不只含有各式各樣的抽象類,並且也有各式各樣的默認行爲,還能順暢地反向呼叫。例如在View類體系裏各種皆能覆寫onDraw()函數,讓View類繼承的基類能順利反向呼叫子類的onDraw()函數。例以下述的範例程序:
3.1 操做情境
1) 此程序執行時,呈現以下的畫面:
2) 若是按下RadioButton,畫面就變換以下:
3) 若按下<Exit>按鈕,程序就結束了。
3.2 撰寫步驟:
Step-1: 創建Android應用程序項目:Fx03。
Step-2: 撰寫Activity的子類ac01,其程序代碼以下:
/* ac01.java */
package com.misoo.ppxx;
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.ViewGroup;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.RadioButton;
public class ac01 extends Activity implements OnClickListener {
private final int WC = ViewGroup.LayoutParams.WRAP_CONTENT;
private MyView mv;
private RadioButton ra;
private Button btn;
@Override public void onCreate(Bundle icicle) {
super.onCreate(icicle);
LinearLayout layout = new LinearLayout(this);
layout.setOrientation(LinearLayout.HORIZONTAL);
LinearLayout.LayoutParams param =
new LinearLayout.LayoutParams(115, 250);
param.leftMargin = 1;
mv = new MyView(this);
layout.addView(mv, param);
ra = new RadioButton(this); ra.setOnClickListener(this);
param = new LinearLayout.LayoutParams(WC, WC);
param.topMargin = 40;
layout.addView(ra, param);
btn = new Button(this); btn.setText("Exit");
btn.setOnClickListener(this); btn.setBackgroundResource(R.drawable.gray);
param.leftMargin = 30;
layout.addView(btn, param);
setContentView(layout);
}
public void onClick(View v) {
if( v == ra) mv.ReDraw();
else if(v == btn) finish();
}}
Step-3: 撰寫View的子類MyView,其程序代碼以下:
/* MyView.java */
package com.misoo.ppxx;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.view.View;
public class MyView extends View {
private Paint pa = new Paint();
private boolean yn = false;
public MyView(Context context) { super(context); }
public void ReDraw(){
this.invalidate();
}
@Override protected void onDraw(Canvas canvas) {
yn = !yn;
pa.setColor(Color.WHITE);
canvas.drawRect(10, 10, 100, 100, pa);
pa.setColor(Color.YELLOW);
if(yn){ pa.setColor(Color.BLUE);
canvas.drawCircle(55, 55, 15, pa); }
else { pa.setColor(Color.RED);
canvas.drawRect(40, 40, 70, 70, pa);
}
}}
Step-4: 執行之。
3.3 說明:
1) 這MyView子類覆寫了onDraw()函數,創造了反向呼叫的機會。
2) 當咱們按下RadioButton時,就呼叫到MyView類的ReDraw()函數,進而呼叫到View的invalidate()函數。
3) 接着,就反向呼叫MyView子類的onDraw()函數,在UI畫面上繪出圖形來。這就是典型的「反向溝通」了。
4) 若是你沒有定義onDraw()函數的話,會執行View基類默認的onDraw()函數,而依據框架默認之慣例而行了。◆
ee ee
【思考Android技術】
請參考: Android從程序員到架構師之路課程(在線視頻學習)
請進入:ADT架構師學苑