diff --git a/build.gradle b/build.gradle
index 02cd8ed..94368b0 100644
--- a/build.gradle
+++ b/build.gradle
@@ -1,6 +1,4 @@
-
-// Top-level build file where you can add configuration options common to all sub-projects/modules.
-
+apply from: "${rootProject.rootDir}/buildCommon/commonLibConfig.gradle"
buildscript {
repositories {
google()
@@ -8,7 +6,7 @@ buildscript {
}
dependencies {
classpath 'com.android.tools.build:gradle:7.1.2'
-
+ classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.5.20"
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
diff --git a/buildCommon/commonLibConfig.gradle b/buildCommon/commonLibConfig.gradle
new file mode 100644
index 0000000..0c66e38
--- /dev/null
+++ b/buildCommon/commonLibConfig.gradle
@@ -0,0 +1,159 @@
+project.ext {
+ sign = [
+ keystore_path : "../signature/innovationapp.jks",
+ keystore_pwd : "123456",
+ keystore_alias: "yinuo"
+ ]
+
+ compileOptions = [
+ sourceCompatibility: JavaVersion.VERSION_1_8,
+ targetCompatibility: JavaVersion.VERSION_1_8,
+ ]
+
+ versions = [
+ compileSdkVersion : 31,
+ buildToolsVersion : "33.0.3",
+ minSdkVersion : 23,
+ targetSdkVersion : 28,
+ versionCode : 1,
+ versionName : "1.0",
+ jvmTarget : "1.8",
+
+ appcompat : "1.2.0",
+ material : "1.2.1",
+ okhttp : "4.9.1",
+ retrofit : "2.9.0",
+ rxjava : "3.0.13",
+ rxandroid : "3.0.0",
+ kotlin : "1.5.10",
+ kotlin_android : "1.5.0",
+ converter_gson : '2.9.0',
+ retrofit_rxjava : "2.9.0",
+ room : "2.3.0",
+ jxl : "2.6.12",
+ navigation_fragment_ktx: "2.3.0",
+ navigation_ui_ktx : "2.3.0",
+ glide : "4.12.0",
+ photo_view : "2.3.0",
+ luban : "1.1.8",
+ gson : "2.8.6",
+ arouter : "1.5.2",
+ mmkv : "1.2.10",
+ okhttp_logger : "3.12.7",
+ lifecycle_process : "2.3.1",
+ ]
+
+ dependencies = [
+ okhttp : "com.squareup.okhttp3:okhttp:${versions.okhttp}",
+ retrofit : "com.squareup.retrofit2:retrofit:${versions.retrofit}",
+ rxjava : "io.reactivex.rxjava3:rxjava:${versions.rxjava}",
+ rxandroid : "io.reactivex.rxjava3:rxandroid:${versions.rxandroid}",
+ okhttp_logger : "com.squareup.okhttp3:logging-interceptor:${versions.okhttp_logger}",
+ kotlin : "org.jetbrains.kotlin:kotlin-stdlib-jdk8:${versions.kotlin}",
+ kotlin_android : "org.jetbrains.kotlinx:kotlinx-coroutines-android:${versions.kotlin_android}",
+ converter_gson : "com.squareup.retrofit2:converter-gson:${versions.converter_gson}",
+ retrofit_rxjava : "com.squareup.retrofit2:adapter-rxjava3:${versions.retrofit_rxjava}",
+ room : "androidx.room:room-runtime:${versions.room}",
+ room_compiler : "androidx.room:room-compiler:${versions.room}",
+ room_ktx : "androidx.room:room-ktx:${versions.room}",
+ room_rxjava : "androidx.room:room-rxjava3:${versions.room}",
+ jxl : "net.sourceforge.jexcelapi:jxl:${versions.jxl}",
+ navigation_fragment_ktx: "androidx.navigation:navigation-fragment-ktx:${versions.navigation_fragment_ktx}",
+ navigation_ui_ktx : "androidx.navigation:navigation-ui-ktx:${versions.navigation_ui_ktx}",
+ navigation_arg : "androidx.navigation:navigation-safe-args-gradle-plugin:${versions.navigation_ui_ktx}",
+ glide : "com.github.bumptech.glide:glide:${versions.glide}",
+ gilde_integration : "com.github.bumptech.glide:okhttp3-integration:${versions.glide}",
+ annotationProcessor : "com.github.bumptech.glide:compiler:${versions.glide}",
+ photo_view : "com.github.chrisbanes:PhotoView:${versions.photo_view}",
+ luban : "top.zibin:Luban:${versions.luban}",
+ gson : "com.google.code.gson:gson:${versions.gson}",
+ arouter : "com.alibaba:arouter-api:${versions.arouter}",
+ arouter_compiler : "com.alibaba:arouter-compiler:${versions.arouter}",
+ mmkv : "com.tencent:mmkv-static:${versions.mmkv}",
+ lifecycle_process : "androidx.lifecycle:lifecycle-process:${versions.lifecycle_process}",
+ ]
+
+ /**
+ * android project android {} default config
+ */
+ setAndroidConfig = {
+ extension ->
+ extension.compileSdkVersion versions.compileSdkVersion
+
+ extension.defaultConfig {
+ minSdkVersion versions.minSdkVersion
+ targetSdkVersion versions.targetSdkVersion
+ versionCode versions.versionCode
+ versionName versions.vserionName
+
+ testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
+ }
+
+ extension.compileOptions {
+ targetCompatibility = compileOptions.targetCompatibility
+ sourceCompatibility = compileOptions.sourceCompatibility
+ }
+
+ extension.kotlinOptions {
+ jvmTarget = versions.jvmTarget
+ }
+ }
+
+ /**
+ * android project dependencies {} default config
+ */
+ setDependencies = {
+ extension ->
+ extension.implementation fileTree(include: ['*.jar'], dir: 'libs')
+ }
+
+ /**
+ * android library config
+ */
+ setLibDefaultConfig = {
+ extension ->
+ extension.apply plugin: 'com.android.library'
+ extension.apply plugin: 'kotlin-android'
+ extension.apply plugin: 'kotlin-parcelize'
+ extension.apply plugin: 'kotlin-kapt'
+ extension.description "lib"
+
+ setAndroidConfig extension.android
+ setDependencies extension.dependencies
+ }
+
+ /**
+ * android application config
+ */
+ setAppDefaultConfig = {
+ extension ->
+ extension.apply plugin: 'com.android.application'
+ extension.apply plugin: 'kotlin-android'
+ extension.apply plugin: 'kotlin-parcelize'
+ extension.apply plugin: 'kotlin-kapt'
+ extension.description "lib"
+
+ setAndroidConfig extension.android
+ setDependencies extension.dependencies
+ }
+
+ /**
+ * android library common config
+ */
+ setArouterConfig = {
+ extension ->
+ extension.android.defaultConfig {
+ javaCompileOptions {
+ annotationProcessorOptions {
+ arguments = [AROUTER_MODULE_NAME: project.getName()]
+ }
+ }
+ }
+
+ // 添加ARouter依赖
+ extension.dependencies.implementation(rootProject.ext.dependencies.arouter) {
+ exclude group: 'com.android.support'
+ }
+ extension.dependencies.annotationProcessor rootProject.ext.dependencies.arouter_compiler
+ }
+}
\ No newline at end of file
diff --git a/commonSPort/.gitignore b/commonSPort/.gitignore
new file mode 100644
index 0000000..42afabf
--- /dev/null
+++ b/commonSPort/.gitignore
@@ -0,0 +1 @@
+/build
\ No newline at end of file
diff --git a/commonSPort/build.gradle b/commonSPort/build.gradle
new file mode 100644
index 0000000..c3321be
--- /dev/null
+++ b/commonSPort/build.gradle
@@ -0,0 +1,22 @@
+apply from: "${rootProject.rootDir}/buildCommon/commonLibConfig.gradle"
+project.ext.setLibDefaultConfig project
+
+android {
+ buildTypes {
+ release {
+ minifyEnabled false
+ proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
+ }
+ }
+ compileOptions {
+ sourceCompatibility JavaVersion.VERSION_1_8
+ targetCompatibility JavaVersion.VERSION_1_8
+ }
+ buildFeatures {
+ viewBinding true
+ }
+}
+
+dependencies {
+ implementation 'com.aill:AndroidSerialPort:1.0.8'
+}
\ No newline at end of file
diff --git a/commonSPort/consumer-rules.pro b/commonSPort/consumer-rules.pro
new file mode 100644
index 0000000..e69de29
diff --git a/commonSPort/proguard-rules.pro b/commonSPort/proguard-rules.pro
new file mode 100644
index 0000000..481bb43
--- /dev/null
+++ b/commonSPort/proguard-rules.pro
@@ -0,0 +1,21 @@
+# Add project specific ProGuard rules here.
+# You can control the set of applied configuration files using the
+# proguardFiles setting in build.gradle.
+#
+# For more details, see
+# http://developer.android.com/guide/developing/tools/proguard.html
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+# public *;
+#}
+
+# Uncomment this to preserve the line number information for
+# debugging stack traces.
+#-keepattributes SourceFile,LineNumberTable
+
+# If you keep the line number information, uncomment this to
+# hide the original source file name.
+#-renamesourcefileattribute SourceFile
\ No newline at end of file
diff --git a/commonSPort/src/main/AndroidManifest.xml b/commonSPort/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..4d8db79
--- /dev/null
+++ b/commonSPort/src/main/AndroidManifest.xml
@@ -0,0 +1,5 @@
+
+
+
+
\ No newline at end of file
diff --git a/commonSPort/src/main/java/com/common/queue/BlockTaskQueue.java b/commonSPort/src/main/java/com/common/queue/BlockTaskQueue.java
new file mode 100644
index 0000000..86d9fac
--- /dev/null
+++ b/commonSPort/src/main/java/com/common/queue/BlockTaskQueue.java
@@ -0,0 +1,68 @@
+package com.common.queue;
+
+import android.util.Log;
+
+import com.common.queue.Task.ITask;
+
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.PriorityBlockingQueue;
+import java.util.concurrent.atomic.AtomicInteger;
+
+public class BlockTaskQueue {
+ private String TAG = "BlockTaskQueue";
+ private AtomicInteger mAtomicInteger = new AtomicInteger();
+ //阻塞队列
+ private final BlockingQueue mTaskQueue = new PriorityBlockingQueue<>();
+
+ public BlockTaskQueue() {
+ }
+
+ //单例模式
+// private static class BlockTaskQueueHolder {
+// private final static BlockTaskQueue INSTANCE = new BlockTaskQueue();
+// }
+//
+// public static BlockTaskQueue getInstance() {
+// return BlockTaskQueueHolder.INSTANCE;
+// }
+
+ /**
+ * 插入时 因为每一个Task都实现了comparable接口 所以队列会按照Task复写的compare()方法定义的优先级次序进行插入
+ * 当优先级相同时,使用AtomicInteger原子类自增 来为每一个task 设置sequence,
+ * sequence的作用是标记两个相同优先级的任务入队的次序
+ */
+ public int add(T task) {
+ if (!mTaskQueue.contains(task)) {
+ task.setSequence(mAtomicInteger.incrementAndGet());
+ mTaskQueue.add(task);
+ Log.d(TAG, "\n add task " + task.toString());
+ }
+ return mTaskQueue.size();
+ }
+
+ public void remove(T task) {
+ if (mTaskQueue.contains(task)) {
+ Log.d(TAG, "\n" + "task has been finished. remove it from task queue");
+ mTaskQueue.remove(task);
+ }
+ if (mTaskQueue.size() == 0) {
+ mAtomicInteger.set(0);
+ }
+ }
+
+ public ITask poll() {
+ return mTaskQueue.poll();
+ }
+
+ public ITask take() throws InterruptedException {
+ return mTaskQueue.take();
+ }
+
+ public void clear() {
+ mTaskQueue.clear();
+ }
+
+ public int size() {
+ return mTaskQueue.size();
+ }
+}
diff --git a/commonSPort/src/main/java/com/common/queue/Task/BaseTask.java b/commonSPort/src/main/java/com/common/queue/Task/BaseTask.java
new file mode 100644
index 0000000..8b69f84
--- /dev/null
+++ b/commonSPort/src/main/java/com/common/queue/Task/BaseTask.java
@@ -0,0 +1,108 @@
+package com.common.queue.Task;
+
+import android.util.Log;
+
+import com.common.queue.TaskScheduler;
+import com.common.queue.BlockTaskQueue;
+
+import java.lang.ref.WeakReference;
+import java.util.concurrent.PriorityBlockingQueue;
+
+public class BaseTask implements ITask {
+ private final String TAG = getClass().getSimpleName();
+ private TaskPriority mTaskPriority = TaskPriority.DEFAULT; //默认优先级
+ private int mSequence;// 入队次序
+ private Boolean mTaskStatus = false; // 标志任务状态,是否仍在展示
+ protected WeakReference taskQueue;//阻塞队列
+ protected int duration = 0; //任务执行时间
+ //此队列用来实现任务时间不确定的队列阻塞功能
+ private PriorityBlockingQueue blockQueue;
+ //构造函数
+ public BaseTask() {
+ taskQueue = new WeakReference<>(BlockTaskQueue.getInstance());
+ blockQueue = new PriorityBlockingQueue<>();
+ }
+ //入队实现
+ @Override
+ public void enqueue() {
+ TaskScheduler.getInstance().enqueue(this);
+ }
+ //执行任务方法,此时标记为设为true,并且将当前任务记录下来
+ @Override
+ public void doTask() {
+ mTaskStatus = true;
+ }
+ //任务执行完成,改变标记位,将任务在队列中移除,并且把记录清除
+ @Override
+ public void finishTask() {
+ this.mTaskStatus = false;
+ this.taskQueue.get().remove(this);
+ Log.d(TAG, taskQueue.get().size() + "");
+ }
+ //设置任务优先级实现
+ @Override
+ public ITask setPriority(TaskPriority mTaskPriority) {
+ this.mTaskPriority = mTaskPriority;
+ return this;
+ }
+ //设置任务执行时间
+ public ITask setDuration(int duration) {
+ this.duration = duration;
+ return this;
+ }
+ //获取任务优先级
+ @Override
+ public TaskPriority getPriority() {
+ return mTaskPriority;
+ }
+ //获取任务执行时间
+ @Override
+ public int getDuration() {
+ return duration;
+ }
+ //设置任务次序
+ @Override
+ public void setSequence(int mSequence) {
+ this.mSequence = mSequence;
+ }
+ //获取任务次序
+ @Override
+ public int getSequence() {
+ return mSequence;
+ }
+ // 获取任务状态
+ @Override
+ public boolean getStatus() {
+ return mTaskStatus;
+ }
+ //阻塞任务执行
+ @Override
+ public void blockTask() throws Exception {
+ blockQueue.take(); //如果队列里面没数据,就会一直阻塞
+ }
+ //解除阻塞
+ @Override
+ public void unLockBlock() {
+ blockQueue.add(1); //往里面随便添加一个数据,阻塞就会解除
+ }
+
+ /**
+ * 排队实现
+ * 优先级的标准如下:
+ * TaskPriority.LOW < TaskPriority.DEFAULT < TaskPriority.HIGH
+ * 当优先级相同 按照插入次序排队
+ */
+ @Override
+ public int compareTo(ITask another) {
+ final TaskPriority me = this.getPriority();
+ final TaskPriority it = another.getPriority();
+ return me == it ? this.getSequence() - another.getSequence() :
+ it.ordinal() - me.ordinal();
+ }
+ //输出一些信息
+ @Override
+ public String toString() {
+ return "task name : " + getClass().getSimpleName() + " sequence : " + mSequence + " TaskPriority : " + mTaskPriority;
+ }
+}
+
\ No newline at end of file
diff --git a/commonSPort/src/main/java/com/common/queue/Task/DemoTask.java b/commonSPort/src/main/java/com/common/queue/Task/DemoTask.java
new file mode 100644
index 0000000..e972614
--- /dev/null
+++ b/commonSPort/src/main/java/com/common/queue/Task/DemoTask.java
@@ -0,0 +1,51 @@
+package com.common.queue.Task;
+
+import android.util.Log;
+
+public class DemoTask extends BaseTask {
+ String name;
+
+ public DemoTask(String name) {
+ this.name = name;
+ }
+
+ //执行任务方法,在这里实现你的任务具体内容
+ @Override
+ public void doTask() {
+ super.doTask();
+ Log.i("LogTask", "--doTask-" + name);
+
+ //如果这个Task的执行时间是不确定的,比如上传图片,那么在上传成功后需要手动调用
+ //unLockBlock方法解除阻塞,例如:
+ uploadImage(new UploadListener() {
+ @Override
+ public void onSuccess() {
+ unLockBlock();
+ }
+ });
+ }
+
+ private void uploadImage(UploadListener uploadListener) {
+ try {
+// long seconds = getDuration();
+ long seconds = (long) (Math.random() * 10000);
+ Log.i("LogTask", "uploadImage milliseconds " + seconds);
+ Thread.sleep(seconds);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ uploadListener.onSuccess();
+ }
+
+ //任务执行完的回调,在这里你可以做些释放资源或者埋点之类的操作
+ @Override
+ public void finishTask() {
+ super.finishTask();
+ Log.i("LogTask", "--finishTask-" + name);
+ }
+
+ public interface UploadListener {
+ void onSuccess();
+ }
+
+}
diff --git a/commonSPort/src/main/java/com/common/queue/Task/ITask.java b/commonSPort/src/main/java/com/common/queue/Task/ITask.java
new file mode 100644
index 0000000..458f798
--- /dev/null
+++ b/commonSPort/src/main/java/com/common/queue/Task/ITask.java
@@ -0,0 +1,41 @@
+package com.common.queue.Task;
+
+public interface ITask extends Comparable {
+
+ // 将该任务插入队列
+ void enqueue();
+
+ // 执行具体任务的方法
+ void doTask();
+
+ // 任务执行完成后的回调方法
+ void finishTask();
+
+ // 设置任务优先级
+ ITask setPriority(TaskPriority mTaskPriority);
+
+ // 获取任务优先级
+ TaskPriority getPriority();
+
+ // 当优先级相同 按照插入顺序 先入先出 该方法用来标记插入顺序
+ void setSequence(int mSequence);
+
+ // 获取入队次序
+ int getSequence();
+
+ // 每个任务的状态,就是标记完成和未完成
+ boolean getStatus();
+
+ // 设置每个任务的执行时间,该方法用于任务执行时间确定的情况
+ ITask setDuration(int duration);
+
+ // 获取每个任务执行的时间
+ int getDuration();
+
+ // 阻塞任务执行,该方法用于任务执行时间不确定的情况
+ void blockTask() throws Exception;
+
+ // 解除阻塞任务,该方法用于任务执行时间不确定的情况
+ void unLockBlock();
+}
+
diff --git a/commonSPort/src/main/java/com/common/queue/Task/TaskEvent.java b/commonSPort/src/main/java/com/common/queue/Task/TaskEvent.java
new file mode 100644
index 0000000..356fb30
--- /dev/null
+++ b/commonSPort/src/main/java/com/common/queue/Task/TaskEvent.java
@@ -0,0 +1,30 @@
+package com.common.queue.Task;
+
+import java.lang.ref.WeakReference;
+
+public class TaskEvent {
+ private WeakReference mTask;
+ int mEventType;
+
+ public ITask getTask() {
+ return mTask.get();
+ }
+
+ public void setTask(ITask mTask) {
+ this.mTask = new WeakReference<>(mTask);
+ }
+
+ public int getEventType() {
+ return mEventType;
+ }
+
+ public void setEventType(int mEventType) {
+ this.mEventType = mEventType;
+ }
+
+ public static class EventType {
+ public static final int DO = 0X00;
+ public static final int FINISH = 0X01;
+ }
+}
+
\ No newline at end of file
diff --git a/commonSPort/src/main/java/com/common/queue/Task/TaskPriority.java b/commonSPort/src/main/java/com/common/queue/Task/TaskPriority.java
new file mode 100644
index 0000000..d435b95
--- /dev/null
+++ b/commonSPort/src/main/java/com/common/queue/Task/TaskPriority.java
@@ -0,0 +1,8 @@
+package com.common.queue.Task;
+
+// 优先级分为3种,如注释所示,他们的关系:LOW < DEFAULT < HIGH
+public enum TaskPriority {
+ LOW, //低
+ DEFAULT,//普通
+ HIGH, //高
+}
diff --git a/commonSPort/src/main/java/com/common/queue/TaskExecutor.java b/commonSPort/src/main/java/com/common/queue/TaskExecutor.java
new file mode 100644
index 0000000..a0f73bd
--- /dev/null
+++ b/commonSPort/src/main/java/com/common/queue/TaskExecutor.java
@@ -0,0 +1,100 @@
+package com.common.queue;
+
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+
+import com.common.queue.Task.TaskEvent;
+import com.common.queue.Task.ITask;
+
+import java.util.concurrent.Executors;
+import java.util.concurrent.TimeUnit;
+
+public class TaskExecutor {
+ private final String TAG = "ShowTaskExecutor";
+ private BlockTaskQueue taskQueue;
+ private TaskHandler mTaskHandler;
+ private boolean isRunning = true;
+ private static final int MSG_EVENT_DO = 0;
+ private static final int MSG_EVENT_FINISH = 1;
+
+ public TaskExecutor(BlockTaskQueue taskQueue) {
+ this.taskQueue = taskQueue;
+ mTaskHandler = new TaskHandler();
+ }
+ //开始遍历任务队列
+ public void start() {
+ Executors.newSingleThreadExecutor().execute(new Runnable() {
+ @Override
+ public void run() {
+ try {
+ while (isRunning) { //死循环
+ ITask iTask;
+ iTask = taskQueue.take(); //取任务
+ if (iTask != null) {
+ //执行任务
+ TaskEvent doEvent = new TaskEvent();
+ doEvent.setTask(iTask);
+ doEvent.setEventType(TaskEvent.EventType.DO);
+ mTaskHandler.obtainMessage(MSG_EVENT_DO, doEvent).sendToTarget();
+ //一直阻塞,直到任务执行完
+ if (iTask.getDuration()!=0) {
+ TimeUnit.MILLISECONDS.sleep(iTask.getDuration());
+ }else {
+ iTask.blockTask();
+ }
+ //完成任务
+ TaskEvent finishEvent = new TaskEvent();
+ finishEvent.setTask(iTask);
+ finishEvent.setEventType(TaskEvent.EventType.FINISH);
+ mTaskHandler.obtainMessage(MSG_EVENT_FINISH, finishEvent).sendToTarget();
+ }
+ }
+ } catch (Exception ex) {
+ ex.printStackTrace();
+ }
+ }
+ });
+ }
+ //根据不同的消息回调不同的方法。
+ private static class TaskHandler extends Handler {
+ TaskHandler() {
+ super(Looper.getMainLooper());
+ }
+
+ @Override
+ public void handleMessage(Message msg) {
+ super.handleMessage(msg);
+ TaskEvent taskEvent = (TaskEvent) msg.obj;
+ if (msg.what == MSG_EVENT_DO && taskEvent.getEventType() == TaskEvent.EventType.DO) {
+ taskEvent.getTask().doTask();
+ }
+ if (msg.what == MSG_EVENT_FINISH && taskEvent.getEventType() == TaskEvent.EventType.FINISH) {
+ taskEvent.getTask().finishTask();
+ }
+ }
+ }
+
+ public void startRunning() {
+ isRunning = true;
+ }
+
+ public void pauseRunning() {
+ isRunning = false;
+ }
+
+ public boolean isRunning() {
+ return isRunning;
+ }
+
+ public void resetExecutor() {
+ isRunning = true;
+ taskQueue.clear();
+ }
+
+ public void clearExecutor() {
+ pauseRunning();
+ taskQueue.clear();
+ }
+}
+
\ No newline at end of file
diff --git a/commonSPort/src/main/java/com/common/queue/TaskScheduler.java b/commonSPort/src/main/java/com/common/queue/TaskScheduler.java
new file mode 100644
index 0000000..7b04d2a
--- /dev/null
+++ b/commonSPort/src/main/java/com/common/queue/TaskScheduler.java
@@ -0,0 +1,44 @@
+package com.common.queue;
+
+import com.common.queue.Task.ITask;
+
+public class TaskScheduler {
+ private final String TAG = "TaskScheduler";
+ private BlockTaskQueue mTaskQueue = new BlockTaskQueue();
+ private TaskExecutor mExecutor;
+
+// private static class ShowDurationHolder {
+// private final static TaskScheduler INSTANCE = new TaskScheduler();
+// }
+
+ public TaskScheduler() {
+ initExecutor();
+ }
+
+ private void initExecutor() {
+ mExecutor = new TaskExecutor(mTaskQueue);
+ mExecutor.start();
+ }
+
+// public static TaskScheduler getInstance() {
+// return ShowDurationHolder.INSTANCE;
+// }
+
+ public void enqueue(ITask task) {
+ //因为TaskScheduler这里写成单例,如果isRunning改成false的话,不判断一下,就会一直都是false
+ if (!mExecutor.isRunning()) {
+ mExecutor.startRunning();
+ }
+ //按照优先级插入队列 依次播放
+ mTaskQueue.add(task);
+ }
+
+ public void resetExecutor() {
+ mExecutor.resetExecutor();
+ }
+
+ public void clearExecutor() {
+ mExecutor.clearExecutor();
+ }
+}
+
\ No newline at end of file
diff --git a/commonSPort/src/main/java/com/common/serialport/EasySerialPort.kt b/commonSPort/src/main/java/com/common/serialport/EasySerialPort.kt
new file mode 100644
index 0000000..ccb1fbc
--- /dev/null
+++ b/commonSPort/src/main/java/com/common/serialport/EasySerialPort.kt
@@ -0,0 +1,103 @@
+package com.common.serialport
+
+import android.util.Log
+import com.aill.androidserialport.SerialPort
+import com.common.serialport.inter.SerialPortHelper
+import com.common.queue.TaskScheduler
+import java.io.IOException
+
+class EasySerialPort(
+ private val portPath: String,
+ private val baudRate: Int,
+ private val mReceiver: (ByteArray) -> Unit
+) : Runnable {
+ private var mPort: SerialPort? = null
+ private var startReceiveMsg = true
+ private var autoRetryConnect = false
+
+ init {
+ openSerialPort();
+ }
+
+ private fun openSerialPort() {
+ mPort = SerialPortHelper.openSerialPort(portPath, baudRate)
+ mPort?.let {
+ startReceiveMsg = true
+ Thread(this).start()
+ }
+ }
+
+ /**
+ * 关闭串口
+ */
+ open fun closePort() {
+ startReceiveMsg = false
+ SerialPortHelper.closePort(mPort)
+ }
+
+ /**
+ * 循环读消息
+ */
+ override fun run() {
+ while (startReceiveMsg) {
+ try {
+ val ips = mPort?.inputStream
+ val readByte = ips?.available()?.let { ByteArray(it) }
+ readByte?.let {
+ val size = ips.read(it)
+ if (size > 0) {
+ mReceiver.invoke(readByte)
+ }
+ }
+ } catch (e: IOException) {
+ Log.e(
+ "EasySerialPort",
+ "read msg error; path = " + portPath + ", error msg = " + e.message
+ )
+ e.printStackTrace()
+ if (autoRetryConnect) {
+ closePort()
+ openSerialPort()
+ }
+ }
+ }
+ }
+
+ /**
+ * 写消息
+ */
+ open fun write(data: ByteArray) {
+ val task = SendMsgTask(data) {
+ try {
+ val outputStream = mPort?.outputStream
+ outputStream?.write(it)
+ outputStream?.flush()
+ } catch (e: IOException) {
+ Log.e(
+ "EasySerialPort",
+ "write msg error; path = " + portPath + ", error msg = " + e.message
+ )
+ e.printStackTrace()
+ if (autoRetryConnect) {
+ closePort()
+ openSerialPort()
+ }
+ }
+ }
+ TaskScheduler.getInstance().enqueue(task)
+ }
+
+ /**
+ * 开始自动重连
+ */
+ open fun enableAutoConnect() {
+ this.autoRetryConnect = true
+ }
+
+ /**
+ * 关闭自动重连
+ */
+ open fun disableAutoConnect() {
+ this.autoRetryConnect = true
+ }
+}
\ No newline at end of file
diff --git a/commonSPort/src/main/java/com/common/serialport/SendMsgTask.kt b/commonSPort/src/main/java/com/common/serialport/SendMsgTask.kt
new file mode 100644
index 0000000..f3392db
--- /dev/null
+++ b/commonSPort/src/main/java/com/common/serialport/SendMsgTask.kt
@@ -0,0 +1,14 @@
+package com.common.serialport
+
+import com.common.queue.Task.BaseTask
+
+class SendMsgTask(private val byteArray: ByteArray, private val action: (ByteArray) -> Unit) :
+ BaseTask() {
+
+ override fun doTask() {
+ super.doTask()
+ action.invoke(byteArray)
+ unLockBlock()
+ }
+
+}
\ No newline at end of file
diff --git a/commonSPort/src/main/java/com/common/serialport/inter/IHelper.kt b/commonSPort/src/main/java/com/common/serialport/inter/IHelper.kt
new file mode 100644
index 0000000..8f0fbea
--- /dev/null
+++ b/commonSPort/src/main/java/com/common/serialport/inter/IHelper.kt
@@ -0,0 +1,10 @@
+package com.common.serialport.inter
+
+import com.aill.androidserialport.SerialPort
+
+interface IHelper {
+
+ fun openSerialPort(portPath: String, baudrate: Int): SerialPort?;
+
+ fun closePort(port: SerialPort?);
+}
\ No newline at end of file
diff --git a/commonSPort/src/main/java/com/common/serialport/inter/SerialPortHelper.kt b/commonSPort/src/main/java/com/common/serialport/inter/SerialPortHelper.kt
new file mode 100644
index 0000000..8cecf6a
--- /dev/null
+++ b/commonSPort/src/main/java/com/common/serialport/inter/SerialPortHelper.kt
@@ -0,0 +1,29 @@
+package com.common.serialport.inter
+
+import android.util.Log
+import com.aill.androidserialport.SerialPort
+import java.io.File
+import java.io.IOException
+
+object SerialPortHelper : IHelper {
+ override fun openSerialPort(portPath: String, baudrate: Int): SerialPort? {
+ try {
+ return SerialPort(File(portPath), baudrate, 0);
+ } catch (e: IOException) {
+ e.printStackTrace()
+ Log.e("SerialPortHelper", "open port error; " + e.message)
+ }
+ return null;
+ }
+
+ override fun closePort(port: SerialPort?) {
+ try {
+ port?.close()
+ port?.inputStream?.close()
+ port?.outputStream?.close()
+ } catch (e: Exception) {
+ e.printStackTrace()
+ Log.e("SerialPortHelper", "closePort error; " + e.message)
+ }
+ }
+}
\ No newline at end of file
diff --git a/commonSPort/src/main/java/com/common/serialport/utils/CommonPortUtils.kt b/commonSPort/src/main/java/com/common/serialport/utils/CommonPortUtils.kt
new file mode 100644
index 0000000..1128523
--- /dev/null
+++ b/commonSPort/src/main/java/com/common/serialport/utils/CommonPortUtils.kt
@@ -0,0 +1,70 @@
+package com.common.serialport.utils
+
+import com.common.serialport.EasySerialPort
+
+/**
+ * @author xiaowusky
+ * 操作串口工具类
+ * 可以同时处理多个串口操作
+ */
+object CommonPortUtils {
+
+ private val portMaps = HashMap()
+
+ /**
+ * 打开串口
+ * @param portPath 串口地址
+ * @param baudRate 波特率
+ * @param mReceiver 接收消息回调
+ */
+ fun openPort(
+ portPath: String,
+ baudRate: Int,
+ mReceiver: (ByteArray) -> Unit
+ ) {
+ if (portMaps.containsKey(portPath)) {
+ return
+ }
+ val easyPort = EasySerialPort(portPath, baudRate, mReceiver)
+ portMaps.put(portPath, easyPort)
+ }
+
+ /**
+ * 发送消息
+ * @param portPath 串口地址
+ * @param data 消息byte数组
+ */
+ fun sendMsg(portPath: String, data: ByteArray) {
+ SinglePortUtils.easyPort?.write(data)
+ }
+
+ /**
+ * 发送消息
+ * @param portPath 串口地址
+ * @param data String类型消息,内部会toByteArray
+ */
+ fun sendMsg(portPath: String, data: String) {
+ SinglePortUtils.easyPort?.write(data.toByteArray())
+ }
+
+ /**
+ * 释放某个串口
+ * @param portPath 串口地址
+ */
+ fun release(portPath: String) {
+ if (portMaps.containsKey(portPath)) {
+ portMaps.get(portPath)?.closePort()
+ }
+ portMaps.remove(portPath)
+ }
+
+ /**
+ * 释放所有串口
+ */
+ fun releaseAll() {
+ portMaps.forEach {
+ it.value?.closePort()
+ }
+ portMaps.clear()
+ }
+}
\ No newline at end of file
diff --git a/commonSPort/src/main/java/com/common/serialport/utils/DataUtils.java b/commonSPort/src/main/java/com/common/serialport/utils/DataUtils.java
new file mode 100644
index 0000000..a5d45bd
--- /dev/null
+++ b/commonSPort/src/main/java/com/common/serialport/utils/DataUtils.java
@@ -0,0 +1,139 @@
+package com.common.serialport.utils;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * 串口数据转换工具类
+ * Created by Administrator on 2016/6/2.
+ */
+public class DataUtils {
+ //-------------------------------------------------------
+ // 判断奇数或偶数,位运算,最后一位是1则为奇数,为0是偶数
+ public static int isOdd(int num) {
+ return num & 1;
+ }
+
+ //-------------------------------------------------------
+ //Hex字符串转int
+ public static int HexToInt(String inHex) {
+ return Integer.parseInt(inHex, 16);
+ }
+
+ public static String IntToHex(int intHex){
+ return Integer.toHexString(intHex);
+ }
+
+ //-------------------------------------------------------
+ //Hex字符串转byte
+ public static byte HexToByte(String inHex) {
+ return (byte) Integer.parseInt(inHex, 16);
+ }
+
+ //-------------------------------------------------------
+ //1字节转2个Hex字符
+ public static String Byte2Hex(Byte inByte) {
+ return String.format("%02x", new Object[]{inByte}).toUpperCase();
+ }
+
+ //-------------------------------------------------------
+ //字节数组转转hex字符串
+ public static String ByteArrToHex(byte[] inBytArr) {
+ StringBuilder strBuilder = new StringBuilder();
+ for (byte valueOf : inBytArr) {
+ strBuilder.append(Byte2Hex(Byte.valueOf(valueOf)));
+ strBuilder.append(" ");
+ }
+ return strBuilder.toString();
+ }
+
+ //-------------------------------------------------------
+ //字节数组转转hex字符串,可选长度
+ public static String ByteArrToHex(byte[] inBytArr, int offset, int byteCount) {
+ StringBuilder strBuilder = new StringBuilder();
+ int j = byteCount;
+ for (int i = offset; i < j; i++) {
+ strBuilder.append(Byte2Hex(Byte.valueOf(inBytArr[i])));
+ }
+ return strBuilder.toString();
+ }
+
+ //-------------------------------------------------------
+ //转hex字符串转字节数组
+ public static byte[] HexToByteArr(String inHex) {
+ byte[] result;
+ int hexlen = inHex.length();
+ if (isOdd(hexlen) == 1) {
+ hexlen++;
+ result = new byte[(hexlen / 2)];
+ inHex = "0" + inHex;
+ } else {
+ result = new byte[(hexlen / 2)];
+ }
+ int j = 0;
+ for (int i = 0; i < hexlen; i += 2) {
+ result[j] = HexToByte(inHex.substring(i, i + 2));
+ j++;
+ }
+ return result;
+ }
+
+ /**
+ * 按照指定长度切割字符串
+ *
+ * @param inputString 需要切割的源字符串
+ * @param length 指定的长度
+ * @return
+ */
+ public static List getDivLines(String inputString, int length) {
+ List divList = new ArrayList<>();
+ int remainder = (inputString.length()) % length;
+ // 一共要分割成几段
+ int number = (int) Math.floor((inputString.length()) / length);
+ for (int index = 0; index < number; index++) {
+ String childStr = inputString.substring(index * length, (index + 1) * length);
+ divList.add(childStr);
+ }
+ if (remainder > 0) {
+ String cStr = inputString.substring(number * length, inputString.length());
+ divList.add(cStr);
+ }
+ return divList;
+ }
+
+ /**
+ * 计算长度,两个字节长度
+ *
+ * @param val value
+ * @return 结果
+ */
+ public static String twoByte(String val) {
+ if (val.length() > 4) {
+ val = val.substring(0, 4);
+ } else {
+ int l = 4 - val.length();
+ for (int i = 0; i < l; i++) {
+ val = "0" + val;
+ }
+ }
+ return val;
+ }
+
+ /**
+ * 校验和
+ *
+ * @param cmd 指令
+ * @return 结果
+ */
+ public static String sum(String cmd) {
+ List cmdList = DataUtils.getDivLines(cmd, 2);
+ int sumInt = 0;
+ for (String c : cmdList) {
+ sumInt += DataUtils.HexToInt(c);
+ }
+ String sum = DataUtils.IntToHex(sumInt);
+ sum = DataUtils.twoByte(sum);
+ cmd += sum;
+ return cmd.toUpperCase();
+ }
+}
diff --git a/commonSPort/src/main/java/com/common/serialport/utils/SinglePortUtils.kt b/commonSPort/src/main/java/com/common/serialport/utils/SinglePortUtils.kt
new file mode 100644
index 0000000..7d06f16
--- /dev/null
+++ b/commonSPort/src/main/java/com/common/serialport/utils/SinglePortUtils.kt
@@ -0,0 +1,51 @@
+
+package com.common.serialport.utils
+
+import com.common.serialport.EasySerialPort
+
+/**
+ * @author xiaowusky
+ * 操作单个串口工具类
+ */
+object SinglePortUtils {
+ var easyPort: EasySerialPort? = null
+
+ /**
+ * 初始化参数
+ * @param portPath 串口地址
+ * @param baudRate 波特率
+ * @param mReceiver 接收消息回调
+ */
+ fun initParams(
+ portPath: String,
+ baudRate: Int,
+ mReceiver: (ByteArray) -> Unit
+ ) {
+ easyPort = EasySerialPort(portPath, baudRate, mReceiver)
+ }
+
+ /**
+ * 发送消息
+ * @param portPath 串口地址
+ * @param data 消息byte数组
+ */
+ fun sendMsg(data: ByteArray) {
+ easyPort?.write(data)
+ }
+
+ /**
+ * 发送消息
+ * @param portPath 串口地址
+ * @param data String类型消息,内部会toByteArray
+ */
+ fun sendMsg(data: String) {
+ easyPort?.write(data.toByteArray())
+ }
+
+ /**
+ * 释放串口
+ */
+ fun release(){
+ easyPort?.closePort()
+ }
+}
\ No newline at end of file
diff --git a/settings.gradle b/settings.gradle
index 7e85a5e..4531efe 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -1,3 +1,4 @@
include ':myapplication' //, ':libuvccamera-release'
include ':library'
include ':ijkplayer-java'
+include ':commonSPort'