Android开源项目-Jamendo音乐播放器研究与优化-基于Builder模式的数据库操作

【一个音符的时值按二等分的原则,成偶数细分下去,称为音符时值的基本划分】

--- 《五线谱基础教程》


对于一个完整的应用来说,数据库操作往往是避免不了的,Jamendo基于生成器模式(Builder Pattern)构建数据库操作的整个框架。那么首先看下生成器模式的定义:将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。

典型结构图如下所示:

Android开源项目-Jamendo音乐播放器研究与优化-基于Builder模式的数据库操作_第1张图片

主要涉及四个角色,分别是:

1)Builder:生成器接口,定义创建一个Product对象所需的各个部件的操作;

2)ConcreteBuilder:具体的生成器实现,实现各个部件的创建,并负责组装Product对象的各个部件,同时提供给用户一个获取组装完成后的Product对象的方法;

3)Director:指导者,主要用于调用Builder接口,以一个统一的过程来构建所需的Product对象;

4)Product:产品,表示被生成器创建的复杂对象,包含各个部件。

接下来看下Jamendo中怎样使用Builder模式实现数据库相关操作:


一 Builder角色

Jamendo中Builder角色由DatabaseBuilder来充当,由于Product对象类型有多种,所以使用泛型表示,如下所示,该抽象类中定义了两个接口,是一个相反的过程,分别是由数据库游标Cursor对象创建出Product对象,以及从Product对象构造出适合数据库操作的ContentValues对象。

public abstract class DatabaseBuilder<T> {

	// 根据传入的Cursor对象构建Product对象
	public abstract T build(Cursor c);

	// 和build方法相反的过程,从Product对象得到适合数据库操作的ContentValues对象
	public abstract ContentValues deconstruct(T t);

}

二 ConcreteBuilder角色以及Product角色

在Eclipse的Type Hierarchy视图中可以看出ConcreteBuilder角色有四个,如图所示:

下面重点结合音乐播放的业务逻辑分别进行介绍:


1)TrackDatabaseBuilder类和Track产品类

Track类维护专辑的音轨信息,主要包括ID、名称、持续时间、歌词链接、数据流链接、评分、序号等信息,如下图所示:

Android开源项目-Jamendo音乐播放器研究与优化-基于Builder模式的数据库操作_第2张图片

TrackDatabaseBuilder类的职责就是将Track产品类的信息和数据库关联起来,如代码所示:

/**
 * 音轨信息的数据库生成类
 *
 */
public class TrackDatabaseBuilder extends DatabaseBuilder<Track> {

	private static final String TRACK_ID = "track_id"; // ID

	private static final String TRACK_NAME = "track_name"; // 名称

	private static final String TRACK_DURATION = "track_duration"; // 持续时间

	private static final String TRACK_URL = "track_url"; // 歌词的链接

	private static final String TRACK_STREAM = "track_stream"; // 数据流的链接

	private static final String TRACK_RATING = "track_rating"; // 评分

	private static final String ALBUM_TRACK_NUM = "album_track_num"; // 序号

	@Override
	public Track build(Cursor query) {
		int columnName = query.getColumnIndex(TRACK_NAME);
		int columnStream = query.getColumnIndex(TRACK_STREAM);
		int columnUrl = query.getColumnIndex(TRACK_URL);
		int columnDuration = query.getColumnIndex(TRACK_DURATION);
		int columnId = query.getColumnIndex(TRACK_ID);
		int columnRating = query.getColumnIndex(TRACK_RATING);
		int columnAlbumTrackNum = query.getColumnIndex(ALBUM_TRACK_NUM);

		Track track = new Track();
		track.setDuration(query.getInt(columnDuration));
		track.setId(query.getInt(columnId));
		track.setName(query.getString(columnName));
		track.setRating(query.getDouble(columnRating));
		track.setStream(query.getString(columnStream));
		track.setUrl(query.getString(columnUrl));
		track.setNumAlbum(query.getInt(columnAlbumTrackNum));
		return track;
	}

	@Override
	public ContentValues deconstruct(Track track) {
		ContentValues values = new ContentValues();
		values.put(TRACK_NAME, track.getName());
		values.put(TRACK_STREAM, track.getStream());
		values.put(TRACK_URL, track.getUrl());
		values.put(TRACK_DURATION, track.getDuration());
		values.put(TRACK_ID, track.getId());
		values.put(TRACK_RATING, track.getRating());
		values.put(ALBUM_TRACK_NUM, track.getNumAlbum());
		return values;
	}
}

2)AlbumDatabaseBuilder类和Album产品类

Album类表示专辑对象,主要包括专辑ID、专辑名称、专辑的封面、专辑的评分、艺术家的名称以及专辑的曲目,类定义的截图如下所示:


AlbumDatabaseBuilder类的职责就是继承DatabaseBuilder类,将上述Album类的主要信息存储到数据库中,实现数据库相关操作,如下代码所示:

/**
 * 专辑的数据库生成器类
 */
public class AlbumDatabaseBuilder extends DatabaseBuilder<Album> {

	private static final String ALBUM_ID = "album_id"; // 专辑ID

	private static final String ALBUM_NAME = "album_name"; // 专辑的名称

	private static final String ALBUM_IMAGE = "album_image"; // 专辑的封面

	private static final String ALBUM_RATING = "album_rating"; // 专辑的星级

	private static final String ARTIST_NAME = "artist_name"; // 艺术家的名字

