思考Android架構(二):像Android框架,如何(How-to)吸引開發者來使用它呢?

前言:Android平臺的核心是C/C++,爲了吸引更多App開發者來使用它,就在C/C++之上,增添一層Java框架,這框架的基類一方面提供接口(即抽像函數)來支持App開發者撰寫子類。這項接口的幕後,隱藏了默認函數(Default Function)及其複雜代碼,讓App開發者只要撰寫簡單的子類,就能繼承而調用這些默認函數,藉由簡單的接口調用,就能輕易叫出複雜的默認行爲(Default Behavior)。html

    抽象類的焦點在於抽象函數,它們的實做指令部份都是從缺的。因此該抽象類的子類『必須』補足這個欠缺,才能成爲一個具體類。這抽像函數是基類與子類二者相遇的地方,也就成爲二者的接口,又稱爲基類的API。不過,在上述文章裏,偏重於API的角色及其設計要點。但並未碰觸到應用開發者的心理層面:爲什麼應用開發者願意來使用框架及其API呢? 也就是說,框架開發者必須關心如何去吸引應用開發者來使用框架及其API。其解答之一是:在基類裏提供默認行爲。java


1.   基類接口隱藏了默認函數android

   剛纔提過了,抽象類裏的抽象函數,其實做指令部份都是從缺的。因此該抽象類的子類『必須』補足這個欠缺,才能成爲一個具體類。可知,子類開發者的負擔是蠻重的,框架設計能夠透過默認行吸引應用子類開發者。想想,若是將一些默認(Default)的實做部份加到抽象類裏,則其子類就可選擇要不要修正這個默認實做部份,這樣能夠減輕子類開發者的負擔。例以下述之範例: 程序員

11104513-321bea7e6c4c4181b975c4ccbcc7c84

其程序代碼以下: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);  

}}

此程序畫出兩隻海鷗以下圖:

11104443-f77876f3a5ec4224b6b6ebf270960d6

    其中的抽象類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 操做情境

  • 此程序一開始,畫面出現兩個按鈕以下:

11104816-27930a6b35d044c2b26069d770b235c

  • 若是按下<Exit>按鈕,程序就結束了。

2.2 撰寫步驟

Step-1: 創建Android項目:Fx02。

11104938-8bc339f6f4b34c11a777ee5fd1aff8d

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) 此程序執行時,呈現以下的畫面:

11105346-07401953d3964b23a465cfab60461da

2) 若是按下RadioButton,畫面就變換以下:

11105401-f60493ec7829478aacb63a0e43b4d1b

3) 若按下<Exit>按鈕,程序就結束了。


3.2 撰寫步驟:

Step-1: 創建Android應用程序項目:Fx03。

11105430-fd0348e16e8b4640b3a29126166dbac

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架構師學苑

相關文章
相關標籤/搜索