目前做的项目是android面板和打印机交互App,把交互中用到的机制总结下来供以后参考

交互的基本原理:

打印机通过打印机事件通过广播的方式,通知应用程序,打印机的最新状态。应用程序通过web api 开启打印机扫描、打印以及获取状态信息。

项目需求

应用程序请求扫描/打印任务,把处理扫描/打印任务状态(取消,拒绝,暂停,预览)变为通用逻辑(状态机),把最终结果传递给回调函数

结构图

下面是控制打印机扫描/打印和监听状态的结构图:

打印机监控 内容_python

代码分析

Scanjob

从状态机的开始请求开始mApplication.getScanJob().scan(requestAttributes),分析Scanjob类:

public ScanJob(){
		this.mHandler = new ScanJobMessageDispatcher();
		// sets the listener for the asynchronous communications
		this.mHandler.setScanJobListener(new JobListener() {
            @Override
            public void onChangeJobStatus(ScanJobAttributeSet jobStatus) {
                changeJobStatus(jobStatus);
            }

            @Override
            public void setJobId(String jobId) {
                setCurrentJobId(jobId);
            }

            @Override
            public String getJobId() {
                return getCurrentJobId();
            }
        });
	}

public boolean  scan(ScanRequestAttributeSet attributes) throws ScanException {
        if( this.mHandler == null ) throw new IllegalStateException("Cannot scan after scanning is completed.");

		return mHandler.requestStartScanJob(attributes);
	}

从代码中可以看出:扫描调用的是ScanJobMessageDispatcher的requestStartScanJob方法,ScanJob在构造函数中实例化了ScanJobMessageDispatcher,并且向其注册了监听事件

ScanJobMessageDispatcher

接下来我们看实现requestStartScanJob的ScanJobMessageDispatcher类:

public boolean requestStartScanJob(ScanRequestAttributeSet attributes) throws ScanException {
        if(this.mJob != null) {
            throw new ScanException("Can not start scan(), because running scan process.");
        }

        // Issues an subscribed ID and registers the asynchronous job event
        String subscribedId = FunctionMessageDispatcher.getInstance().addAsyncJobEventListener(this);
        if( subscribedId == null ) {
            ...
        }
        ...
        Request req = new Request();
        ...
        try {
            Response<CreateJobResponseBody> resp = mScanner.createJob(req);
            ...
                mJob = new Job(jobId);
                startJobEventDispatcher(jobId);
                return true;
            }

        } catch (IOException e) {
           ...
        } catch (InvalidResponseException e) {
            ...
            return false;
        }
            ...
            return false;
	}

private void startJobEventDispatcher(String jobId) {
	    finishJobEventDispatcher();
	    mJobEventDispatcher = new JobEventDispatcher(jobId);
	    mJobEventDispatcher.start();
	}
@Override
	public void onReceiveJobEvent(GetJobStatusResponseBody event) {
	    try {
            mJobEventQueue.put(event);
        } catch (InterruptedException e) {
        }
	}
private class JobEventDispatcher extends Thread {

	    private final String mJobId;

	    private volatile boolean mCanceled = false;
            ...
	    @Override
	    public void run() {
	        Log.d(SmartSDKApplication.getTagName(), PREFIX + "scan job event dispatcher start (" + mJobId + ")");

	        while (!mCanceled) {
	            GetJobStatusResponseBody event;
	            try {
	                event = mJobEventQueue.take();
                        ...
	                if (listener != null) {
	                    listener.onChangeJobStatus(jobStatusResponseToAttributes(event));
	                }

	            } catch (InterruptedException ignore) {
	            }
	        }
	    }
	}

从requestStartScanJob可以看到

1.获取消息接收器的唯一实例,并且向其注册订阅事件,订阅信息是下面的mJob(扫描任务Id)

2.然后通过mScanner调用打印机的web api发起扫描请求

3.最后开始消息读取线程,并将消息传给回调函数。消息处理采用消息队列的目的是: 保证接收到的广播事件串行化处理;不影响消息分发线程的效率

