前言
vitamio和oplayer系列文章得到廣大同行的關注和支援,非常感謝!離系列文章的上篇有幾個月了,各種忙暫停了本系列文章,非常抱歉!離oplayer正式上線還有距離,還有很多要做的事情,繼續前行!
聲明
歡迎轉載,但請保留文章原始出處:)
部落格園:http://www.cnblogs.com
農民伯伯: http://over140.cnblogs.com
正文
一、注意事項
注意3.0整合的适合建議使用library方式整合vitamio,否則需要反射或者使用oplayer的方法,覆寫r(參見代碼)。
二、主要代碼:

/** 媒體掃描 */
public class mediascannerservice extends service implements runnable {
private static final string service_name = "com.nmbb.oplayer.service.mediascannerservice";
/** 掃描檔案夾 */
public static final string extra_directory = "scan_directory";
/** 掃描檔案 */
public static final string extra_file_path = "scan_file";
public static final string extra_mime_type = "mimetype";
public static final int scan_status_normal = -1;
/** 開始掃描 */
public static final int scan_status_start = 0;
/** 正在掃描 掃描到一個視訊檔案 */
public static final int scan_status_running = 1;
/** 掃描完成 */
public static final int scan_status_end = 2;
/** */
private arraylist<imediascannerobserver> observers = new arraylist<imediascannerobserver>();
private concurrenthashmap<string, string> mscanmap = new concurrenthashmap<string, string>();
/** 目前狀态 */
private volatile int mservicestatus = scan_status_normal;
private dbhelper<pomedia> mdbhelper;
private map<string, object> mdbwhere = new hashmap<string, object>(2);
@override
public void oncreate() {
super.oncreate();
mdbhelper = new dbhelper<pomedia>();
}
/** 是否正在運作 */
public static boolean isrunning() {
activitymanager manager = (activitymanager) oplayerapplication.getcontext().getsystemservice(context.activity_service);
for (runningserviceinfo service : manager.getrunningservices(integer.max_value)) {
if (service_name.equals(service.service.getclassname()))
return true;
}
return false;
public int onstartcommand(intent intent, int flags, int startid) {
if (intent != null)
parseintent(intent);
return super.onstartcommand(intent, flags, startid);
/** 解析intent */
private void parseintent(final intent intent) {
final bundle arguments = intent.getextras();
if (arguments != null) {
if (arguments.containskey(extra_directory)) {
string directory = arguments.getstring(extra_directory);
logger.i("onstartcommand:" + directory);
//掃描檔案夾
if (!mscanmap.containskey(directory))
mscanmap.put(directory, "");
} else if (arguments.containskey(extra_file_path)) {
//單檔案
string filepath = arguments.getstring(extra_file_path);
logger.i("onstartcommand:" + filepath);
if (!stringutils.isempty(filepath)) {
if (!mscanmap.containskey(filepath))
mscanmap.put(filepath, arguments.getstring(extra_mime_type));
// scanfile(filepath, arguments.getstring(extra_mime_type));
}
}
if (mservicestatus == scan_status_normal || mservicestatus == scan_status_end) {
new thread(this).start();
//scan();
public void run() {
scan();
/** 掃描 */
private void scan() {
//開始掃描
notifyobservers(scan_status_start, null);
while (mscanmap.keyset().size() > 0) {
string path = "";
for (string key : mscanmap.keyset()) {
path = key;
break;
if (mscanmap.containskey(path)) {
string mimetype = mscanmap.get(path);
if ("".equals(mimetype)) {
scandirectory(path);
} else {
scanfile(path, mimetype);
//掃描完成一個
mscanmap.remove(path);
//任務之間歇息一秒
try {
thread.sleep(1000);
} catch (interruptedexception e) {
logger.e(e);
//全部掃描完成
notifyobservers(scan_status_end, null);
//第一次掃描
opreference pref = new opreference(this);
if (pref.getboolean(oplayerapplication.pref_key_first, true))
pref.putbooleanandcommit(oplayerapplication.pref_key_first, false);
//停止服務
stopself();
private handler mhandler = new handler() {
@override
public void handlemessage(message msg) {
super.handlemessage(msg);
for (imediascannerobserver s : observers) {
if (s != null) {
s.update(msg.what, (pomedia) msg.obj);
};
private void scanfile(string path, string mimetype) {
save(new pomedia(path, mimetype));
private void scandirectory(string path) {
eachallmedias(new file(path));
/** 遞歸查找視訊 */
private void eachallmedias(file f) {
if (f != null && f.exists() && f.isdirectory()) {
file[] files = f.listfiles();
if (files != null) {
for (file file : f.listfiles()) {
// logger.i(f.getabsolutepath());
if (file.isdirectory()) {
//忽略.開頭的檔案夾
if (!file.getabsolutepath().startswith("."))
eachallmedias(file);
} else if (file.exists() && file.canread() && fileutils.isvideo(file)) {
save(new pomedia(file));
}
/**
* 儲存入庫
*
* @throws filenotfoundexception
*/
private void save(pomedia media) {
mdbwhere.put("path", media.path);
mdbwhere.put("last_modify_time", media.last_modify_time);
//檢測
if (!mdbhelper.exists(media, mdbwhere)) {
if (media.title != null && media.title.length() > 0)
media.title_key = pinyinutils.chinenetospell(media.title.charat(0) + "");
} catch (exception ex) {
logger.e(ex);
media.last_access_time = system.currenttimemillis();
//提取縮略圖
// extractthumbnail(media);
media.mime_type = fileutils.getmimetype(media.path);
//入庫
mdbhelper.create(media);
//掃描到一個
notifyobservers(scan_status_running, media);
/** 提取生成縮略圖 */
private void extractthumbnail(pomedia media) {
final context ctx = oplayerapplication.getcontext();
// thumbnailutils.
bitmap bitmap = thumbnailutils.createvideothumbnail(ctx, media.path, thumbnailutils.mini_kind);
try {
if (bitmap == null) {
//縮略圖建立失敗
bitmap = bitmap.createbitmap(thumbnailutils.target_size_mini_thumbnail_width, thumbnailutils.target_size_mini_thumbnail_height, bitmap.config.rgb_565);
media.width = bitmap.getwidth();
media.height = bitmap.getheight();
//縮略圖
bitmap = thumbnailutils.extractthumbnail(bitmap, convertutils.diptopx(ctx, thumbnailutils.target_size_micro_thumbnail_width), convertutils.diptopx(ctx, thumbnailutils.target_size_micro_thumbnail_height), thumbnailutils.options_recycle_input);
if (bitmap != null) {
//将縮略圖存到視訊目前路徑
file thum = new file(oplayerapplication.oplayer_video_thumb, uuid.randomuuid().tostring());
media.thumb_path = thum.getabsolutepath();
//thum.createnewfile();
fileoutputstream istream = new fileoutputstream(thum);
bitmap.compress(bitmap.compressformat.jpeg, 85, istream);
istream.close();
} catch (exception ex) {
logger.e(ex);
} finally {
if (bitmap != null)
bitmap.recycle();
// ~~~ 狀态改變
/** 通知狀态改變 */
private void notifyobservers(int flag, pomedia media) {
mhandler.sendmessage(mhandler.obtainmessage(flag, media));
/** 增加觀察者 */
public void addobserver(imediascannerobserver s) {
synchronized (this) {
if (!observers.contains(s)) {
observers.add(s);
/** 删除觀察者 */
public synchronized void deleteobserver(imediascannerobserver s) {
observers.remove(s);
/** 删除所有觀察者 */
public synchronized void deleteobservers() {
observers.clear();
public interface imediascannerobserver {
/**
*
* @param flag 0 開始掃描 1 正在掃描 2 掃描完成
* @param file 掃描到的視訊檔案
*/
public void update(int flag, pomedia media);
// ~~~ binder
private final mediascannerservicebinder mbinder = new mediascannerservicebinder();
public class mediascannerservicebinder extends binder {
public mediascannerservice getservice() {
return mediascannerservice.this;
public ibinder onbind(intent intent) {
return mbinder;
}

代碼說明:
1、預設service是在主線程中運作的,掃描比較耗時,這裡啟用了一個新的線程。
2、使用了觀察者模式來通知資料變化,沒有用廣播。
3、暫時去掉了截圖,截圖報錯,還在修改。
三、oplayer
3.1 下載下傳
請移步#taocode(svn):(沒有賬戶的請注冊一個即可)
3.2 更新
a). 資料庫層使用了ormlite架構。
b). 将掃描視訊檔案修改為背景服務,單獨起了一個線程。
c). 整合vitamio 3.0,修改反射為覆寫io.voo.vitamio.r。
四、vitamio
已建立vitamio開發者聯盟官方qq群!群号為:246969281
注意:目前僅接受已經開發基于vitamio産品的開發者申請加入,申請理由請填寫産品的名稱和連結!
五、八卦
想在這裡澄清一下oplayer與vplayer、vitamio的關系:
1、oplayer這個項目是跟公司沒有關系,純屬于個人業餘愛好作品。
2、oplayer使用的是vitamio,但不會比大家優先擷取vitamio的新版本。
3、oplayer非官方示例。
結束
更加深刻體會“堅持就是勝利”這句話的意義。
轉載:http://www.cnblogs.com/over140/archive/2012/11/07/2759241.html