	@Override
	public Album build(Cursor query) {
		int columnArtistName = query.getColumnIndex(ARTIST_NAME);
		int columnName = query.getColumnIndex(ALBUM_NAME);
		int columnImage = query.getColumnIndex(ALBUM_IMAGE);
		int columnId = query.getColumnIndex(ALBUM_ID);
		int columnRating = query.getColumnIndex(ALBUM_RATING);

		Album album = new Album();
		album.setId(query.getInt(columnId));
		album.setArtistName(query.getString(columnArtistName));
		album.setName(query.getString(columnName));
		album.setRating(query.getDouble(columnRating));
		album.setImage(query.getString(columnImage));
		return album;
	}

	@Override
	public ContentValues deconstruct(Album album) {
		ContentValues values = new ContentValues();
		values.put(ARTIST_NAME, album.getArtistName());
		values.put(ALBUM_IMAGE, album.getImage());
		values.put(ALBUM_NAME, album.getName());
		values.put(ALBUM_ID, album.getId());
		values.put(ALBUM_RATING, album.getRating());
		return values;
	}
}

3)RadioDatabaseBuilder类和Radio产品类

Radio类表示广播收音相关的信息,主要是ID、名称和对应的图像标识,代码如图所示:

Android开源项目-Jamendo音乐播放器研究与优化-基于Builder模式的数据库操作_第3张图片

RadioDatabaseBuilder类的实现方式跟上面几种类似,直接看代码:

/**
 * 广播信息的数据库生成类
 *
 */
public class RadioDatabaseBuilder extends DatabaseBuilder<Radio> {
	
	private static final String RADIO_ID = "radio_id"; // 广播ID
	
	private static final String RADIO_IDSTR = "radio_idstr"; // 广播ID的字符串形式
	
	private static final String RADIO_NAME = "radio_name"; // 广播的名称
	
	private static final String RADIO_IMAGE = "radio_image"; // 广播的图像标识
	
	private static final String RADIO_DATE = "radio_date"; // 广播信息的存库时间

	@Override
	public Radio build(Cursor query) {
		int columnId = query.getColumnIndex(RADIO_ID);
		int columnIdstr = query.getColumnIndex(RADIO_IDSTR);
		int columnName = query.getColumnIndex(RADIO_NAME);
		int columnImage = query.getColumnIndex(RADIO_IMAGE);
		
		Radio radio = new Radio();
		radio.setId(query.getInt(columnId));
		radio.setIdstr(query.getString(columnIdstr));
		radio.setImage(query.getString(columnImage));
		radio.setName(query.getString(columnName));
		return radio;
	}

	@Override
	public ContentValues deconstruct(Radio radio) {
		ContentValues values = new ContentValues();
		values.put(RADIO_ID, radio.getId());
		values.put(RADIO_IDSTR, radio.getIdstr());
		values.put(RADIO_NAME, radio.getName());
		values.put(RADIO_IMAGE, radio.getImage());
		values.put(RADIO_DATE, System.currentTimeMillis());
		return values;
	}
}

4)DownloadJobBuilder类和DownloadJob产品类

DownloadJob产品类跟之前的三个产品类不大一样,它不是纯粹的包含数据库信息,还维护了下载相关的信息,本文只分析数据库相关部分,下载部分放到后面文章分析。如下图所示,DownloadJob类中和数据库相关的只有其中的PlaylistEntry:

Android开源项目-Jamendo音乐播放器研究与优化-基于Builder模式的数据库操作_第4张图片

PlaylistEntry类是对Album类和Track类的简单封装,对外体现为播放列表信息类,定义如下所示:


DownloadJobBuilder类自然就是负责构建与反构建DownloadJob中的PlaylistEntruy信息部分,代码如下:

/**
 * 下载信息的数据库生成类
 *
 */
public class DownloadJobBuilder extends DatabaseBuilder<DownloadJob> {

	private static final String DOWNLOADED = "downloaded"; // 是否下载完成标志位(下载完成-1,下载未完成-0)

	@Override
	public DownloadJob build(Cursor query) {
		Track track = new TrackDatabaseBuilder().build(query);
		Album album = new AlbumDatabaseBuilder().build(query);

		// 封装成播放列表类
		PlaylistEntry pEntry = new PlaylistEntry();
		pEntry.setAlbum(album);
		pEntry.setTrack(track);

		DownloadJob dJob = new DownloadJob(pEntry,DownloadHelper.getDownloadPath(), 
				0, JamendoApplication.getInstance().getDownloadFormat());
		
		// 查询下载进度
		int progress = query.getInt(query.getColumnIndex(DOWNLOADED));
		if (progress == 1) {
			dJob.setProgress(100);
		}
		return dJob;
	}

	@Override
	public ContentValues deconstruct(DownloadJob t) {
		ContentValues values = new ContentValues();

		values.putAll(new TrackDatabaseBuilder().deconstruct(t
				.getPlaylistEntry().getTrack()));
		values.putAll(new AlbumDatabaseBuilder().deconstruct(t
				.getPlaylistEntry().getAlbum()));
		values.put(DOWNLOADED, (t.getProgress() == 100) ? 1 : 0);

		return values;
	}

}

三 Director角色

Director角色调用Builder角色提供的接口,以统一的方式来构建所需要的Product角色,Jamendo中操作数据库Builder角色的Director角色有两个,分别是DatabaseImpl类和DownloadDatabaseImpl类,类图如下所示:


其中DatabaseImpl类是AlbumDatabaseBuilder、TrackDatabaseBuilder和RadioDatabaseBuilder类的指导者;

DownloadDatabaseImpl类是AlbumDatabaseBuilder和TrackDatabaseBuilder和DownloadJobBuilder类的指导者。

下面简单看下DatabaseImpl中调用Builder角色类的部分代码:

Android开源项目-Jamendo音乐播放器研究与优化-基于Builder模式的数据库操作_第5张图片




你可能感兴趣的:(数据库,优化,android,String,音乐,数据库相关)