2019级软件工程应用与实践-人工智能快递柜(代码分析7)

2021SC@SDUSC

public class CabinetService extends Service {}

创建一个CabinetService类,继承自Service类
类中的具体内容分析如下:

private String TAG = CabinetService.class.getSimpleName();
    public class LocalBinder extends Binder {
        public CabinetService getService() {
            return CabinetService.this;
        }
    }

首先创建Binder对象,返回给客户端即Activity使用,提供数据交换的接口,声明一个方法,getService此方法为提供给客户端调用。在方法中,返回当前对象LocalService,这样我们就可在客户端端调用Service的公共方法了。

    int mStartMode;
    IBinder mBinder;
    boolean mAllowRebind;

定义的三个变量依次代表:标识服务如果被杀死之后的行为;绑定的客户端接口;标识是否可以使用onRebind。便于后面精简代码。

public void onCreate() {
        EventBus.getDefault().register(this);

        MqttUtils.addMqttObserver(new CabinetObserver(this));

        Log.e(TAG, "service is created");
   
        MqttSchedule schedule = new MqttSchedule();
        schedule.rollMethod();
    }

重新定义了onCreate()方法,其中使用了mqtt 定时检测任务

@Override
    public int onStartCommand(Intent intent, int flags, int startId) {

        Log.e(TAG, "service is Start");


        return mStartMode;
    }

调用startService()启动服务时回调

@Override
    public IBinder onBind(Intent intent) {
        Log.e(TAG, "service is onBind");
        return mBinder;
    }

通过bindService()绑定到服务的客户端

@Override
    public boolean onUnbind(Intent intent) {
        Log.e(TAG, "service is onUnbind");
        return mAllowRebind;
    }

通过unbindService()解除所有客户端绑定时调用

@Override
    public void onRebind(Intent intent) {
        Log.e(TAG, "service is onRebind");

    }

通过bindService()将客户端绑定到服务时调用

@Override
    public void onDestroy() {
        Log.e(TAG, "service is onDestroy");

        EventBus.getDefault().unregister(this);
    }

服务不再有用且将要被销毁时调用

@Subscribe(threadMode = ThreadMode.MAIN)
    public void snycResult(String msg){
        if (msg.equals("overWrite")){

            Log.e(TAG, msg);
        }else {
            Log.e(TAG, "影子同步错误");
           //Toast.makeText(this,"影子同步错误:"+msg,Toast.LENGTH_LONG);
           
        }
    }

此时ThreadMode 线程模式为MAIN模式,在主线程处理事件 , 如果在子线程发送消息 , 处理消息时会将线程切换成主线程 。主要有两种情况:

  • 如果发送事件的线程是 主线程 , 则立刻调用消息处理事件 , 此时 主线程会阻塞 ;
  • 如果发送事件的线程是 子线程 , 事件在队列中排队等待传递 , 不会阻塞发布线程 ;

如果数据库被重写,读取数据库所有数据,更新页面;在数据库未被重写的情况下,学长原使用Toast.makeText(this,“影子同步错误:”+msg,Toast.LENGTH_LONG);来重新发送上一步的请求,继续被阻塞的原主进程,但这样使用是报错的。原因分析如下:在子线程中 使用Toast 弹出消息时,去相应的位置去取对象,子线程根本没有初始化就直接取,结果肯定取不到,所以就会抛出此异常,这就是Toast不能直接在子线程中使用,如果使用的话需要添加prepare()函数。

public void update(List<List<NotifyDataDetails>> list){
        //list.get(0)是添加的数据的类名和sri
        //list.get(1)是更新的数据的类名和sri
        //list.get(2)是删除的数据的类名和sri
        Log.e(TAG, JSON.toJSONString(list));

        List<NotifyDataDetails> addDataDetailsList = list.get(0);
        
        for (NotifyDataDetails addDetail : addDataDetailsList) {
            switch (addDetail.getClassName()) {
                case "SduMedia":
                    SduMedia media = (SduMedia) DaoManager.search(new SduMedia(), addDetail.getSri());
                    if (media == null) {
                        Log.e(TAG, "收到一个空的media,信息如下: " + JSON.toJSONString(addDetail));
                        continue;
                    }
                    Log.e(TAG, media.getPath());
                    if (!media.getDownloaded()) {

                        MinioUtil.downloadByUrl(media.getPath(), (InputStream is) -> {
                            if (is != null) {
                                Log.e(TAG, "file separator " + File.separator);
                                String[] strs = media.getPath().split(File.separator);
                                String fileName = strs[strs.length - 1];
                                FileUtil.saveFile(is, fileName);
                                media.setDownloaded(true);
                                media.setAnPath(FileUtil.path + File.pathSeparator + fileName);
                         
                                DaoManager.update(media);

                                ShadowFactory.notifyUpdate(media);

                            }
                        });
                    }
                    break;
            }
        }

这个方法主要管理的是柜子端界面上宣传展示的部分(主要是宣传图)。media是自定义的一个媒体文件对象。if-continue部分主要说明在media文件不存在的时候,则不报错。在media文件存在时,如果这个媒体文件没有被下载到本机立即发起网络请求,下载这个文件到本机,完成后执行回调。使用

media.setDownloaded(true);
media.setAnPath(FileUtil.path + File.pathSeparator + fileName);
DaoManager.update(media);
ShadowFactory.notifyUpdate(media);

更新影子中,当前media的downloaded标志位,同时更新文件存放位置url;更新数据库;发送到后台,并通知前端媒体组件,更新媒体列表

上一篇:golang 互斥锁和读写锁


下一篇:Oracle-11g-R2 RAC 环境下 GPnP Profile 文件