使用Vitamio打造自己的Android万能播放器(11)—— 本地扫描后台服务

简介:

一、注意事项

本章节使用的是Vitamio 3.0(2012-11-07)请大家及时更新。

注意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;
    }

    @Override
     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();
        }
    }

    @Override
     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)) {
             try {
                 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;
        }
    }

    @Override
     public IBinder onBind(Intent intent) {
         return mBinder;
    }

}

代码说明:

1、默认Service是在主线程中运行的,扫描比较耗时,这里启用了一个新的线程。

2、使用了观察者模式来通知数据变化,没有用广播。

3、暂时去掉了截图,截图报错,还在修改。

三、OPlayer

3.1 下载
请移步#Taocode(SVN):(没有账户的请注册一个即可)
项目地址: http://code.taobao.org/p/oplayer
SVN地址: http://code.taobao.org/svn/oplayer/  

3.2 更新
a). 数据库层使用了ormlite框架。
b). 将扫描视频文件修改为后台服务,单独起了一个线程。

c). 整合Vitamio 3.0,修改反射为覆盖io.voo.vitamio.R。 

四、Vitamio

已建立Vitamio开发者联盟官方QQ群!群号为:246969281
注意:目前仅接受已经开发基于Vitamio产品的开发者申请加入,申请理由请填写产品的名称和链接!
官方微博:http://weibo.com/vitamio 

五、八卦

想在这里澄清一下OPlayer与VPlayer、Vitamio的关系:

1、OPlayer这个项目是跟公司没有关系,纯属于个人业余爱好作品。

2、OPlayer使用的是Vitamio,但不会比大家优先获取Vitamio的新版本。

3、OPlayer非官方示例。

本文转自博客园农民伯伯的博客,原文链接:使用Vitamio打造自己的Android万能播放器(11)—— 本地扫描后台服务,如需转载请自行联系原博主。


目录
相关文章
|
4月前
|
缓存 算法 Java
Linux内核新特性年终大盘点-安卓杀后台现象减少的背后功臣MGLRU算法简介
MGLRU是一种新型内存管理算法,它的出现是为了弥补传统LRU(Least Recently Used)和LFU(Least Frequently Used)算法在缓存替换选择上的不足,LRU和LFU的共同缺点就是在做内存页面替换时,只考虑内存页面在最近一段时间内被访问的次数和最后一次的访问时间,但是一个页面的最近访问次数少或者最近一次的访问时间较早,可能仅仅是因为这个内存页面新近才被创建,属于刚刚完成初始化的年代代页面,它的频繁访问往往会出现在初始化之后的一段时间里,那么这时候就把这种年轻代的页面迁移出去
|
3月前
|
开发工具 Android开发
Android平台RTMP推送|轻量级RTSP服务|GB28181设备接入模块之实时快照保存JPG还是PNG?
Android平台RTMP推送|轻量级RTSP服务|GB28181设备接入模块之实时快照保存JPG还是PNG?
|
3月前
|
数据采集 编解码 图形学
Android平台Unity下如何通过WebCamTexture采集摄像头数据并推送至RTMP服务器或轻量级RTSP服务
Android平台Unity下如何通过WebCamTexture采集摄像头数据并推送至RTMP服务器或轻量级RTSP服务
|
4月前
|
物联网 Android开发
Android Ble蓝牙App(七)扫描过滤
Android Ble蓝牙App(七)扫描过滤
|
4月前
|
XML 物联网 API
Android Ble蓝牙App(二)连接与发现服务
Android Ble蓝牙App(二)连接与发现服务
|
4月前
|
物联网 API Android开发
Android Ble蓝牙App(一)扫描(下)
Android Ble蓝牙App(一)扫描(下)
|
4月前
|
XML 物联网 Android开发
Android Ble蓝牙App(一)扫描(上)
Android Ble蓝牙App(一)扫描(上)
|
4月前
|
物联网 Android开发
【Android App】低功耗蓝牙中扫描BLE设备的讲解及实战(附源码和演示 超详细)
【Android App】低功耗蓝牙中扫描BLE设备的讲解及实战(附源码和演示 超详细)
88 0
|
4月前
|
Android开发 网络架构
【Android App】检查手机连接WiFi信息以及扫描周围WiFi的讲解及实战(附源码和演示 超详细必看)
【Android App】检查手机连接WiFi信息以及扫描周围WiFi的讲解及实战(附源码和演示 超详细必看)
147 1
|
4月前
|
XML 存储 Java
Android 开发音频录播中媒体录制器MediaRecorder和媒体播放器MediaPlayer的讲解及实战(超详细 附源码)
Android 开发音频录播中媒体录制器MediaRecorder和媒体播放器MediaPlayer的讲解及实战(超详细 附源码)
42 0