zoukankan      html  css  js  c++  java
  • Android四大组件之Service(续)

    本地服务启动和通过广播的方式回调是非常简单的。

    下面介绍远程服务和通过远程回调的方式通知activity的方式。

    1.service定义:

    package com.joyfulmath.globalsearch.imagesearch.service;
    
    import java.util.ArrayList;
    
    import com.joyfulmath.globalsearch.imagesearch.service.aidl.IBuildService;
    import com.joyfulmath.globalsearch.imagesearch.service.aidl.ICallBack;
    import com.joyfulmath.globalsearch.imagesearch.service.aidl.PersonImageItem;
    
    import android.app.Service;
    import android.content.Intent;
    import android.os.IBinder;
    import android.os.RemoteCallbackList;
    import android.os.RemoteException;
    import android.util.Log;
    
    /*
     * image operator running in service thread and listener the contentobserver
     * */
    public class ImageSearchBuildService extends Service implements onServiceEngineListener{
        private static final String TAG = "ImageSearch.BuildService";
    
        public final static String ACTION = "com.joyfulmath.intent.imagesearch.BUILD_IMAGE";
        public final static String ACTION_METHOD = "action.method";
        public final static String ACTION_REBUILD_DB = "action.rebuild.db";
        
        private ImageSearchOperator mImageSearchOperator = null;
        private ImageSearchBuildServiceImpl iServiceImpl = null;
        private RemoteCallbackList<ICallBack> mCallbacks = new RemoteCallbackList<ICallBack>();
        private long mCurrentCookie = -1;
        @Override
        public IBinder onBind(Intent intent) {
            mCurrentCookie = intent.getLongExtra("cookie",-1);
            Log.i(TAG, "[onBind] mCurrentCookie:"+mCurrentCookie);
            iServiceImpl = new ImageSearchBuildServiceImpl(mImageSearchOperator);
            return iServiceImpl;
        }
    
        @Override
        public void onCreate() {
            Log.i(TAG, "[onCreate]");
            super.onCreate();
            mImageSearchOperator = new ImageSearchOperator(this,this);
            mImageSearchOperator.startOperatorThread();
        }
    
        @Override
        public void onDestroy() {
            Log.i(TAG, "[onDestroy]");
            super.onDestroy();
            if(mImageSearchOperator!=null)
            {
                mImageSearchOperator.exitOperatorThread();
            }
            iServiceImpl = null;
        }
    
        @Override
        public int onStartCommand(Intent intent, int flags, int startId) {
            Log.i(TAG, "[onStartCommand]");
            String method = intent.getStringExtra(ACTION_METHOD);
            if(method!=null)
            {
                if(method.equals(ACTION_REBUILD_DB))
                {
                    //start rebuild db
                    mImageSearchOperator.rebuildImageSearchDbHandle();
                }
            }
            
            return Service.START_NOT_STICKY;
        }
    
        @Override
        public boolean onUnbind(Intent intent) {
            Log.i(TAG, "[onUnbind]");
            if(mImageSearchOperator!=null)
            {
                mImageSearchOperator.abortFindPersonHandle();
            }
            
            return super.onUnbind(intent);
        }
        
        private class ImageSearchBuildServiceImpl extends IBuildService.Stub{
    
            public ImageSearchOperator mOperator = null;
            public ImageSearchBuildServiceImpl(ImageSearchOperator operator)
            {
                mOperator = operator;
            }
            
            @Override
            public int getServiceStatus() throws RemoteException {
                return mOperator.mOperatorStatus;
            }
    
            @Override
            public int findPerson(String path, int filter)
                    throws RemoteException {
                Log.i(TAG, "findPerson imageFilter:"+filter+" path: "+path);
                mOperator.findPersonHandle(path, filter,mCurrentCookie);
                return 0;
            }
    
            @Override
            public void registerCallback(ICallBack cb) throws RemoteException {
                // TODO Auto-generated method stub
                if(cb!=null)
                {
                    mCallbacks.register(cb);
                }
            }
    
            @Override
            public void unregisterCallback(ICallBack cb) throws RemoteException {
                // TODO Auto-generated method stub
                if(cb!=null)
                {
                    mCallbacks.unregister(cb);
                }
            }
            
        }
    
        @Override
        public void onEngineStatusUpdate(int status) {
            nofityStatusChanged(status);
        }
    
        @Override
        public void onQueryResult(long sessionid,String srcPath, int imageFilter,
                ArrayList<PersonImageItem> mResultItems) {
            if(mCurrentCookie == sessionid)
            {
                onFindPersonResult(srcPath,imageFilter,mResultItems);
            }
            else
            {
                Log.w(TAG, "onQueryResult old session:"+sessionid+" currentSession:"+mCurrentCookie);
            }
        }
    
        private void nofityStatusChanged(int status) {
    //        synchronized (this) {
    //            int n = mCallbacks.beginBroadcast();
    //            Log.i(TAG, "nofityStatusChanged n:"+n);
    //            try {
    //                for (int i = 0; i < n; i++) {
    //                    mCallbacks.getBroadcastItem(i).onServiceStatusChanged(status);
    //                }
    //            } catch (RemoteException e) {
    //                Log.e(TAG, "RemoteException:"+e.getMessage());
    //            }
    //            mCallbacks.finishBroadcast();
    //        }
            
        }
        
        private void onFindPersonResult(String srcPath, int imageFilter,
                ArrayList<PersonImageItem> mResultItems)
        {
            try{
                synchronized (this) {
                    Log.i(TAG, "onFindPersonResult filter:"+imageFilter);
                    int n = mCallbacks.beginBroadcast();
                    try {
                        for (int i = 0; i < n; i++) {
                            mCallbacks.getBroadcastItem(i).onQueryResult(mResultItems, srcPath, imageFilter);
                        }
                    } catch (RemoteException e) {
                        Log.e(TAG, "remote error:"+e);
                    }
                    mCallbacks.finishBroadcast();
                }
            }catch (Exception e) {
                Log.i(TAG, "onFindPersonResult Wrong:"+e.getMessage());
            }
        }
    }

    2.IBuildService

    package com.joyfulmath.globalsearch.imagesearch.service.aidl;
    import com.joyfulmath.globalsearch.imagesearch.service.aidl.PersonImageItem;
    import com.joyfulmath.globalsearch.imagesearch.service.aidl.ICallBack;
    
    interface IBuildService{
        int getServiceStatus();
        int findPerson(String path,int filter);
        void registerCallback(ICallBack cb);     
        void unregisterCallback(ICallBack cb);  
    }

    3.数据传递类型:

    package com.joyfulmath.globalsearch.imagesearch.service.aidl;
    
    import android.os.Parcel;
    import android.os.Parcelable;
    
    public class PersonImageItem implements Parcelable {
        
        public int persion_id;
        public int contact_id = -1;
        public int type = -1;
        public int image_id = -1;
        public int imageSize;
        public String Bitmap_Path = "";
    
    
        public PersonImageItem(int personId,int contact_id,String path,int imageId, int imageSize,int type)
        {
            this.persion_id = personId;
            this.contact_id = contact_id;
            this.Bitmap_Path = path;
            this.image_id = imageId;
            this.imageSize = imageSize;
            this.type = type;
        }
    
        public PersonImageItem(Parcel source)
        {
            readFromParcel(source);
        }
        
        
        public PersonImageItem(PersonImageItem person) {
            this.persion_id = person.persion_id;
            this.contact_id = person.contact_id;
            this.Bitmap_Path =person.Bitmap_Path;
            this.image_id = person.image_id;
            this.imageSize = person.imageSize;
            this.type = person.type;
        }
    
        public PersonImageItem(int persionId, int contact_id,int type)
        {
            this.persion_id = persionId;
            this.contact_id = contact_id;
            this.type = type;
        }
        
    
        public final static Parcelable.Creator<PersonImageItem> CREATOR = new Parcelable.Creator<PersonImageItem>() {
    
            @Override
            public PersonImageItem createFromParcel(Parcel source) {
                return new PersonImageItem(source);
            }
    
            @Override
            public PersonImageItem[] newArray(int size) {
                // TODO Auto-generated method stub
                return new PersonImageItem[size];
            }
            
        };
    
        @Override
        public int describeContents() {
            // TODO Auto-generated method stub
            return 0;
        }
    
        @Override
        public void writeToParcel(Parcel dest, int flags) {
            // TODO Auto-generated method stub
            dest.writeInt(persion_id);
            dest.writeInt(contact_id);
            dest.writeInt(image_id);
            dest.writeInt(imageSize);
            dest.writeInt(type);
            dest.writeString(Bitmap_Path);
    
        }
        
        public void readFromParcel(Parcel source)
        {
            persion_id = source.readInt();
            contact_id = source.readInt();
            image_id = source.readInt();
            imageSize = source.readInt();
            type = source.readInt();
            Bitmap_Path = source.readString();
        }
    }
    package com.joyfulmath.globalsearch.imagesearch.service.aidl;
    parcelable PersonImageItem;
    PersonImageItem是service返回给client端的结果类型。
    package com.joyfulmath.globalsearch.imagesearch.service.aidl;
    
    import com.joyfulmath.globalsearch.imagesearch.service.aidl.PersonImageItem;
    interface ICallBack{
        void onQueryResult(in List<PersonImageItem> items,String path,int filter);
        void onServiceStatusChanged(int status);
    }

    client端engine,启动service,调用service服务以及观察service返回的结果。

    package com.joyfulmath.globalsearch.imagesearch.client;
    
    
    import java.util.ArrayList;
    import java.util.List;
    
    import com.joyfulmath.globalsearch.imagesearch.AlertListAdapter.ListAdapterInfo;
    import com.joyfulmath.globalsearch.imagesearch.client.resulttype.ContactResultItem;
    import com.joyfulmath.globalsearch.imagesearch.client.resulttype.SdcardImageResultItem;
    import com.joyfulmath.globalsearch.imagesearch.service.FaceRecognizeEngine;
    import com.joyfulmath.globalsearch.imagesearch.service.ImageSearchBuildService;
    import com.joyfulmath.globalsearch.imagesearch.service.aidl.IBuildService;
    import com.joyfulmath.globalsearch.imagesearch.service.aidl.ICallBack;
    import com.joyfulmath.globalsearch.imagesearch.service.aidl.PersonImageItem;
    import com.joyfulmath.globalsearch.imagesearch.utils.ImageSearchUtils;
    
    import android.content.BroadcastReceiver;
    import android.content.ComponentName;
    import android.content.ContentResolver;
    import android.content.Context;
    import android.content.Intent;
    import android.content.ServiceConnection;
    import android.content.pm.PackageManager;
    import android.content.pm.ResolveInfo;
    import android.database.Cursor;
    import android.graphics.Bitmap;
    import android.graphics.BitmapFactory;
    import android.graphics.drawable.Drawable;
    import android.net.Uri;
    import android.os.Bundle;
    import android.os.Handler;
    import android.os.IBinder;
    import android.os.Looper;
    import android.os.Message;
    import android.os.Process;
    import android.os.RemoteException;
    import android.provider.MediaStore;
    import android.util.Log;
    
    public class SearchEngine extends BroadcastReceiver implements Runnable{
    
        private static final String TAG = "ImageSearch.Engine";
        private Context mContext = null;
        private ContentResolver mContentResolver = null;
        private onEngineListener mListener=null;
        public Handler mEngineHandler =null;
        public Looper mEngineLooper =null;
        public SearchWorkQueue mWorkQueue = null;
        public int mbgEngineStatus = ImageSearchUtils.OPERATOR_STATUS_NONE;
        private IBuildService iServce = null;
        private long mSessionCookie = -1;
        
        public SearchEngine(Context context,onEngineListener listener) {
            mContext = context;
            mContentResolver = mContext.getContentResolver();
            mListener = listener;
            mbgEngineStatus = ImageSearchUtils.OPERATOR_STATUS_NONE;
            mSessionCookie = generateCookie();
            startHandleThread();
            registerBroadCast();
            bindService();
        }
      //监听service的回调
        private ICallBack.Stub mCallback = new ICallBack.Stub() {
            
            @Override
            public void onServiceStatusChanged(int status) throws RemoteException {
                // TODO Auto-generated method stub
                mbgEngineStatus = status;
            }
            
            @Override
            public void onQueryResult(List<PersonImageItem> items, String path,
                    int filter) throws RemoteException {
                Log.i(TAG, "ICallBack onQueryResult filter:"+filter);
                if(items.size()>0)
                {
                    Log.i(TAG, "ICallBack onQueryResult items:"+items.size());
    
                    ArrayList<GenericResultItem> mReults = new ArrayList<GenericResultItem>(items.size());
                    
                    switch(filter)
                    {
                    case ImageSearchUtils.FIND_TYPE_CONTACT:
                        for(PersonImageItem person:items)
                        {
                            ContactResultItem contactitem = new ContactResultItem(person, mContext);
                            mReults.add(contactitem);
                        }
                        break;
                    case ImageSearchUtils.FIND_TYPE_IMAGE_STORE:
                        for(PersonImageItem person:items)
                        {
                            SdcardImageResultItem contactitem = new SdcardImageResultItem(person);
                            mReults.add(contactitem);
                        }
                        break;
                    }
                    
                    if(mWorkQueue!=null)
                    {
                        mWorkQueue.notifyWorkQueue(mReults,filter);
                    }
                }
                else
                {
                    Log.i(TAG, "ICallBack onQueryResult items null");
                    if(mWorkQueue!=null)
                    {
                        mWorkQueue.notifyWorkQueue(null,filter);
                    }
                }
            }
        };
        
      //service connect
    private ServiceConnection conn = new ServiceConnection() { @Override public void onServiceDisconnected(ComponentName name) { // TODO Auto-generated method stub Log.i(TAG, "onServiceDisconnected"); iServce = null; } @Override public void onServiceConnected(ComponentName name, IBinder service) { iServce = IBuildService.Stub.asInterface(service); Log.i(TAG, "onServiceConnected"); try { iServce.registerCallback(mCallback); } catch (RemoteException e) { Log.w(TAG, "onServiceConnected wrong:"+e.getMessage()); } } };
      //启动service并绑定
    private void bindService() { Log.i(TAG, "[bindService] cookie:"+mSessionCookie); Intent intent = new Intent(); intent.setAction(ImageSearchBuildService.ACTION); intent.putExtra("cookie", mSessionCookie); mContext.startService(intent); mContext.bindService(intent, conn, Context.BIND_AUTO_CREATE); }
      //断开service
    private void unBindService() { try { if (iServce != null) { iServce.unregisterCallback(mCallback); } mContext.unbindService(conn); } catch (Exception e) { } } public void findPersonInService(String path, int imageFilter) throws RemoteException { Log.i(TAG, "findPersonInService imageFilter:"+imageFilter); if(iServce!=null) { iServce.findPerson(path, imageFilter); } } private void startHandleThread() { new Thread(this).start(); } private void exitHandleThread(){ if(mEngineLooper!=null) { mEngineLooper.quit(); mEngineLooper = null; } mEngineHandler = null; mContentResolver = null; } public boolean isDeviceSupportEngine() { return FaceRecognizeEngine.checkDeviceSupport(); } public void Release() { unBindService(); unRegisterReceiver(); exitHandleThread(); Log.i(TAG, "[Release] done"); } public void abortSearchImageAsync() { } public void SearchImageAsyncHandle(String path,int imageFilter) { Log.i(TAG, "SearchImageAsyncHandle imageFilter"+imageFilter); //send message to async all search image one by one Message msg = mEngineHandler.obtainMessage(); msg.what = ImageSearchUtils.ENGINE_START_SEARCH; Bundle data = new Bundle(); data.putString("path", path); data.putInt("filter", imageFilter); msg.setData(data); mEngineHandler.sendMessage(msg); } private void searchImageTask(String path,int imageFilter) { try{ if(mWorkQueue == null) { mWorkQueue = new SearchWorkQueue("clientEngine",this); } mWorkQueue.prepareWorkQueue(imageFilter, path); mWorkQueue.query(); }catch (Exception e) { // TODO: handle exception } } public void searhImageQueueHandle() { Message msg = mEngineHandler.obtainMessage(); msg.what = ImageSearchUtils.ENGINE_SEARCH_QUEUE; mEngineHandler.sendMessage(msg); } private void searchImageQueueTask() { if(mWorkQueue!=null) { mWorkQueue.query(); } } public void onSearchResult(String path, ArrayList<GenericResultItem> itmes) { if(mListener!=null) { mListener.onSearchResult(path, itmes); } } @Override public void onReceive(Context context, Intent intent) { } public void registerBroadCast() { } public void unRegisterReceiver() { } public void decodeUriToBitmapHandle(Uri uri) { Message msg = mEngineHandler.obtainMessage(); msg.what = ImageSearchUtils.ENGINE_OP_DEOCDE_URI; Bundle data = new Bundle(); data.putParcelable("uri", uri); msg.setData(data); mEngineHandler.sendMessage(msg); } public void prepareSrcImageItemsHandle() { Message msg = mEngineHandler.obtainMessage(); msg.what = ImageSearchUtils.ENGINE_OP_PREPARE_SRC_APP; mEngineHandler.sendMessage(msg); } private void decodeUriTask(Uri uri) { try { Log.i(TAG, "DecodeUriTask uri" + uri.toString()); String[] projects = new String[1]; projects[0] = MediaStore.Images.Media.DATA; Cursor cursor = mContentResolver.query(uri, projects, null, null, null); String path = null; if (cursor != null) { while (cursor.moveToNext()) { path = cursor.getString(cursor .getColumnIndex(MediaStore.Images.Media.DATA)); break; } cursor.close(); } if (!path.isEmpty()) { Bitmap bitmap = BitmapFactory.decodeFile(path); if (mListener != null) { mListener.onEngineDecodeUri(bitmap, path); } } else { if (mListener != null) { mListener.onEngineDecodeUri(null, null); } } } catch (Exception e) { Log.i(TAG, "DecodeUriTask error:" + e.getMessage()); if (mListener != null) { mListener.onEngineDecodeUri(null, null); } } finally { } } private void prepareSrcSelectItemTask() { try { PackageManager pm = mContext.getPackageManager(); Intent mainIntent = new Intent(ImageSearchUtils.ACTION_CAMERA_PICKER); List<ResolveInfo> resolveInfos = pm .queryIntentActivities(mainIntent, PackageManager.MATCH_DEFAULT_ONLY); ArrayList<ListAdapterInfo> infos = new ArrayList<ListAdapterInfo>(2); if(!resolveInfos.isEmpty()&& resolveInfos.size()>0) { Log.i(TAG, "PrepareSrcSelectItemTask Camera is find"); ResolveInfo reInfo = resolveInfos.get(0); String appLabel = (String) reInfo.loadLabel(pm); // 获得应用程序的Label Drawable icon = reInfo.loadIcon(pm); // 获得应用程序图标 ListAdapterInfo info = new ListAdapterInfo(appLabel,icon,ImageSearchUtils.REQUEST_CAMERA_PICK); infos.add(info); } Intent mainIntent2 = new Intent(ImageSearchUtils.ACTION_GALLERY_PICKER); List<ResolveInfo> resolveInfos2 = pm .queryIntentActivities(mainIntent2, PackageManager.MATCH_DEFAULT_ONLY); if(!resolveInfos2.isEmpty() && resolveInfos2.size()>0) { Log.i(TAG, "PrepareSrcSelectItemTask Gallery is find"); ResolveInfo reInfo2 = resolveInfos2.get(0); // String activityName2 = reInfo2.activityInfo.name; // 获得该应用程序的启动Activity的name // String pkgName2 = reInfo2.activityInfo.packageName; // 获得应用程序的包名 String appLabel2 = (String) reInfo2.loadLabel(pm); // 获得应用程序的Label Drawable icon2 = reInfo2.loadIcon(pm); // 获得应用程序图标 ListAdapterInfo info2 = new ListAdapterInfo(appLabel2,icon2,ImageSearchUtils.REQUEST_GALLERY_PICK); infos.add(info2); } if(mListener!=null) { mListener.onPrepareActivityInfo(infos); } } catch (Exception e) { Log.i(TAG, "PrepareSrcSelectItemTask error:"+e.getMessage()); } finally{ } } public static class EngineHandler extends Handler{ private SearchEngine mSearchEngine = null; public EngineHandler(Looper loop, SearchEngine engine) { super(loop); mSearchEngine = engine; } @Override public void handleMessage(Message msg) { switch(msg.what) { case ImageSearchUtils.ENGINE_OP_DEOCDE_URI: Bundle datauri = msg.getData(); Uri uri = datauri.getParcelable("uri"); mSearchEngine.decodeUriTask(uri); break; case ImageSearchUtils.ENGINE_OP_PREPARE_SRC_APP: mSearchEngine.prepareSrcSelectItemTask(); break; case ImageSearchUtils.ENGINE_START_SEARCH: Bundle data = msg.getData(); String path = data.getString("path"); int imageFilter = data.getInt("filter"); mSearchEngine.searchImageTask(path, imageFilter); break; case ImageSearchUtils.ENGINE_SEARCH_QUEUE: mSearchEngine.searchImageQueueTask(); break; } } } @Override public void run() { Looper.prepare(); mEngineLooper = Looper.myLooper(); mEngineHandler = new EngineHandler(mEngineLooper,this); Log.i(TAG, "frontground engine handle running TID:"+Process.myTid()); Looper.loop(); } private long generateCookie() { return System.currentTimeMillis(); } }

     onstartcommand返回类型?

    START_STICKY: 如果service进程被kill掉,保留service的状态为开始状态,但不保留递送的intent对象。随后系统会尝试重新创建service,由 于服务状态为开始状态,所以创建服务后一定会调用onStartCommand(Intent,int,int)方法。如果在此期间没有任何启动命令被传 递到service,那么参数Intent将为null

    START_NOT_STICKY:“非粘性的”。使用这个返回值时,如果在执行完onStartCommand后,服务被异常kill掉,系统不会自动重启该服务。

    START_REDELIVER_INTENT:重传Intent。使用这个返回值时,如果在执行完onStartCommand后,服务被异常kill掉,系统会自动重启该服务,并将Intent的值传入。
    START_STICKY的兼容版本,但不保证服务被kill后一定能重启。

  • 相关阅读:
    资源限制
    垃圾收集器
    GC日志
    happens-before
    maven相互依赖导致无法编译成功
    LVM-逻辑卷常用命令和示意图
    取消RAID5
    扩展RAID5的容量
    模拟RAID5损坏
    创建RAID5
  • 原文地址:https://www.cnblogs.com/deman/p/4233785.html
Copyright © 2011-2022 走看看