FunctionMessageDispatcher

接下来查看FunctionMessageDispatcher类:

private FunctionMessageDispatcher(){
	    // Registers an Internal listener to receive asynchronous events from SDKService
        mScanAsyncEventReceiver = new ScanEventReceiver();
        mScanAsyncEventReceiver.addAsyncEventListener(this);

        mScanner = new Scanner();
	}

public String addAsyncJobEventListener(AsyncJobEventHandler handler){
		if(handler == null) {
			throw new NullPointerException("handler is null");
		}
        synchronized (mAsyncEvHandlers) {
            if (mSubscribedId == null) {
                this.mSubscribedId = mScanAsyncEventReceiver.startReceiveJobEvent();
            }
            if (mSubscribedId != null) {
                mAsyncEvHandlers.add(handler);
            }
            return this.mSubscribedId;
        }
	}

public String startReceiveJobEvent() {
		return setReceiveFunctionJobEvent(RECEIVE_SCAN_JOB_STATE_ACTION, true);
}
String setReceiveFunctionJobEvent(String action, boolean isReceiveEvent){
		...
		SDKServiceResultReceiver resultReceiver = new SDKServiceResultReceiver();

		sendIntent.putExtra("PRODUCT_ID",SmartSDKApplication.getProductId());
                ...
		Handler mHandler = new Handler(this.broadcastResultReceiveThread.getLooper());
		SmartSDKApplication.getContext().sendOrderedBroadcast(sendIntent, SDK_SERVICE_SEND_CMD_PERMISSION,
				resultReceiver, mHandler, Activity.RESULT_OK, null, null);
                ...
		// synchronous processing
		bundle = resultReceiver.getResultExtras();
		subscribedId = bundle.getString("SUBSCRIBED_ID");
		return subscribedId;
}
public void onReceive(Context context, Intent intent) {
	    postEvent(EventData.EVENT_TYPE_JOB_EVENT, eventData);
}
void postEvent(int eventType, String eventData) {
	this.mMessageThread.post(eventType, eventData, this);
}
public void onReceiveJobEvent(String eventData) {
        if(eventData == null) return;

        Map<String, Object> decoded = GenericJsonDecoder.decodeToMap(eventData);
        GetJobStatusResponseBody body = new GetJobStatusResponseBody((Map<String, Object>) decoded.get("data"));

        String jobId = body.getJobId();
        AsyncJobEventHandler[] handlers;
        synchronized (mAsyncEvHandlers) {
            handlers = mAsyncEvHandlers.toArray(new AsyncJobEventHandler[mAsyncEvHandlers.size()]);
        }
        for(AsyncJobEventHandler handler : handlers) {
            if( handler.getJobId() == null || handler.getJobId().equals(jobId)) {
                handler.onReceiveJobEvent(body);  
            }
        }
    }
MessageDispatchThread.java
public void run() {
		while(isStart) {
			try {
				EventData ev = mEventQueue.take();
				AbstractEventReceiver receiver = ev.getReceiver();
				int evType = ev.getEventType();
				String data = ev.getEventData();

				receiver.notifyAsyncEvent(evType, data);

			} catch (InterruptedException e) {
	  
			}
		}
	}

从addAsyncJobEventListener方法开始

1.startReceiveJobEvent是向系统底层注册扫描事件监听,系统接收到扫描事件后向ScanEventReceiver发送广播

2.把监听器添加到mAsyncEvHandlers注册列表中

3.ScanEventReceiver.onReceive收到事件后把消息分发给线程mMessageThread,MessageDispatchThread.run()消费消息,把消息发送给receiver,receiver就是this.mMessageThread.post(eventType, eventData, this)传入的FunctionMessageDispatcher实例

4.FunctionMessageDispatcher.onReceiveJobEvent把事件发送给所有的订阅者,发送事件的方法是调用ScanJobMessageDispatcher.onReceiveJobEvent把event放入mJobEventQueue队列中。JobEventDispatcher.run读取事件发送给ScanJob的回调函数