使用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)—— 本地扫描后台服务,如需转载请自行联系原博主。


目录
相关文章
|
18天前
|
Java API 调度
Android系统 自定义开机广播,禁止后台服务,运行手动安装应用接收开机广播
Android系统 自定义开机广播,禁止后台服务,运行手动安装应用接收开机广播
41 0
|
19天前
|
Android开发
Android 11 添加Service服务SELinux问题
Android 11 添加Service服务SELinux问题
42 1
|
4天前
|
缓存 Java Android开发
Android 9.0 WiFi 扫描结果上报和获取流程
Android 9.0 WiFi 扫描结果上报和获取流程
7 0
|
11天前
|
安全 网络安全 Android开发
云端防御策略:融合云服务与网络安全的未来构建高效的Android应用:从内存优化到电池寿命
【4月更文挑战第30天】 随着企业加速向云计算环境转移,数据和服务的云端托管成为常态。本文探讨了在动态且复杂的云服务场景下,如何构建和实施有效的网络安全措施来保障信息资产的安全。我们将分析云计算中存在的安全挑战,并展示通过多层次、多维度的安全框架来提升整体防护能力的方法。重点关注包括数据加密、身份认证、访问控制以及威胁检测与响应等关键技术的实践应用,旨在为读者提供一种结合最新技术进展的网络安全策略视角。 【4月更文挑战第30天】 在竞争激烈的移动市场中,Android应用的性能和资源管理已成为区分优秀与平庸的关键因素。本文深入探讨了提升Android应用效率的多个方面,包括内存优化策略、电池
|
4月前
|
开发工具 Android开发
Android平台RTMP推送|轻量级RTSP服务|GB28181设备接入模块之实时快照保存JPG还是PNG?
Android平台RTMP推送|轻量级RTSP服务|GB28181设备接入模块之实时快照保存JPG还是PNG?
|
4月前
|
数据采集 编解码 图形学
Android平台Unity下如何通过WebCamTexture采集摄像头数据并推送至RTMP服务器或轻量级RTSP服务
Android平台Unity下如何通过WebCamTexture采集摄像头数据并推送至RTMP服务器或轻量级RTSP服务
115 0
|
5月前
|
物联网 Android开发
Android Ble蓝牙App(七)扫描过滤
Android Ble蓝牙App(七)扫描过滤
|
5月前
|
XML 物联网 API
Android Ble蓝牙App(二)连接与发现服务
Android Ble蓝牙App(二)连接与发现服务