1、11.Android 的类别继承与委托之范例1.1 类别继承的副作用继承和委托皆能达到对象再用之目的,各有所长各有所短,相辅相成才是完美的。如下述类别:在 New Collegiate 字典上对正方形的定义是:正方形是一种 4 边等长的长方形所以使用继承如下:然而,上述的实作继承却有些缺点,宜避免之。例如,Square 从 Rectangle 继承了setLength()和 setWidth()函数,但这两个函数对于 Square 而言是无意义且有害的。因之,上述的继承关系是不良的。至于如何改善上述的继承关系呢?可改用委托:当 Square 之对象接到外界传来的 area()讯息时,就委托 R
2、ectangle 之对象代为处理。虽然委托会令程序复杂些,但勉强使用继承,后遗症将更大。因为副作用可能会延续到Rectangle 的各子孙类别!1.2 Android 的继承与委托之例兹以 Android 里的 MediaPlayer 类别为例。1.2.1 操作情境:1. 此程序开始执行后,出现画面如下:2. 按下,就开始播放 MP3 音乐。3. 若按下,就结束播放音乐。4. 若按下,程序就结束了。1.2.2 范例程序(1):采单纯继承方法1.2.2.1 撰写步骤:Step-1: 建立 Android 项目:Px01。Step-2: 撰写 Activity 的子类别:ac01,其程序代码如下:
3、/* ac01.java */package com.misoo.pkzz;import android.app.Activity;import android.graphics.Color;import android.media.MediaPlayer;import android.os.Bundle;import android.view.View;import android.view.View.OnClickListener;import android.widget.LinearLayout;import android.widget.TextView;public class a
4、c01 extends Activity implements OnClickListener private final int WC = LinearLayout.LayoutParams.WRAP_CONTENT; private final int FP = LinearLayout.LayoutParams.FILL_PARENT; private MediaPlayer mPlayer;private myButton btn, btn2, btn3;public TextView tv;public void onCreate(Bundle icicle) super.onCre
5、ate(icicle);LinearLayout layout = new LinearLayout(this);layout.setOrientation(LinearLayout.VERTICAL);btn = new myButton(this);btn.setId(101);btn.setText(“play“);btn.setOnClickListener(this);LinearLayout.LayoutParams param = new LinearLayout.LayoutParams(btn.get_width(), btn.get_height(); param.topM
6、argin = 10;layout.addView(btn, param); btn2 = new myButton(this);btn2.setId(102);btn2.setText(“stop“);btn2.setOnClickListener(this);layout.addView(btn2, param);btn3 = new myButton(this);btn3.setId(103);btn3.setText(“exit“);btn3.setOnClickListener(this);layout.addView(btn3, param);tv = new TextView(t
7、his);tv.setTextColor(Color.WHITE);tv.setText(“Ready“);LinearLayout.LayoutParams param2 = new LinearLayout.LayoutParams(FP, WC); param2.topMargin = 10;layout.addView(tv, param2);setContentView(layout); /-myMediaPlayer my_player = new myMediaPlayer();mPlayer = my_player.create(this, R.raw.test_cbr);pu
8、blic void onClick(View v) switch(v.getId()case 101:mPlayer.start();break;case 102:mPlayer.stop();break;case 103:finish();break;Step-3: 撰写 myMediaPlayer 类别,其程序代码如下:/* myMediaPlayer.java */package com.misoo.pkzz;import android.content.Context;import android.media.MediaPlayer;public class myMediaPlayer
9、 extends MediaPlayer public static MediaPlayer create(Context context)return MediaPlayer.create(context, R.raw.test_cbr);Step-4: 撰写 Button 的子类别:myButton,其程序代码如下:/* myButton.java */package com.misoo.pkcc;import android.content.Context;import android.widget.Button;public class myButton extends Button
10、public myButton(Context ctx)super(ctx);super.setBackgroundResource(R.drawable.heart);public int get_width()return 80;public int get_height()return 50;Step-5: 执行之。1.2.2.2 说明:在 ac01 类别的指令:myMediaPlayer my_player = new myMediaPlayer();mPlayer = my_player.create(this, R.raw.test_cbr);所传回来的是 MediaPlayer
11、类别之对象参考(即 mPlayer 的值),而不是 myMediaPlayer类别的对象参考。既然是 MediaPlayer 类别之对象参考,则外界的类别或函数(如 ac01类别)就能透过 mPlayer 参考(即使用 MediaPlayer 接口)来使用此新诞生的 MediaPlayer类别之对象了,如下图:虽然在 my_player 对象里也有一个 MediaPlayer 的小对象,但是 mPlayer 并不是参考到它,而是参考到由 create()函数所诞生的心对象。1.2.3 范例程序(2):采继承与委托混合型1.2.3.1 撰写步骤:Step-1: 建立 Android 项目:Px0
12、2。Step-2: 撰写 Activity 的子类别:ac01,其程序代码如下:/* ac01.java */package com.misoo.pkzz;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;import android.widget.TextView;public
13、class ac01 extends Activity implements OnClickListener private final int WC = LinearLayout.LayoutParams.WRAP_CONTENT; private final int FP = LinearLayout.LayoutParams.FILL_PARENT; private myMediaPlayer my_player;private myButton btn, btn2, btn3;public TextView tv;public void onCreate(Bundle icicle)
14、super.onCreate(icicle);LinearLayout layout = new LinearLayout(this);layout.setOrientation(LinearLayout.VERTICAL);btn = new myButton(this);btn.setId(101);btn.setText(“play“);btn.setOnClickListener(this);LinearLayout.LayoutParams param = new LinearLayout.LayoutParams(btn.get_width(), btn.get_height();
15、 param.topMargin = 10;layout.addView(btn, param); btn2 = new myButton(this);btn2.setId(102);btn2.setText(“stop“);btn2.setOnClickListener(this);layout.addView(btn2, param);btn3 = new myButton(this);btn3.setId(103);btn3.setText(“exit“);btn3.setOnClickListener(this);layout.addView(btn3, param);tv = new
16、 TextView(this);tv.setTextColor(Color.WHITE);tv.setText(“Ready“);LinearLayout.LayoutParams param2 = new LinearLayout.LayoutParams(FP, WC); param2.topMargin = 10;layout.addView(tv, param2);setContentView(layout); /-my_player = myMediaPlayer.create(this);public void onClick(View v) switch(v.getId()cas
17、e 101:my_player.start();break;case 102:my_player.stop();break;case 103:finish();break;Step-3: 撰写 myMediaPlayer 类别,其程序代码如下:/* myMediaPlayer.java */package com.misoo.pkzz;import android.app.Activity;import android.content.Context;import android.media.MediaPlayer;import android.util.Log;public class my
18、MediaPlayer extends MediaPlayer private static MediaPlayer mSuper;private static Context ctx;public static myMediaPlayer create(Context context)ctx = context;mSuper = MediaPlayer.create(context, R.raw.test_cbr);return new myMediaPlayer();public void start()trymSuper.start();(ac01)ctx).tv.setText(“Pl
19、aying audio.“);(Activity)ctx).setTitle(“MP3 Music“); catch (Exception e) Log.e(“StartPlay“, “error: “ + e.getMessage(), e);public void stop()if (mSuper != null) (ac01)ctx).tv.setText(“Stop“);mSuper.stop();mSuper.release();mSuper = null;Step-4: 撰写 Button 的子类别:myButton,其程序代码如下:/* myButton.java */packa
20、ge com.misoo.pkcc;import android.content.Context;import android.widget.Button;public class myButton extends Button public myButton(Context ctx)super(ctx);super.setBackgroundResource(R.drawable.heart);public int get_width()return 80;public int get_height()return 50;Step-5: 执行之。1.2.3.2 说明:在 ac01 对象里的
21、my_player 是参考到 myMediaPlayer 的对象,此对象里 mSuper 再参考到 MediaPlayer 的对象,如下图:在 ac01 类别里的指令: my_player.start();是呼叫到 myMediaPlayer 子类别的 start()函数,然后才委托呼叫 MediaPlayer 的 start()函数。此时,可看到继承的副作用了,就是:myMediaPlayer 继承了众多函数,并无法透过 my_palyer 去呼叫之,甚至可能是有害的。因此宜改用下一小节的单纯委托方法。1.2.4 范例程序(3):采单纯委托方法1.2.4.1 撰写步骤:Step-1: 建立
22、Android 项目:Px03。Step-2: 撰写 Activity 的子类别:ac01,其程序代码如下:/* ac01.java */package com.misoo.pkcc;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;import android.widget.Te
23、xtView;public class ac01 extends Activity implements OnClickListener private final int WC = LinearLayout.LayoutParams.WRAP_CONTENT; private final int FP = LinearLayout.LayoutParams.FILL_PARENT; private mp3Player mp3_player;private myButton btn, btn2, btn3;public TextView tv;public void onCreate(Bund
24、le icicle) super.onCreate(icicle);mp3_player = new mp3Player(this);LinearLayout layout = new LinearLayout(this);layout.setOrientation(LinearLayout.VERTICAL);btn = new myButton(this);btn.setId(101);btn.setText(“play“);btn.setOnClickListener(this);LinearLayout.LayoutParams param = new LinearLayout.Lay
25、outParams(btn.get_width(), btn.get_height(); param.topMargin = 10;layout.addView(btn, param); btn2 = new myButton(this);btn2.setId(102);btn2.setText(“stop“);btn2.setOnClickListener(this);layout.addView(btn2, param);btn3 = new myButton(this);btn3.setId(103);btn3.setText(“exit“);btn3.setOnClickListene
26、r(this);layout.addView(btn3, param);tv = new TextView(this);tv.setTextColor(Color.WHITE);tv.setText(“Ready“);LinearLayout.LayoutParams param2 = new LinearLayout.LayoutParams(FP, WC); param2.topMargin = 10;layout.addView(tv, param2);setContentView(layout); public void onClick(View v) switch(v.getId()
27、case 101: mp3_player.start(); break;case 102: mp3_player.stop(); break;case 103: finish(); break;Step-3: 撰写 mp3Player 类别,其程序代码如下:/* mp3Player.java */package com.misoo.pkcc;import android.app.Activity;import android.content.Context;import android.media.MediaPlayer;import android.util.Log;public class
28、 mp3Player private MediaPlayer mPlayer;private Context ctx; public mp3Player(Context context)ctx = context;mPlayer = MediaPlayer.create(ctx, R.raw.test_cbr);public void start()trymPlayer.start();(ac01)ctx).tv.setText(“Playing audio.“);(Activity)ctx).setTitle(“MP3 Music“); catch (Exception e) Log.e(“
29、StartPlay“, “error: “ + e.getMessage(), e);public void stop()if (mPlayer != null) (ac01)ctx).tv.setText(“Stop“);mPlayer.stop();mPlayer.release();mPlayer = null;Step-4: 撰写 Button 的子类别:myButton,其程序代码如下:/* myButton.java */package com.misoo.pkcc;import android.content.Context;import android.widget.Button;public class myButton extends Button public myButton(Context ctx)super(ctx);super.setBackgroundResource(R.drawable.heart);