天天看點

Android開源項目-Jamendo音樂播放器研究與優化-基于Builder模式的資料庫操作

【一個音符的時值按二等分的原則,成偶數細分下去,稱為音符時值的基本劃分】

--- 《五線譜基礎教程》

對于一個完整的應用來說,資料庫操作往往是避免不了的,Jamendo基于生成器模式(Builder Pattern)建構資料庫操作的整個架構。那麼首先看下生成器模式的定義:将一個複雜對象的建構與它的表示分離,使得同樣的建構過程可以建立不同的表示。

典型結構圖如下所示:

Android開源項目-Jamendo音樂播放器研究與優化-基于Builder模式的資料庫操作

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

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角色有四個,如圖所示:

Android開源項目-Jamendo音樂播放器研究與優化-基于Builder模式的資料庫操作

下面重點結合音樂播放的業務邏輯分别進行介紹:

1)TrackDatabaseBuilder類和Track産品類

Track類維護專輯的音軌資訊,主要包括ID、名稱、持續時間、歌詞連結、資料流連結、評分、序号等資訊,如下圖所示:

Android開源項目-Jamendo音樂播放器研究與優化-基于Builder模式的資料庫操作

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、專輯名稱、專輯的封面、專輯的評分、藝術家的名稱以及專輯的曲目,類定義的截圖如下所示:

Android開源項目-Jamendo音樂播放器研究與優化-基于Builder模式的資料庫操作

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模式的資料庫操作

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:

PlaylistEntry類是對Album類和Track類的簡單封裝,對外展現為播放清單資訊類,定義如下所示:

Android開源項目-Jamendo音樂播放器研究與優化-基于Builder模式的資料庫操作

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類,類圖如下所示:

Android開源項目-Jamendo音樂播放器研究與優化-基于Builder模式的資料庫操作

其中DatabaseImpl類是AlbumDatabaseBuilder、TrackDatabaseBuilder和RadioDatabaseBuilder類的指導者;

DownloadDatabaseImpl類是AlbumDatabaseBuilder和TrackDatabaseBuilder和DownloadJobBuilder類的指導者。

下面簡單看下DatabaseImpl中調用Builder角色類的部分代碼:

Android開源項目-Jamendo音樂播放器研究與優化-基于Builder模式的資料庫操作