ee ee
欢迎访问 ==>高老师的博客网页
高焕堂:MISOO(大数据.大思考)联盟.台北中心和东京(日本)分社.总教练
EE EE
前言:
成都创新互联长期为近1000家客户提供的网站建设服务,团队从业经验10年,关注不同地域、不同群体,并针对不同对象提供差异化的产品和服务;打造开放共赢平台,与合作伙伴共同营造健康的互联网生态环境。为丰满企业提供专业的网站设计制作、网站制作,丰满网站改版等技术服务。拥有10年丰富建站经验和众多成功案例,为您定制开发。
谁来诞生子类的对象呢?答案是:框架。这样让框架能有绝对的制约能力去「框住」应用子类的结构和行为。接着,请你来思考一个有趣的问题:
l框架开发者(强龙)先写框架基类的程序码;
l然后,AP开发者(地头蛇)才撰写应用子类在后。
那么框架开发者事先又如何知道地头蛇后来撰写的应用子类的名称呢?如果不知道应用子类的名称,又如何诞生应用子类的对象呢?
ee ee
欢迎访问 ==>高老师的博客网页
高焕堂:MISOO(大数据.大思考)联盟.台北中心和东京(日本)分社.总教练
EE EE
框架如何创建App子类的对象(二)?
--- 由基类创建亲生子类的对象
1. 以MediaPlayer播放mp3音乐为例
大家对于拿MediaPlayer来播放mp3音乐的应用程序,应该不会陌生。最简单的架构如下图所示:
图1、由myActivity来创建MediaPlayer的对象
你也可以设计一个包容器(Wrapper)类别来包装MediaPlayer类别,也就是由这个Wrapper来帮忙创建MediaPlayer对象,如下图所示:
图2、由Wrapper协助来创建MediaPlayer的对象
无论是在上图1或图2的架构里,你都是扮演一个传统的角色:AP开发者。于此,就来换个新鲜的角色:框架开发者。在上一篇文章里,已经说明了,必须让框架基类去创建应用子类的对象,才能让框架拥有高度的制约力量。在上一篇文章的范例里(即Ex04_01程序范例)已经实践了这个目标,让框架基类(如GraphView)来创建子类别(如myDrawing)的对象。其中,值得留意的是:上一篇文章范例里的基类GraphView并不是myDrawing的直系父类别(基类)。简而言之,myDrawing并不是继承GraphView基类。亦即,myDrawing并不是GraphView的亲生应用子类。
于是,在本文里,我们来看看一个基类如何创建亲生子类别的对象。如下图所示:
图3、由基类Player来创建亲生子类mp3Player的对象
大家都知道一个类别本身就是一个对象,我们常常称之为「母对象」(Meta-object),而类别的静态函数(static function)就是这个母对象的函数,在这种函数里可以(由该母对象)创建自己类别的对象。在上图的架构里,由myActivity创建Player基类的init()静态函数,这init()创建其亲生子类别mp3Player的对象。请留意,这init()会将mp3Player的IPlay接口传回给myActivity。一旦myActivity接到mp3Player的IPlay接口,就能进行实际的创建动作。也就是,myActivity透过IPlay接口,而创建到mp3Player的play()函数,并进而创建MediaPalyer的start()函数,展开了播放mp3音乐的动作了。[歡迎光臨 高煥堂 網頁: http://www.cnblogs.com/myEIT/ ]
2. 框架的设计与实践
2.1 复习:擅用配置文文件
在上一篇文章里,运用了配置(Configuration)文件的机制来实践由框架(的基类)来创建应用(AP或App)子类的对象的任务,这是框架开发的基本技巧。其主要面对的情境是:框架基类由强龙设计在先,而应用子类则由地头蛇开发在后。也就是说,当强龙撰写框架基类时,地头蛇(和客户)都尚未出现,基类开发者还不知道AP子类的名称,那么又如何去<
图4、由子类开发者撰写配置(Configuration)文件
因此,解决之道是:请地头蛇撰写完AP子类时,也将子类的名称字符串(classname string)写入一个特定的配置(Configuration)文件里,然后于程序执行时,才去读取配置文文件里的子类的名称字符串,然后透过Java的指令:
Class.forName(classname).newInstance();
就能创建该AP子类的对象了。于是,实践了由框架创建AP子类对象的任务了。
2.2 设计架构图
基于上述配置文文件的机制,也依循上一篇文章范例的架构,兹绘制架构图如下:
图6、由基类创建子类对象的过程
创建完成子类对象之后,就能够透过接口来调用该子类对象的函数了。例如,myActivity就透过IPlay而调用mp3Player的play()函数,此刻myActivity就调用MediaPlayer的start()函数,开始播放了。如下图:
图7、调用所创建的新对象
结束播放时,myActivity就透过IPlay而调用了mp3Player的stop()函数,此刻myActivity就调用MediaPlayer的stop()函数了。
2.3 撰写代码:<创建对象>的实践途径
兹将上图落实为Android代码,其执行画面如下:
首先建立一个Android的Ex04_02项目(Project),如下:
背景图像sunrise.png存在/res里。
撰写你的框架基类和API
// Player.java
package myFramework;
import android.content.Context;
public abstract class Player {
static private Player player = null;
public static IPlay init(Context context){
String pkclassName = ((PActivity)context).getPlayerClass();
try {
player = (Player)Class.forName(pkclassName).newInstance();
return (IPlay)player;
} catch (Exception e)
{e.printStackTrace(); }
return null;
}
}
// PActivity.java
package myFramework;
import com.misoo.pk003.R;
import android.app.Activity;
public abstract class PActivity extends Activity{
public IPlay init(){
return Player.init(this);
}
public String getPlayerClass(){
return this.getResources().getString(R.string.playerclass);
}
}
// IPlay.java
package myFramework;
import android.content.Context;
public interface IPlay {
void play(Context context);
void stop();
}
把基类和API送人,协助别人去开发应用子类
// mp3Player.java
package com.misoo.pk003;
import myFramework.IPlay;
import myFramework.Player;
import android.content.Context;
import android.media.MediaPlayer;
import android.util.Log;
public class mp3Player extends Player implements IPlay{
private MediaPlayer mPlayer = null;
public void play(Context context) {
try{
mPlayer = MediaPlayer.create(context, R.raw.dreamed);
mPlayer.start();
} catch (Exception e) {
Log.e("StartPlay", "error: " + e.getMessage(), e);
}
}
public void stop(){
if (mPlayer != null) {
mPlayer.stop(); mPlayer.release(); mPlayer = null;
}
}}
// myActivity.java
package com.misoo.pk003;
import myFramework.IPlay;
import myFramework.PActivity;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.LinearLayout;
public class myActivity extends PActivity implements OnClickListener{
private Button ibtn1, ibtn2;
private IPlay player;
@Overrideprotected void onCreate(Bundle icicle) {
super.onCreate(icicle);
LinearLayout layout = new LinearLayout(this);
layout.setOrientation(LinearLayout.VERTICAL);
ibtn1 = new Button(this); ibtn1.setOnClickListener(this);
ibtn1.setText("Play"); ibtn1.setBackgroundResource(R.drawable.heart);
LinearLayout.LayoutParams param1 =
new LinearLayout.LayoutParams(150, 65);
param1.topMargin = 10; param1.leftMargin = 10;
layout.addView(ibtn1, param1);
ibtn2 = new Button(this); ibtn2.setOnClickListener(this);
ibtn2.setText("Exit"); ibtn2.setBackgroundResource(R.drawable.mountain);
layout.addView(ibtn2, param1);
setContentView(layout);
//-----------------------------------------------
player = init();
}
public void onClick(View v) {
if(v == ibtn1) {
setTitle("playing...");
player.play(this);
}
else {
player.stop();
finish();
}
}
3. 结语
由框架(的基类)来创建应用(AP或App)子类的对象是框架开发的基本技巧。因为框架必需掌握重要对象的运行生命周期(Life-cycle)才能有效控制对象的行为,以及取重要的信息传递机制和内容。如此,框架就能有效<框住>数以万计的应用程序,而不会失控了。◆