上传文件至 /
This commit is contained in:
parent
ca07a146f3
commit
43acbcfd33
|
@ -24,8 +24,8 @@ import androidx.room.PrimaryKey;
|
||||||
public String humidity="0"; // 湿度
|
public String humidity="0"; // 湿度
|
||||||
public String weather="0"; // 天气状况
|
public String weather="0"; // 天气状况
|
||||||
public String imageSource="-1";
|
public String imageSource="-1";
|
||||||
|
public String partid;
|
||||||
public ImageEntity(String path, long time, double latitude, double longitude, double altitude, String user, String audioPath, String project, String unit, int blade, boolean b,String unitName,String temperature,String humidity,String weather,String imageSource) {
|
public ImageEntity(String path, long time, double latitude, double longitude, double altitude, String user, String audioPath, String project, String unit, int blade, boolean b,String unitName,String temperature,String humidity,String weather,String imageSource,String partid) {
|
||||||
|
|
||||||
this.path = path;
|
this.path = path;
|
||||||
this.time = time;
|
this.time = time;
|
||||||
|
@ -43,6 +43,7 @@ import androidx.room.PrimaryKey;
|
||||||
this.humidity=humidity;
|
this.humidity=humidity;
|
||||||
this.unitName=unitName;
|
this.unitName=unitName;
|
||||||
this.imageSource=imageSource;
|
this.imageSource=imageSource;
|
||||||
|
this.partid=partid;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,575 @@
|
||||||
|
package com.example.myapplication.Service;
|
||||||
|
|
||||||
|
import android.app.Notification;
|
||||||
|
import android.app.NotificationChannel;
|
||||||
|
import android.app.NotificationManager;
|
||||||
|
import android.app.PendingIntent;
|
||||||
|
import android.app.Service;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.database.ContentObserver;
|
||||||
|
import android.database.Cursor;
|
||||||
|
import android.location.Location;
|
||||||
|
import android.location.LocationManager;
|
||||||
|
import android.media.ExifInterface;
|
||||||
|
import android.net.ConnectivityManager;
|
||||||
|
import android.net.NetworkCapabilities;
|
||||||
|
import android.net.Uri;
|
||||||
|
import android.os.Build;
|
||||||
|
import android.os.Handler;
|
||||||
|
import android.os.IBinder;
|
||||||
|
import android.os.Looper;
|
||||||
|
import android.provider.MediaStore;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
|
import androidx.core.app.NotificationCompat;
|
||||||
|
import androidx.room.Room;
|
||||||
|
|
||||||
|
import com.example.myapplication.DataBase.AppDatabase;
|
||||||
|
import com.example.myapplication.R;
|
||||||
|
import com.example.myapplication.Tool.BackgroundToast;
|
||||||
|
import com.example.myapplication.Tool.NotificationReceiver;
|
||||||
|
import com.example.myapplication.model.ImageEntity;
|
||||||
|
import com.example.myapplication.model.SharedDataManager;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.concurrent.ExecutorService;
|
||||||
|
import java.util.concurrent.Executors;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
import okhttp3.MediaType;
|
||||||
|
import okhttp3.MultipartBody;
|
||||||
|
import okhttp3.OkHttpClient;
|
||||||
|
import okhttp3.Request;
|
||||||
|
import okhttp3.RequestBody;
|
||||||
|
import okhttp3.Response;
|
||||||
|
|
||||||
|
public class PhotoMonitoringService extends Service implements SharedDataManager.DataChangeListener {
|
||||||
|
private static final String CHANNEL_ID = "PhotoMonitoringChannel";
|
||||||
|
private static final int NOTIFICATION_ID = 101;
|
||||||
|
private static final int THUMBNAIL_SIZE = 100;
|
||||||
|
|
||||||
|
// 锁对象
|
||||||
|
private final Object monitoringLock = new Object();
|
||||||
|
private final Object uploadLock = new Object();
|
||||||
|
|
||||||
|
// 状态标志
|
||||||
|
private boolean isMonitoring = false;
|
||||||
|
private boolean isUploading = false;
|
||||||
|
private boolean isRecording = false;
|
||||||
|
private int successCount = 0;
|
||||||
|
private int failureCount = 0;
|
||||||
|
|
||||||
|
// 组件
|
||||||
|
private ContentObserver contentObserver;
|
||||||
|
private final ExecutorService executor = Executors.newFixedThreadPool(6);
|
||||||
|
private final OkHttpClient httpClient = new OkHttpClient.Builder()
|
||||||
|
.connectTimeout(30, TimeUnit.SECONDS) // 连接超时
|
||||||
|
.readTimeout(60, TimeUnit.SECONDS) // 读取超时
|
||||||
|
.writeTimeout(60, TimeUnit.SECONDS) // 写入超时
|
||||||
|
.build();
|
||||||
|
|
||||||
|
// 数据库
|
||||||
|
private AppDatabase db;
|
||||||
|
private AppDatabase db2;
|
||||||
|
|
||||||
|
// 位置相关
|
||||||
|
private Location lastKnownLocation;
|
||||||
|
private LocationManager locationManager;
|
||||||
|
|
||||||
|
// 配置参数
|
||||||
|
private String token;
|
||||||
|
private String user;
|
||||||
|
private String projectId;
|
||||||
|
private String unit;
|
||||||
|
private int blade;
|
||||||
|
private String unitName;
|
||||||
|
private String Temperator;
|
||||||
|
private String Humidity;
|
||||||
|
private String Weather;
|
||||||
|
private String ChooseImageSource;
|
||||||
|
|
||||||
|
// 其他状态
|
||||||
|
private long lastPhotoId = 0;
|
||||||
|
private String currentAudioPath="0";
|
||||||
|
private String imgpath="-1";
|
||||||
|
private String partid="-1";
|
||||||
|
|
||||||
|
// 回调接口
|
||||||
|
private MonitoringCallback callback;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onImagePathChanged(String newPath) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onTokenChanged(String newToken) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onUserChanged(String newUser) {
|
||||||
|
user=newUser;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onAudioPathChanged(String newAudioPath) {
|
||||||
|
currentAudioPath=newAudioPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onProjectIdChanged(String newProjectId) {
|
||||||
|
projectId=newProjectId;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onUnitChanged(String newUnit) {
|
||||||
|
unit=newUnit;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onBladeChanged(int newBlade) {
|
||||||
|
blade=newBlade;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onPartidChanged(String newPartid) {
|
||||||
|
partid=newPartid;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onChooseImageSourceChanged(String newChooseImageSource) {
|
||||||
|
ChooseImageSource=newChooseImageSource;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onUnitNameChanged(String newUnitName) {
|
||||||
|
unitName=newUnitName;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onIsRecordingChanged(boolean newisRecording) {
|
||||||
|
isRecording=newisRecording;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onUploadingStatusChanged(boolean isUploading) {
|
||||||
|
this.isUploading=isUploading;
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface MonitoringCallback {
|
||||||
|
void onUploadSuccess(String filePath);
|
||||||
|
void onUploadFailure(String filePath, String error);
|
||||||
|
void onStatusChanged(boolean isMonitoring);
|
||||||
|
}
|
||||||
|
SharedDataManager dataManager ;
|
||||||
|
@Override
|
||||||
|
public void onCreate() {
|
||||||
|
super.onCreate();
|
||||||
|
createNotificationChannel();
|
||||||
|
|
||||||
|
// 初始化数据库
|
||||||
|
db = Room.databaseBuilder(getApplicationContext(),
|
||||||
|
AppDatabase.class, "image-database").build();
|
||||||
|
db2 = Room.databaseBuilder(getApplicationContext(),
|
||||||
|
AppDatabase.class, "image-database2").build();
|
||||||
|
|
||||||
|
// 初始化位置管理器
|
||||||
|
locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
|
||||||
|
dataManager=SharedDataManager.getInstance();
|
||||||
|
|
||||||
|
dataManager.addListener(this);
|
||||||
|
updateFromSharedData();
|
||||||
|
}
|
||||||
|
private void updateFromSharedData() {
|
||||||
|
dataManager = SharedDataManager.getInstance();
|
||||||
|
this.token = dataManager.getToken();
|
||||||
|
this.user = dataManager.getUser();
|
||||||
|
this.currentAudioPath = dataManager.getAudioPath();
|
||||||
|
this.projectId = dataManager.getProjectId();
|
||||||
|
this.unit = dataManager.getUnit();
|
||||||
|
this.blade = dataManager.getBlade();
|
||||||
|
this.ChooseImageSource = dataManager.getChooseImageSource();
|
||||||
|
this.unitName = dataManager.getUnitName();
|
||||||
|
this.partid=dataManager.getPartid();
|
||||||
|
this.isUploading=dataManager.getisUploading();
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public int onStartCommand(Intent intent, int flags, int startId) {
|
||||||
|
// 从intent中获取配置参数
|
||||||
|
if (intent != null && "start_monitoring".equals(intent.getStringExtra("command"))) {
|
||||||
|
startMonitoring();
|
||||||
|
}
|
||||||
|
|
||||||
|
startForeground(NOTIFICATION_ID, buildNotification("服务正在运行", "监听照片变化中"));
|
||||||
|
|
||||||
|
return START_STICKY;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@Override
|
||||||
|
public IBinder onBind(Intent intent) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onDestroy() {
|
||||||
|
stopMonitoring();
|
||||||
|
super.onDestroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 公共接口方法
|
||||||
|
public void startMonitoring() {
|
||||||
|
|
||||||
|
synchronized (monitoringLock) {
|
||||||
|
if (isMonitoring) return;
|
||||||
|
|
||||||
|
lastPhotoId = getLastPhotoId();
|
||||||
|
|
||||||
|
contentObserver = new ContentObserver(new Handler(Looper.getMainLooper())) {
|
||||||
|
@Override
|
||||||
|
public void onChange(boolean selfChange, Uri uri) {
|
||||||
|
super.onChange(selfChange, uri);
|
||||||
|
if (!isRecording && uri != null && uri.toString().contains("images/media")) {
|
||||||
|
checkNewPhotos();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
getContentResolver().registerContentObserver(
|
||||||
|
MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
|
||||||
|
true,
|
||||||
|
contentObserver
|
||||||
|
);
|
||||||
|
|
||||||
|
isMonitoring = true;
|
||||||
|
if (callback != null) {
|
||||||
|
callback.onStatusChanged(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查已有照片
|
||||||
|
executor.execute(() -> {
|
||||||
|
List<ImageEntity> history = db2.imageDao().getAll();
|
||||||
|
if (history != null && !history.isEmpty()) {
|
||||||
|
synchronized (uploadLock) {
|
||||||
|
for (ImageEntity image : history) {
|
||||||
|
String partname = getPartName(image.blade);
|
||||||
|
if (partid == null) partid = partname;
|
||||||
|
uploadPhoto(image.path, image.time, lastKnownLocation, image.user,
|
||||||
|
image.audioPath, image.project, image.unit, image.blade,
|
||||||
|
partid, image.imageSource, image.unitName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
db2.imageDao().deleteAll();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void stopMonitoring() {
|
||||||
|
synchronized (monitoringLock) {
|
||||||
|
if (!isMonitoring) return;
|
||||||
|
|
||||||
|
if (contentObserver != null) {
|
||||||
|
getContentResolver().unregisterContentObserver(contentObserver);
|
||||||
|
contentObserver = null;
|
||||||
|
}
|
||||||
|
if (callback != null) {
|
||||||
|
callback.onStatusChanged(false);
|
||||||
|
}
|
||||||
|
isMonitoring=false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private String getPartName(int b)
|
||||||
|
{
|
||||||
|
return "叶片" +b;
|
||||||
|
}
|
||||||
|
public void setCallback(MonitoringCallback callback) {
|
||||||
|
this.callback = callback;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isMonitoring() {
|
||||||
|
return isMonitoring;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 私有方法
|
||||||
|
private void checkNewPhotos() {
|
||||||
|
String[] projection = {
|
||||||
|
MediaStore.Images.Media._ID,
|
||||||
|
MediaStore.Images.Media.DATA,
|
||||||
|
MediaStore.Images.Media.DATE_ADDED,
|
||||||
|
MediaStore.Images.Media.DATE_TAKEN,
|
||||||
|
MediaStore.Images.Media.LATITUDE,
|
||||||
|
MediaStore.Images.Media.LONGITUDE
|
||||||
|
};
|
||||||
|
|
||||||
|
String selection = MediaStore.Images.Media._ID + " > ? AND " +
|
||||||
|
MediaStore.Images.Media.DATE_TAKEN + " > 0 AND " +
|
||||||
|
"(" + MediaStore.Images.Media.DATA + " LIKE '%/DCIM/%' OR " +
|
||||||
|
MediaStore.Images.Media.DATA + " LIKE '%/Camera/%')";
|
||||||
|
String[] selectionArgs = new String[]{String.valueOf(lastPhotoId)};
|
||||||
|
|
||||||
|
try (Cursor cursor = getContentResolver().query(
|
||||||
|
MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
|
||||||
|
projection,
|
||||||
|
selection,
|
||||||
|
selectionArgs,
|
||||||
|
MediaStore.Images.Media._ID + " DESC"
|
||||||
|
)) {
|
||||||
|
if (cursor != null) {
|
||||||
|
while (cursor.moveToNext()) {
|
||||||
|
processNewPhoto(cursor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
Log.e("PhotoMonitoringService", "Error checking new photos", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void processNewPhoto(Cursor cursor) {
|
||||||
|
long id = cursor.getLong(0);
|
||||||
|
String path = cursor.getString(1);
|
||||||
|
imgpath = path;
|
||||||
|
dataManager.setImagePath(imgpath);
|
||||||
|
long time = cursor.getLong(2) * 1000;
|
||||||
|
double latitude = cursor.getDouble(3);
|
||||||
|
double longitude = cursor.getDouble(4);
|
||||||
|
double altitude = 0.0;
|
||||||
|
|
||||||
|
try {
|
||||||
|
Location lastLocation = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER);
|
||||||
|
if (lastLocation != null) {
|
||||||
|
lastKnownLocation = lastLocation;
|
||||||
|
}
|
||||||
|
} catch (SecurityException e) {
|
||||||
|
Log.w("PhotoMonitoringService", "Location permission not granted");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lastKnownLocation != null) {
|
||||||
|
latitude = lastKnownLocation.getLatitude();
|
||||||
|
longitude = lastKnownLocation.getLongitude();
|
||||||
|
altitude = lastKnownLocation.getAltitude();
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
ExifInterface exif = new ExifInterface(path);
|
||||||
|
String altitudeStr = exif.getAttribute(ExifInterface.TAG_GPS_ALTITUDE);
|
||||||
|
if (altitudeStr != null) {
|
||||||
|
altitude = Double.parseDouble(altitudeStr);
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
Log.e("PhotoMonitoringService", "Error reading EXIF data", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
String audioPath = currentAudioPath == null ? "0" : currentAudioPath;
|
||||||
|
lastPhotoId = Math.max(lastPhotoId, id);
|
||||||
|
|
||||||
|
if (isNetworkAvailable() && !isRecording) {
|
||||||
|
uploadNewPhoto(path, time, audioPath, latitude, longitude, altitude);
|
||||||
|
} else {
|
||||||
|
queuePhotoForLater(path, time, audioPath, latitude, longitude, altitude);
|
||||||
|
}
|
||||||
|
|
||||||
|
currentAudioPath = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void uploadNewPhoto(String path, long time, String audioPath,
|
||||||
|
double latitude, double longitude, double altitude) {
|
||||||
|
executor.execute(() -> {
|
||||||
|
List<ImageEntity> history = db2.imageDao().getAll();
|
||||||
|
if (history != null && !history.isEmpty()) {
|
||||||
|
synchronized (uploadLock) {
|
||||||
|
for (ImageEntity image : history) {
|
||||||
|
String partname = getPartName(image.blade);
|
||||||
|
String ipartid = image.partid;
|
||||||
|
if (ipartid == null) ipartid = partname;
|
||||||
|
uploadPhoto(image.path, image.time, lastKnownLocation,
|
||||||
|
image.user, image.audioPath, image.project,
|
||||||
|
image.unit, image.blade, ipartid, image.imageSource, image.unitName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
db2.imageDao().deleteAll();
|
||||||
|
|
||||||
|
String partname = getPartName(blade);
|
||||||
|
|
||||||
|
if (partid == null) partid = partname;
|
||||||
|
|
||||||
|
uploadPhoto(path, time, lastKnownLocation, user,
|
||||||
|
audioPath, projectId, unit, blade, partid, ChooseImageSource, unitName);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void queuePhotoForLater(String path, long time, String audioPath,
|
||||||
|
double latitude, double longitude, double altitude) {
|
||||||
|
executor.execute(() -> {
|
||||||
|
String partname = getPartName(blade);
|
||||||
|
|
||||||
|
if (partid == null) partid = partname;
|
||||||
|
|
||||||
|
db2.imageDao().insert(new ImageEntity(path, time, latitude, longitude, altitude,
|
||||||
|
user, audioPath, projectId, unit, blade, false, unitName,
|
||||||
|
Temperator, Humidity, Weather, ChooseImageSource,partid));
|
||||||
|
|
||||||
|
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void uploadPhoto(String filePath, long time, Location location, String user,
|
||||||
|
String audioPath, String project, String unit, int blade,
|
||||||
|
String partid, String imageSource, String unitName) {
|
||||||
|
synchronized (uploadLock) {
|
||||||
|
if (isUploading) {
|
||||||
|
queuePhotoForLater(filePath, time, audioPath,
|
||||||
|
location != null ? location.getLatitude() : 0,
|
||||||
|
location != null ? location.getLongitude() : 0,
|
||||||
|
location != null ? location.getAltitude() : 0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
executor.execute(() -> {
|
||||||
|
try {
|
||||||
|
File imageFile = new File(filePath);
|
||||||
|
if (!imageFile.exists()) {
|
||||||
|
if (callback != null) {
|
||||||
|
callback.onUploadFailure(filePath, "File does not exist");
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
double latitude = location != null ? location.getLatitude() : 0;
|
||||||
|
double longitude = location != null ? location.getLongitude() : 0;
|
||||||
|
double altitude = location != null ? location.getAltitude() : 0;
|
||||||
|
|
||||||
|
MultipartBody.Builder builder = new MultipartBody.Builder()
|
||||||
|
.setType(MultipartBody.FORM)
|
||||||
|
.addFormDataPart("image", imageFile.getName(),
|
||||||
|
RequestBody.create(imageFile, MediaType.parse("image/*")))
|
||||||
|
.addFormDataPart("time", String.valueOf(time))
|
||||||
|
.addFormDataPart("latitude", String.valueOf(latitude))
|
||||||
|
.addFormDataPart("longitude", String.valueOf(longitude))
|
||||||
|
.addFormDataPart("altitude", String.valueOf(altitude))
|
||||||
|
.addFormDataPart("uploadUser", user)
|
||||||
|
.addFormDataPart("projectId", project)
|
||||||
|
.addFormDataPart("turbineId", unit)
|
||||||
|
.addFormDataPart("partId", partid)
|
||||||
|
.addFormDataPart("imageSource", imageSource);
|
||||||
|
|
||||||
|
RequestBody requestBody = builder.build();
|
||||||
|
Request request = new Request.Builder()
|
||||||
|
.url("http://pms.dtyx.net:9158/common/upload-image/file")
|
||||||
|
.post(requestBody)
|
||||||
|
.addHeader("Authorization", token)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
try (Response response = httpClient.newCall(request).execute()) {
|
||||||
|
if (response.isSuccessful()) {
|
||||||
|
db.imageDao().insert(new ImageEntity(filePath, time, latitude, longitude, altitude,
|
||||||
|
user, audioPath, project, unit, blade, true, unitName,
|
||||||
|
Temperator, Humidity, Weather, ChooseImageSource,partid));
|
||||||
|
|
||||||
|
if (callback != null) {
|
||||||
|
successCount++;
|
||||||
|
Log.d("上传成功:","已经上传成功"+successCount+"张图片");
|
||||||
|
BackgroundToast.show(this,"已经上传成功"+successCount+"张图片");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
db2.imageDao().insert(new ImageEntity(filePath, time, latitude, longitude, altitude,
|
||||||
|
user, audioPath, project, unit, blade, false, unitName,
|
||||||
|
Temperator, Humidity, Weather, ChooseImageSource,partid));
|
||||||
|
|
||||||
|
if (callback != null) {
|
||||||
|
failureCount++;
|
||||||
|
BackgroundToast.show(this,"上传失败"+response.code()+response.message());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
db2.imageDao().insert(new ImageEntity(filePath, time, 0, 0, 0,
|
||||||
|
user, audioPath, project, unit, blade, false, unitName,
|
||||||
|
Temperator, Humidity, Weather, ChooseImageSource,partid));
|
||||||
|
|
||||||
|
if (callback != null) {
|
||||||
|
BackgroundToast.show(this,"io错误"+e.getMessage());
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isNetworkAvailable() {
|
||||||
|
ConnectivityManager cm = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
|
||||||
|
if (cm == null) return false;
|
||||||
|
|
||||||
|
NetworkCapabilities capabilities = cm.getNetworkCapabilities(cm.getActiveNetwork());
|
||||||
|
return capabilities != null &&
|
||||||
|
(capabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) ||
|
||||||
|
capabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) ||
|
||||||
|
capabilities.hasTransport(NetworkCapabilities.TRANSPORT_ETHERNET));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
private void createNotificationChannel() {
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||||
|
NotificationChannel channel = new NotificationChannel(
|
||||||
|
CHANNEL_ID,
|
||||||
|
"照片上传服务",
|
||||||
|
NotificationManager.IMPORTANCE_HIGH // 使用高优先级确保通知显示
|
||||||
|
);
|
||||||
|
channel.setDescription("显示照片上传状态和进度");
|
||||||
|
NotificationManager manager = getSystemService(NotificationManager.class);
|
||||||
|
manager.createNotificationChannel(channel);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private Notification buildNotification(String title, String content) {
|
||||||
|
return new NotificationCompat.Builder(this, CHANNEL_ID)
|
||||||
|
.setContentTitle(title)
|
||||||
|
.setContentText(content)
|
||||||
|
.setSmallIcon(R.drawable.ic_upload) // 使用上传图标
|
||||||
|
.setPriority(NotificationCompat.PRIORITY_HIGH)
|
||||||
|
.setOngoing(true) // 设置为持续通知
|
||||||
|
.setOnlyAlertOnce(true) // 更新时不重复提醒
|
||||||
|
.addAction(createStopAction())
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
private NotificationCompat.Action createStopAction() {
|
||||||
|
Intent stopIntent = new Intent(this, NotificationReceiver.class);
|
||||||
|
stopIntent.setAction("ACTION_STOP_SERVICE");
|
||||||
|
// 修改这一行,添加 FLAG_IMMUTABLE 或 FLAG_MUTABLE
|
||||||
|
PendingIntent stopPendingIntent = PendingIntent.getBroadcast(
|
||||||
|
this,
|
||||||
|
0,
|
||||||
|
stopIntent,
|
||||||
|
PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_UPDATE_CURRENT); // 添加 FLAG_IMMUTABLE
|
||||||
|
|
||||||
|
return new NotificationCompat.Action(
|
||||||
|
R.drawable.ic_stop, "停止", stopPendingIntent);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private long getLastPhotoId() {
|
||||||
|
long id = -1;
|
||||||
|
Cursor cursor = getContentResolver().query(
|
||||||
|
MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
|
||||||
|
new String[]{"MAX(" + MediaStore.Images.Media._ID + ")"},
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null
|
||||||
|
);
|
||||||
|
|
||||||
|
if (cursor != null && cursor.moveToFirst()) {
|
||||||
|
id = cursor.getLong(0); // MAX(_ID) 的结果在索引 0
|
||||||
|
cursor.close();
|
||||||
|
}
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -7,8 +7,12 @@ import android.app.Service;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.pm.PackageManager;
|
import android.content.pm.PackageManager;
|
||||||
import android.content.pm.ServiceInfo;
|
import android.content.pm.ServiceInfo;
|
||||||
|
import android.media.MediaRecorder;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
|
import android.os.Handler;
|
||||||
import android.os.IBinder;
|
import android.os.IBinder;
|
||||||
|
import android.os.Looper;
|
||||||
|
import android.util.Log;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
import androidx.annotation.RequiresApi;
|
import androidx.annotation.RequiresApi;
|
||||||
|
@ -16,12 +20,60 @@ import androidx.core.app.ActivityCompat;
|
||||||
import androidx.core.app.NotificationCompat;
|
import androidx.core.app.NotificationCompat;
|
||||||
import androidx.core.app.NotificationManagerCompat;
|
import androidx.core.app.NotificationManagerCompat;
|
||||||
|
|
||||||
|
|
||||||
|
import androidx.lifecycle.Observer;
|
||||||
|
import androidx.lifecycle.ViewModelProvider;
|
||||||
|
import androidx.room.Room;
|
||||||
|
|
||||||
|
import com.example.myapplication.DataBase.AppDatabase;
|
||||||
|
|
||||||
import com.example.myapplication.R;
|
import com.example.myapplication.R;
|
||||||
|
import com.example.myapplication.Tool.BackgroundToast;
|
||||||
|
import com.example.myapplication.model.AudioEntity;
|
||||||
|
import com.example.myapplication.model.SharedDataManager;
|
||||||
|
|
||||||
public class RecordingService extends Service {
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.text.SimpleDateFormat;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.Locale;
|
||||||
|
import java.util.concurrent.ExecutorService;
|
||||||
|
import java.util.concurrent.Executors;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
import io.reactivex.disposables.Disposable;
|
||||||
|
import okhttp3.MediaType;
|
||||||
|
import okhttp3.MultipartBody;
|
||||||
|
import okhttp3.OkHttpClient;
|
||||||
|
import okhttp3.Request;
|
||||||
|
import okhttp3.RequestBody;
|
||||||
|
import okhttp3.Response;
|
||||||
|
|
||||||
|
public class RecordingService extends Service implements SharedDataManager.DataChangeListener {
|
||||||
private static final String CHANNEL_ID = "recording_channel";
|
private static final String CHANNEL_ID = "recording_channel";
|
||||||
private static final int NOTIFICATION_ID = 1;
|
private static final int NOTIFICATION_ID = 2;
|
||||||
|
private MediaRecorder mediaRecorder;
|
||||||
|
private String currentAudioPath;
|
||||||
|
private Handler handler;
|
||||||
|
private Runnable updateTimerRunnable;
|
||||||
|
private AppDatabase db;
|
||||||
|
private AppDatabase db2;
|
||||||
|
private final ExecutorService executor = Executors.newFixedThreadPool(4);
|
||||||
|
private String currentImagePath="-1";
|
||||||
|
private String currentToken="-1";
|
||||||
|
private SharedDataManager dataManager;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public IBinder onBind(Intent intent) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private final OkHttpClient httpClient = new OkHttpClient.Builder()
|
||||||
|
.connectTimeout(30, TimeUnit.SECONDS) // 连接超时
|
||||||
|
.readTimeout(60, TimeUnit.SECONDS) // 读取超时
|
||||||
|
.writeTimeout(60, TimeUnit.SECONDS) // 写入超时
|
||||||
|
.build();
|
||||||
|
private int recordingSeconds = 0;
|
||||||
@RequiresApi(api = Build.VERSION_CODES.R)
|
@RequiresApi(api = Build.VERSION_CODES.R)
|
||||||
@Override
|
@Override
|
||||||
public void onCreate() {
|
public void onCreate() {
|
||||||
|
@ -43,20 +95,250 @@ public class RecordingService extends Service {
|
||||||
Toast.makeText(this,"错误:"+e,Toast.LENGTH_LONG).show();
|
Toast.makeText(this,"错误:"+e,Toast.LENGTH_LONG).show();
|
||||||
stopSelf();
|
stopSelf();
|
||||||
}
|
}
|
||||||
|
handler = new Handler(Looper.getMainLooper());
|
||||||
|
db = Room.databaseBuilder(getApplicationContext(),
|
||||||
|
AppDatabase.class, "image-database").build();
|
||||||
|
db2 = Room.databaseBuilder(getApplicationContext(),
|
||||||
|
AppDatabase.class, "image-database2").build();
|
||||||
|
createNotificationChannel();
|
||||||
|
|
||||||
|
|
||||||
|
// 在 onCreate() 中改进 ViewModel 初始化
|
||||||
|
|
||||||
|
// 观察LiveData变化
|
||||||
|
// 在类成员变量中添加
|
||||||
|
|
||||||
|
dataManager=SharedDataManager.getInstance();
|
||||||
|
dataManager.addListener(this);
|
||||||
|
currentImagePath = dataManager.getImagePath();
|
||||||
|
currentToken = dataManager.getToken();
|
||||||
|
// 在onCreate()中改为使用成员变量观察
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onImagePathChanged(String newPath) {
|
||||||
|
currentImagePath = newPath;
|
||||||
|
Log.d("Service", "ImagePath updated: " + newPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onTokenChanged(String newToken) {
|
||||||
|
currentToken = newToken;
|
||||||
|
Log.d("Service", "Token updated: " + newToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onUserChanged(String newUser) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onAudioPathChanged(String newAudioPath) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onProjectIdChanged(String newProjectId) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onUnitChanged(String newUnit) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onBladeChanged(int newBlade) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onPartidChanged(String newPartid) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onChooseImageSourceChanged(String newChooseImageSource) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onUnitNameChanged(String newUnitName) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onIsRecordingChanged(boolean newisRecording) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onUploadingStatusChanged(boolean isUploading) {
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// 获取当前数据(可选,如果 Activity 需要读取)
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int onStartCommand(Intent intent, int flags, int startId) {
|
public int onStartCommand(Intent intent, int flags, int startId) {
|
||||||
|
|
||||||
return START_STICKY;
|
if (intent != null && "start_recording".equals(intent.getAction())) {
|
||||||
|
startRecording();
|
||||||
|
} else if (intent != null && "stop_recording".equals(intent.getAction())) {
|
||||||
|
stopRecording();
|
||||||
|
}
|
||||||
|
return START_REDELIVER_INTENT;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
private void startRecording() {
|
||||||
public IBinder onBind(Intent intent) {
|
try {
|
||||||
return null;
|
// 1. 设置录音文件路径
|
||||||
|
currentAudioPath = getExternalCacheDir().getAbsolutePath()
|
||||||
|
+ "/" + System.currentTimeMillis() + ".3gp";
|
||||||
|
dataManager.setAudioPath(currentAudioPath);
|
||||||
|
// 2. 初始化MediaRecorder
|
||||||
|
mediaRecorder = new MediaRecorder();
|
||||||
|
|
||||||
|
mediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
|
||||||
|
mediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
|
||||||
|
mediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
|
||||||
|
mediaRecorder.setOutputFile(currentAudioPath);
|
||||||
|
mediaRecorder.prepare();
|
||||||
|
mediaRecorder.start();
|
||||||
|
|
||||||
|
// 3. 启动前台服务
|
||||||
|
startForegroundService();
|
||||||
|
|
||||||
|
// 4. 开始计时更新通知
|
||||||
|
startUpdatingTimer();
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
Toast.makeText(this, "录音失败: " + e.getMessage(), Toast.LENGTH_SHORT).show();
|
||||||
|
stopSelf();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void startForegroundService() {
|
||||||
|
Notification notification = buildNotification("录音中... 00:00");
|
||||||
|
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
||||||
|
startForeground(NOTIFICATION_ID, notification,
|
||||||
|
ServiceInfo.FOREGROUND_SERVICE_TYPE_MICROPHONE);
|
||||||
|
} else {
|
||||||
|
startForeground(NOTIFICATION_ID, notification);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void startUpdatingTimer() {
|
||||||
|
updateTimerRunnable = new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
recordingSeconds++;
|
||||||
|
String time = String.format("%02d:%02d",
|
||||||
|
recordingSeconds / 60, recordingSeconds % 60);
|
||||||
|
updateNotification("录音中... " + time);
|
||||||
|
handler.postDelayed(this, 1000);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
handler.post(updateTimerRunnable);
|
||||||
|
}
|
||||||
|
private void uploadAudio(String imageId, String audioPath, String token) {
|
||||||
|
// 1. 参数校验(在调用线程执行,避免不必要的后台任务)
|
||||||
|
if (audioPath == null || audioPath.equals("0")) {
|
||||||
|
BackgroundToast.show(this, "文件路径为空");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
File audioFile = new File(audioPath);
|
||||||
|
if (!audioFile.exists()) {
|
||||||
|
BackgroundToast.show(this, "文件不存在");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. 在后台线程执行上传逻辑
|
||||||
|
executor.execute(() -> {
|
||||||
|
// 3. 构建请求体(已在后台线程)
|
||||||
|
RequestBody requestBody = new MultipartBody.Builder()
|
||||||
|
.setType(MultipartBody.FORM)
|
||||||
|
.addFormDataPart("file", audioFile.getName(),
|
||||||
|
RequestBody.create(audioFile, MediaType.parse("audio/*")))
|
||||||
|
.build();
|
||||||
|
|
||||||
|
// 4. 构建请求
|
||||||
|
Request.Builder requestBuilder = new Request.Builder()
|
||||||
|
.url("http://pms.dtyx.net:9158/audio/upload/" + imageId)
|
||||||
|
.post(requestBody);
|
||||||
|
|
||||||
|
if (token != null && !token.isEmpty()) {
|
||||||
|
requestBuilder.addHeader("Authorization", token);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 5. 同步执行请求(try-with-resources 自动关闭 Response)
|
||||||
|
try (Response response = httpClient.newCall(requestBuilder.build()).execute()) {
|
||||||
|
String currentTime = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.getDefault())
|
||||||
|
.format(new Date());
|
||||||
|
|
||||||
|
if (response.isSuccessful()) {
|
||||||
|
// 上传成功
|
||||||
|
db.AudioDao().delete(new AudioEntity(audioPath, imageId, currentTime));
|
||||||
|
db2.AudioDao().insert(new AudioEntity(audioPath, imageId, currentTime));
|
||||||
|
BackgroundToast.show(this, "录音上传成功: " + imageId);
|
||||||
|
stopSelf();
|
||||||
|
} else {
|
||||||
|
// 上传失败(HTTP 错误)
|
||||||
|
db.AudioDao().insert(new AudioEntity(audioPath, imageId, currentTime));
|
||||||
|
BackgroundToast.show(this,
|
||||||
|
"录音上传失败: " + response.code() + " " + response.message());
|
||||||
|
stopSelf();
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
// 网络异常
|
||||||
|
String currentTime = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.getDefault())
|
||||||
|
.format(new Date());
|
||||||
|
db.AudioDao().insert(new AudioEntity(audioPath, imageId, currentTime));
|
||||||
|
BackgroundToast.show(this, "录音上传失败: " + e.getMessage());
|
||||||
|
Log.e("录音上传失败:",e.toString());
|
||||||
|
stopSelf();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void stopRecording() {
|
||||||
|
try {
|
||||||
|
// 1. 停止录音
|
||||||
|
if (mediaRecorder != null) {
|
||||||
|
mediaRecorder.stop();
|
||||||
|
mediaRecorder.release();
|
||||||
|
mediaRecorder = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. 停止计时器
|
||||||
|
if (handler != null && updateTimerRunnable != null) {
|
||||||
|
handler.removeCallbacks(updateTimerRunnable);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. 更新通知
|
||||||
|
updateNotification("录音已保存");
|
||||||
|
|
||||||
|
// 4. 上传录音文件(如果有需要)
|
||||||
|
if (currentAudioPath != null) {
|
||||||
|
uploadAudio(currentImagePath, currentAudioPath, currentToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 5. 不立即停止服务,等待上传完成
|
||||||
|
// 可以通过其他机制(如广播或LiveData)在上传完成后通知服务停止
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
Toast.makeText(this, "停止录音失败: " + e.getMessage(), Toast.LENGTH_SHORT).show();
|
||||||
|
stopSelf();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
private void createNotificationChannel() {
|
private void createNotificationChannel() {
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||||
NotificationChannel channel = new NotificationChannel(
|
NotificationChannel channel = new NotificationChannel(
|
||||||
|
@ -70,7 +352,7 @@ public class RecordingService extends Service {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private Notification buildNotification(String text) {
|
public Notification buildNotification(String text) {
|
||||||
// 确保图标有效(R.drawable.ic_mic_on必须存在)
|
// 确保图标有效(R.drawable.ic_mic_on必须存在)
|
||||||
return new NotificationCompat.Builder(this, CHANNEL_ID)
|
return new NotificationCompat.Builder(this, CHANNEL_ID)
|
||||||
.setSmallIcon(R.drawable.ic_mic_on)
|
.setSmallIcon(R.drawable.ic_mic_on)
|
||||||
|
@ -92,4 +374,35 @@ public class RecordingService extends Service {
|
||||||
NotificationManagerCompat.from(this)
|
NotificationManagerCompat.from(this)
|
||||||
.notify(NOTIFICATION_ID, buildNotification(text));
|
.notify(NOTIFICATION_ID, buildNotification(text));
|
||||||
}
|
}
|
||||||
|
@Override
|
||||||
|
public void onDestroy() {
|
||||||
|
super.onDestroy();
|
||||||
|
|
||||||
|
|
||||||
|
// 2. 停止并释放MediaRecorder
|
||||||
|
if (mediaRecorder != null) {
|
||||||
|
try {
|
||||||
|
mediaRecorder.stop();
|
||||||
|
mediaRecorder.release();
|
||||||
|
} catch (IllegalStateException e) {
|
||||||
|
Log.e("Service", "MediaRecorder释放异常", e);
|
||||||
|
}
|
||||||
|
mediaRecorder = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. 移除Handler回调
|
||||||
|
if (handler != null && updateTimerRunnable != null) {
|
||||||
|
handler.removeCallbacks(updateTimerRunnable);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
dataManager.removeListener(this);
|
||||||
|
// 5. 关闭数据库(如果Room支持)
|
||||||
|
if (db != null) {
|
||||||
|
db.close();
|
||||||
|
}
|
||||||
|
if (db2 != null) {
|
||||||
|
db2.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -0,0 +1,200 @@
|
||||||
|
package com.example.myapplication.model;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
// SharedDataManager.java
|
||||||
|
public class SharedDataManager {
|
||||||
|
private static SharedDataManager instance;
|
||||||
|
private String imagePath ="-1";
|
||||||
|
private String token="-1";
|
||||||
|
private String user="-1";
|
||||||
|
private String audioPath="-1";
|
||||||
|
private String projectId="-1";
|
||||||
|
private String unit="-1";
|
||||||
|
private int blade=-1;
|
||||||
|
private String partid="-1";
|
||||||
|
private String chooseImageSource="-1";
|
||||||
|
private String unitName="-1";
|
||||||
|
private boolean isRecording=false;
|
||||||
|
private boolean isUploading=false; // 新增上传状态字段
|
||||||
|
|
||||||
|
private final List<DataChangeListener> listeners = new ArrayList<>();
|
||||||
|
|
||||||
|
public interface DataChangeListener {
|
||||||
|
void onImagePathChanged(String newPath);
|
||||||
|
void onTokenChanged(String newToken);
|
||||||
|
void onUserChanged(String newUser);
|
||||||
|
void onAudioPathChanged(String newAudioPath);
|
||||||
|
void onProjectIdChanged(String newProjectId);
|
||||||
|
void onUnitChanged(String newUnit);
|
||||||
|
void onBladeChanged(int newBlade);
|
||||||
|
void onPartidChanged(String newPartid);
|
||||||
|
void onChooseImageSourceChanged(String newChooseImageSource);
|
||||||
|
void onUnitNameChanged(String newUnitName);
|
||||||
|
void onIsRecordingChanged(boolean newisRecording);
|
||||||
|
void onUploadingStatusChanged(boolean isUploading); // 新增上传状态变化回调
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private SharedDataManager() {}
|
||||||
|
|
||||||
|
public static synchronized SharedDataManager getInstance() {
|
||||||
|
if (instance == null) {
|
||||||
|
instance = new SharedDataManager();
|
||||||
|
}
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
public boolean getIsRecording(){return isRecording;}
|
||||||
|
public String getImagePath() {return imagePath;}
|
||||||
|
public String getUser() { return user; }
|
||||||
|
public String getAudioPath() { return audioPath; }
|
||||||
|
public String getProjectId() { return projectId; }
|
||||||
|
public String getUnit() { return unit; }
|
||||||
|
public int getBlade() { return blade; }
|
||||||
|
public String getPartid() { return partid; }
|
||||||
|
public String getChooseImageSource() { return chooseImageSource; }
|
||||||
|
public String getUnitName() { return unitName; }
|
||||||
|
public String getToken() {return token;}
|
||||||
|
public boolean getisUploading() {
|
||||||
|
return isUploading;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUploading(boolean uploading) {
|
||||||
|
if (this.isUploading != uploading) {
|
||||||
|
this.isUploading = uploading;
|
||||||
|
notifyUploadingStatusChanged(uploading);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public void setImagePath(String imagePath) {
|
||||||
|
this.imagePath = imagePath;
|
||||||
|
notifyImagePathChanged(imagePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUser(String user) {
|
||||||
|
this.user = user;
|
||||||
|
notifyUserChanged(user);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAudioPath(String audioPath) {
|
||||||
|
this.audioPath = audioPath;
|
||||||
|
notifyAudioPathChanged(audioPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setProjectId(String projectId) {
|
||||||
|
this.projectId = projectId;
|
||||||
|
notifyProjectIdChanged(projectId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUnit(String unit) {
|
||||||
|
this.unit = unit;
|
||||||
|
notifyUnitChanged(unit);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setBlade(int blade) {
|
||||||
|
this.blade = blade;
|
||||||
|
notifyBladeChanged(blade);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPartid(String partid) {
|
||||||
|
this.partid = partid;
|
||||||
|
notifyPartidChanged(partid);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setChooseImageSource(String chooseImageSource) {
|
||||||
|
this.chooseImageSource = chooseImageSource;
|
||||||
|
notifyChooseImageSourceChanged(chooseImageSource);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUnitName(String unitName) {
|
||||||
|
this.unitName = unitName;
|
||||||
|
notifyUnitNameChanged(unitName);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void setToken(String token) {
|
||||||
|
this.token = token;
|
||||||
|
notifyTokenChanged(token);
|
||||||
|
}
|
||||||
|
public void setIsRecording(boolean isRecording) {
|
||||||
|
this.isRecording =isRecording ;
|
||||||
|
notifyIsRecordingChanged(isRecording);
|
||||||
|
}
|
||||||
|
public void addListener(DataChangeListener listener) {
|
||||||
|
listeners.add(listener);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void removeListener(DataChangeListener listener) {
|
||||||
|
listeners.remove(listener);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void notifyImagePathChanged(String newPath) {
|
||||||
|
for (DataChangeListener listener : listeners) {
|
||||||
|
listener.onImagePathChanged(newPath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void notifyTokenChanged(String newToken) {
|
||||||
|
for (DataChangeListener listener : listeners) {
|
||||||
|
listener.onTokenChanged(newToken);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private void notifyUserChanged(String newUser) {
|
||||||
|
for (DataChangeListener listener : listeners) {
|
||||||
|
listener.onUserChanged(newUser);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void notifyAudioPathChanged(String newAudioPath) {
|
||||||
|
for (DataChangeListener listener : listeners) {
|
||||||
|
listener.onAudioPathChanged(newAudioPath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void notifyProjectIdChanged(String newProjectId) {
|
||||||
|
for (DataChangeListener listener : listeners) {
|
||||||
|
listener.onProjectIdChanged(newProjectId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void notifyUnitChanged(String newUnit) {
|
||||||
|
for (DataChangeListener listener : listeners) {
|
||||||
|
listener.onUnitChanged(newUnit);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void notifyBladeChanged(int newBlade) {
|
||||||
|
for (DataChangeListener listener : listeners) {
|
||||||
|
listener.onBladeChanged(newBlade);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void notifyPartidChanged(String newPartid) {
|
||||||
|
for (DataChangeListener listener : listeners) {
|
||||||
|
listener.onPartidChanged(newPartid);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void notifyChooseImageSourceChanged(String newChooseImageSource) {
|
||||||
|
for (DataChangeListener listener : listeners) {
|
||||||
|
listener.onChooseImageSourceChanged(newChooseImageSource);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void notifyUnitNameChanged(String newUnitName) {
|
||||||
|
for (DataChangeListener listener : listeners) {
|
||||||
|
listener.onUnitNameChanged(newUnitName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private void notifyIsRecordingChanged(boolean newIsRecording) {
|
||||||
|
for (DataChangeListener listener : listeners) {
|
||||||
|
listener.onIsRecordingChanged(newIsRecording);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private void notifyUploadingStatusChanged(boolean isUploading) {
|
||||||
|
for (DataChangeListener listener : listeners) {
|
||||||
|
listener.onUploadingStatusChanged(isUploading);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue