完善AI聊天助手功能 #39

Merged
pvexk5qol merged 3 commits from caoweiqiong_branch into master 4 weeks ago

@ -0,0 +1,5 @@
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="#FFFFFF" />
<corners android:topLeftRadius="2dp" android:topRightRadius="12dp"
android:bottomRightRadius="12dp" android:bottomLeftRadius="12dp" />
</shape>

@ -0,0 +1,5 @@
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="#E3F2FD" /> <!-- 浅蓝色背景 -->
<stroke android:width="1dp" android:color="#2196F3" /> <!-- 深蓝边框 -->
<corners android:radius="12dp" />
</shape>

@ -0,0 +1,5 @@
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="#FFD700" /> <!-- 使用小米金色 -->
<corners android:topLeftRadius="12dp" android:topRightRadius="2dp"
android:bottomRightRadius="12dp" android:bottomLeftRadius="12dp" />
</shape>

@ -25,9 +25,17 @@
android:id="@+id/menu_export_text"
android:title="@string/menu_export_text"/>
<!-- [修改] 原 menu_sync 改为 menu_pull -->
<item
android:id="@+id/menu_sync"
android:title="@string/menu_sync"/>
android:id="@+id/menu_pull"
android:title="@string/menu_pull"
android:icon="@android:drawable/ic_popup_sync" />
<!-- [新增] 新增 menu_push -->
<item
android:id="@+id/menu_push"
android:title="@string/menu_push"
android:icon="@android:drawable/ic_menu_upload" />
<item
android:id="@+id/menu_setting"

@ -93,6 +93,9 @@
<string name="char_count_format">%1$d 字</string>
<string name="menu_push">Push</string>
<string name="menu_pull">Pull</string>
<string name="preferences_floating_window_title">全局悬浮球</string>
<string name="preferences_floating_window_summary">开启后可在屏幕边缘显示快捷图标,点击立即记录灵感</string>
<string name="toast_need_overlay_permission">开启悬浮球需要“显示在其他应用上”的权限,请手动授予</string>

@ -268,8 +268,6 @@ public class Notes {
* 1: (Reminder Card)
*/
public static final String MSG_TYPE = "msg_type";
public static final int MSG_TYPE_TEXT = 0; // 普通对话
public static final int MSG_TYPE_REMINDER = 1; // [核心] 提醒卡片UI显示金色气泡
public static final String CONTENT = "content";
public static final String CREATED_AT = "created_at";

@ -50,7 +50,6 @@ public class NotesProvider extends ContentProvider {
private static final int URI_SEARCH = 5;
private static final int URI_SEARCH_SUGGEST = 6;
private static final int URI_USER_ACCOUNT = 7; // 新增编号
private static final int URI_CHAT_MESSAGES = 8;
static {
mMatcher = new UriMatcher(UriMatcher.NO_MATCH);
@ -62,8 +61,6 @@ public class NotesProvider extends ContentProvider {
mMatcher.addURI(Notes.AUTHORITY, SearchManager.SUGGEST_URI_PATH_QUERY, URI_SEARCH_SUGGEST);
mMatcher.addURI(Notes.AUTHORITY, SearchManager.SUGGEST_URI_PATH_QUERY + "/*", URI_SEARCH_SUGGEST);
mMatcher.addURI(Notes.AUTHORITY, "user_account", URI_USER_ACCOUNT);
// [核心新增]:让系统认识 content://micode_notes/chat_messages
mMatcher.addURI(Notes.AUTHORITY, "chat_messages", URI_CHAT_MESSAGES);
}
/**
@ -143,9 +140,6 @@ public class NotesProvider extends ContentProvider {
Log.e(TAG, "got exception: " + ex.toString());
}
break;
case URI_CHAT_MESSAGES:
c = db.query(NotesDatabaseHelper.TABLE.CHAT_MESSAGES, projection, selection, selectionArgs, null, null, sortOrder);
break;
default:
throw new IllegalArgumentException("Unknown URI " + uri);
}
@ -174,12 +168,6 @@ public class NotesProvider extends ContentProvider {
case URI_USER_ACCOUNT:
insertedId = db.insert(TABLE.USER_ACCOUNT, null, values);
break;
// [核心新增]:处理聊天消息的真正入库逻辑
case URI_CHAT_MESSAGES:
insertedId = db.insert(NotesDatabaseHelper.TABLE.CHAT_MESSAGES, null, values);
// 插入成功后发送数据变更通知,让 ChatFragment 能够自动刷新
getContext().getContentResolver().notifyChange(uri, null);
break;
default:
throw new IllegalArgumentException("Unknown URI " + uri);
}

@ -15,17 +15,11 @@ import androidx.work.WorkerParameters;
import com.google.firebase.auth.FirebaseAuth;
import com.google.firebase.firestore.FirebaseFirestore;
import com.google.firebase.firestore.QueryDocumentSnapshot;
import com.google.gson.JsonObject;
import net.micode.notes.data.Notes;
import net.micode.notes.data.Notes.NoteColumns;
import net.micode.notes.model.CloudNote;
import net.micode.notes.tool.AiNotificationHelper;
import net.micode.notes.tool.SyncMapper;
import net.micode.notes.tool.ai.AiDataSyncHelper;
import net.micode.notes.tool.ai.CozeClient;
import net.micode.notes.tool.ai.CozeRequest;
import net.micode.notes.tool.ai.CozeResponse;
import java.util.UUID;
import java.util.concurrent.CountDownLatch;
@ -37,7 +31,6 @@ public class SyncWorker extends Worker {
public static final int MODE_ALL = 0; // 默认:全量同步
public static final int MODE_PUSH = 1; // 仅上传
public static final int MODE_PULL = 2; // 仅拉取
public static final int MODE_REMINDER = 3;
public SyncWorker(@NonNull Context context, @NonNull WorkerParameters workerParams) {
super(context, workerParams);
@ -63,7 +56,6 @@ public class SyncWorker extends Worker {
// --- PUSH 逻辑 (保持同步执行即可因为它本身不依赖回调返回数据给UI) ---
if (mode == MODE_PUSH || mode == MODE_ALL) {
performPush(db, uid);
syncToCozeAgent();
}
// --- PULL 逻辑 (异步变同步) ---
@ -80,12 +72,6 @@ public class SyncWorker extends Worker {
}
}
// 2. 在 doWork() 中增加判断
if (mode == MODE_REMINDER) {
String title = getInputData().getString("reminder_title");
requestAiReminderReply(title);
}
return isSuccess[0] ? Result.success() : Result.failure();
} catch (Exception e) {
@ -94,161 +80,6 @@ public class SyncWorker extends Worker {
}
}
// 3. 实现提醒请求逻辑
private void requestAiReminderReply(String agendaTitle) {
try {
// 1. 构造请求参数
com.google.gson.JsonObject json = new com.google.gson.JsonObject();
json.addProperty("intent", "reminder");
json.addProperty("payload", "日程即将开始:" + agendaTitle);
json.addProperty("current_time", AiDataSyncHelper.getCurrentTime());
// 2. 发起对话
CozeRequest request = new CozeRequest(CozeClient.BOT_ID, "user_demo", json.toString());
retrofit2.Response<CozeResponse> response = CozeClient.getInstance()
.chat(CozeClient.getAuthToken(), request).execute();
// 声明变量,用于存放最终结果
String finalAnswer = null;
if (response.isSuccessful() && response.body() != null && response.body().data != null) {
String chatId = response.body().data.id;
String convId = response.body().data.conversation_id;
// 3. 轮询状态直到完成
String status = "";
int retries = 0;
while (!"completed".equals(status) && retries < 15) {
Thread.sleep(2000);
retrofit2.Response<CozeResponse> pollResp = CozeClient.getInstance()
.retrieveChat(CozeClient.getAuthToken(), chatId, convId).execute();
if (pollResp.isSuccessful() && pollResp.body() != null && pollResp.body().data != null) {
status = pollResp.body().data.status;
}
retries++;
}
// 4. [核心修复点]:状态完成后,请求消息列表并解析出 content
if ("completed".equals(status)) {
retrofit2.Response<com.google.gson.JsonObject> msgListResp = CozeClient.getInstance()
.getMessageList(CozeClient.getAuthToken(), chatId, convId).execute();
if (msgListResp.isSuccessful() && msgListResp.body() != null) {
com.google.gson.JsonArray messages = msgListResp.body().getAsJsonArray("data");
// 遍历寻找 AI 的回答内容
for (com.google.gson.JsonElement el : messages) {
com.google.gson.JsonObject m = el.getAsJsonObject();
if ("assistant".equals(m.get("role").getAsString()) &&
"answer".equals(m.get("type").getAsString())) {
finalAnswer = m.get("content").getAsString();
break;
}
}
}
}
}
// 5. 统一处理最终结果
if (finalAnswer != null && !finalAnswer.isEmpty()) {
saveReminderToLocal(finalAnswer);
AiNotificationHelper.sendAiNotification(getApplicationContext(), finalAnswer);
Log.d("AiReminder", "Successfully got AI reminder: " + finalAnswer);
} else {
Log.w("AiReminder", "AI returned empty answer for reminder.");
}
} catch (Exception e) {
Log.e("AiReminder", "Error in requestAiReminderReply", e);
}
}
private void saveReminderToLocal(String content) {
android.content.ContentValues values = new android.content.ContentValues();
values.put(Notes.ChatColumns.SENDER_TYPE, 1); // AI
values.put(Notes.ChatColumns.MSG_TYPE, 1); // [重要] 设为提醒卡片类型
values.put(Notes.ChatColumns.CONTENT, content);
values.put(Notes.ChatColumns.CREATED_AT, System.currentTimeMillis());
getApplicationContext().getContentResolver().insert(
android.net.Uri.parse("content://micode_notes/chat_messages"), values);
}
// 在 SyncWorker 类中添加
private void syncToCozeAgent() {
try {
com.google.gson.JsonObject payloadJson = new com.google.gson.JsonObject();
payloadJson.addProperty("intent", "sync");
payloadJson.addProperty("payload", AiDataSyncHelper.getSyncPayload(getApplicationContext()));
payloadJson.addProperty("current_time", AiDataSyncHelper.getCurrentTime());
CozeRequest request = new CozeRequest(CozeClient.BOT_ID, "user_demo", payloadJson.toString());
// 1. 发起对话
retrofit2.Response<CozeResponse> response = CozeClient.getInstance()
.chat(CozeClient.getAuthToken(), request).execute();
if (response.isSuccessful() && response.body() != null && response.body().data != null) {
String chatId = response.body().data.id;
String convId = response.body().data.conversation_id; // [关键] 获取会话ID
String status = "";
int retries = 0;
while (!"completed".equals(status) && retries < 15) {
Thread.sleep(2000);
// [关键] 传入两个 ID 轮询
retrofit2.Response<CozeResponse> pollResp = CozeClient.getInstance()
.retrieveChat(CozeClient.getAuthToken(), chatId, convId).execute();
if (pollResp.isSuccessful() && pollResp.body() != null && pollResp.body().data != null) {
status = pollResp.body().data.status;
}
retries++;
}
// 2. 完成后抓取真正的“Answer”
if ("completed".equals(status)) {
retrofit2.Response<com.google.gson.JsonObject> msgListResp = CozeClient.getInstance()
.getMessageList(CozeClient.getAuthToken(), chatId, convId).execute();
if (msgListResp.isSuccessful() && msgListResp.body() != null) {
com.google.gson.JsonArray messages = msgListResp.body().getAsJsonArray("data");
String finalAnswer = null;
// 遍历寻找 role=assistant 且 type=answer 的内容
for (com.google.gson.JsonElement el : messages) {
com.google.gson.JsonObject m = el.getAsJsonObject();
if ("assistant".equals(m.get("role").getAsString()) &&
"answer".equals(m.get("type").getAsString())) {
finalAnswer = m.get("content").getAsString();
break;
}
}
if (finalAnswer != null && !finalAnswer.isEmpty()) {
// 插入本地数据库并弹通知
saveChatMessageToLocal(finalAnswer);
AiNotificationHelper.sendAiNotification(getApplicationContext(), finalAnswer);
}
}
}
}
} catch (Exception e) {
Log.e("CozeSync", "Sync Failed", e);
}
}
// 辅助方法:将 AI 消息存入本地 chat_messages 表
private void saveChatMessageToLocal(String content) {
android.content.ContentValues values = new android.content.ContentValues();
values.put(net.micode.notes.data.Notes.ChatColumns.SENDER_TYPE, 1); // AI
values.put(net.micode.notes.data.Notes.ChatColumns.MSG_TYPE, 0); // 文本
values.put(net.micode.notes.data.Notes.ChatColumns.CONTENT, content);
values.put(net.micode.notes.data.Notes.ChatColumns.CREATED_AT, System.currentTimeMillis());
getApplicationContext().getContentResolver().insert(
android.net.Uri.parse("content://micode_notes/chat_messages"), values);
}
/**
* [] sync_state = 1
*/

@ -1,31 +1,18 @@
package net.micode.notes.tool.ai;
import com.google.gson.JsonObject;
import retrofit2.Call;
import retrofit2.http.Body;
import retrofit2.http.GET;
import retrofit2.http.Header;
import retrofit2.http.POST;
import retrofit2.http.Query;
public interface CozeApiService {
/**
*
* https://www.coze.cn/open/docs/developer_guides/chat
*/
@POST("v3/chat")
Call<CozeResponse> chat(@Header("Authorization") String token, @Body CozeRequest request);
// [核心修复] 轮询接口:使用 Query 参数传递 IDs
@POST("v3/chat/retrieve")
Call<CozeResponse> retrieveChat(
@Header("Authorization") String token,
@Query("chat_id") String chatId,
@Query("conversation_id") String conversationId
);
// [核心新增] 获取消息列表:用于抓取 AI 的文本回复
@GET("v3/chat/message/list")
Call<com.google.gson.JsonObject> getMessageList(
Call<CozeResponse> chat(
@Header("Authorization") String token,
@Query("chat_id") String chatId,
@Query("conversation_id") String conversationId
@Body CozeRequest request
);
}

@ -14,8 +14,13 @@ public class CozeResponse {
public ChatData data;
public static class ChatData {
public String id; // chat_id
public String conversation_id; // [核心修复] 必须添加此字段
public String status;
@SerializedName("id")
public String id; // 会话ID
@SerializedName("status")
public String status; // 状态completed, in_progress等
// 注意:非流式模式下,回复通常在后续的消息查询中或特定的 V3 响应字段中
// 为了简化 Demo我们假设智能体立即返回了结果
}
}

@ -20,7 +20,6 @@ import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import net.micode.notes.R;
import net.micode.notes.data.Notes;
import net.micode.notes.tool.ai.AiReminderScheduler;
import net.micode.notes.data.Notes.NoteColumns;
import java.util.ArrayList;
import java.util.Calendar;
@ -152,14 +151,6 @@ public class AgendaFragment extends Fragment {
cv.put(NoteColumns.LOCAL_MODIFIED, 1);
getContext().getContentResolver().insert(Notes.CONTENT_NOTE_URI, cv);
// [新增] 核心补丁:让 AI 助理感知到新日程
try {
AiReminderScheduler.updateAllReminders(getContext());
android.util.Log.d("AiReminder", "Scheduled from Agenda Quick Add");
} catch (Exception e) {
e.printStackTrace();
}
// 重置 UI
et.setText("");
tvQuickTime.setText("全天");

@ -20,9 +20,6 @@ public class ChatFragment extends Fragment {
private List<ChatMessage> mMessages = new ArrayList<>();
private EditText mInput;
private android.database.ContentObserver mChatObserver;
private static final android.net.Uri CHAT_URI = android.net.Uri.parse("content://micode_notes/chat_messages");
@Override
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_chat, container, false);
@ -34,172 +31,19 @@ public class ChatFragment extends Fragment {
mRecyclerView.setAdapter(mAdapter);
view.findViewById(R.id.btn_chat_send).setOnClickListener(v -> {
final String text = mInput.getText().toString().trim();
if (text.isEmpty()) return;
// --- 第一部分:将用户消息存入数据库 ---
// 之前我们是手动 mMessages.add(...),现在不用了!
// 因为 ContentObserver 监听到数据库插入后,会自动调用 loadHistory 刷新列表。
new Thread(() -> {
android.content.ContentValues userValues = new android.content.ContentValues();
userValues.put(net.micode.notes.data.Notes.ChatColumns.SENDER_TYPE, 0); // 0 代表用户
userValues.put(net.micode.notes.data.Notes.ChatColumns.MSG_TYPE, 0); // 普通文本
userValues.put(net.micode.notes.data.Notes.ChatColumns.CONTENT, text);
userValues.put(net.micode.notes.data.Notes.ChatColumns.CREATED_AT, System.currentTimeMillis());
// 执行插入
getContext().getContentResolver().insert(CHAT_URI, userValues);
}).start();
// 清空输入框
mInput.setText("");
// --- 第二部分:向 AI 发起请求 (逻辑保持之前的异步方式) ---
new Thread(() -> {
try {
// 1. 组装请求 (intent=chat)
com.google.gson.JsonObject json = new com.google.gson.JsonObject();
json.addProperty("intent", "chat");
json.addProperty("payload", text);
json.addProperty("current_time", net.micode.notes.tool.ai.AiDataSyncHelper.getCurrentTime());
net.micode.notes.tool.ai.CozeRequest request = new net.micode.notes.tool.ai.CozeRequest(
net.micode.notes.tool.ai.CozeClient.BOT_ID, "user_demo", json.toString());
// 2. 发起 API 请求并轮询完成状态
retrofit2.Response<net.micode.notes.tool.ai.CozeResponse> response =
net.micode.notes.tool.ai.CozeClient.getInstance().chat(
net.micode.notes.tool.ai.CozeClient.getAuthToken(), request).execute();
if (response.isSuccessful() && response.body() != null && response.body().data != null) {
String chatId = response.body().data.id;
String convId = response.body().data.conversation_id;
android.util.Log.d("MiChat", "开始轮询 AI 响应, ChatID: " + chatId);
String status = "";
int retries = 0;
while (!"completed".equals(status) && retries < 30) { // 最多等 60 秒
Thread.sleep(2000);
retrofit2.Response<net.micode.notes.tool.ai.CozeResponse> poll =
net.micode.notes.tool.ai.CozeClient.getInstance().retrieveChat(
net.micode.notes.tool.ai.CozeClient.getAuthToken(), chatId, convId).execute();
if (poll.isSuccessful() && poll.body() != null && poll.body().data != null) {
status = poll.body().data.status;
android.util.Log.d("MiChat", "当前状态: " + status);
if ("failed".equals(status)) break;
}
retries++;
}
if ("completed".equals(status)) {
android.util.Log.d("MiChat", "轮询完成,准备抓取回复内容...");
retrofit2.Response<com.google.gson.JsonObject> msgList =
net.micode.notes.tool.ai.CozeClient.getInstance().getMessageList(
net.micode.notes.tool.ai.CozeClient.getAuthToken(), chatId, convId).execute();
if (msgList.isSuccessful() && msgList.body() != null) {
com.google.gson.JsonArray dataArray = msgList.body().getAsJsonArray("data");
boolean foundAnswer = false;
for (com.google.gson.JsonElement el : dataArray) {
com.google.gson.JsonObject m = el.getAsJsonObject();
// 【核心检查点】打印出 AI 返回的所有消息类型,看看为什么没匹配到
android.util.Log.d("MiChat", "收到消息: role=" + m.get("role").getAsString() +
", type=" + m.get("type").getAsString());
// 寻找 AI 发送的真正的回答内容
if ("assistant".equals(m.get("role").getAsString()) &&
"answer".equals(m.get("type").getAsString())) {
String answer = m.get("content").getAsString();
foundAnswer = true;
// 存入数据库,触发 ContentObserver 刷新 UI
android.content.ContentValues aiValues = new android.content.ContentValues();
aiValues.put(net.micode.notes.data.Notes.ChatColumns.SENDER_TYPE, 1);
aiValues.put(net.micode.notes.data.Notes.ChatColumns.MSG_TYPE, 0);
aiValues.put(net.micode.notes.data.Notes.ChatColumns.CONTENT, answer);
aiValues.put(net.micode.notes.data.Notes.ChatColumns.CREATED_AT, System.currentTimeMillis());
getContext().getContentResolver().insert(CHAT_URI, aiValues);
android.util.Log.d("MiChat", "AI 回复已入库: " + answer);
break;
}
}
if (!foundAnswer) {
android.util.Log.w("MiChat", "未在消息列表中找到 type 为 answer 的回复!");
}
}
} else {
android.util.Log.e("MiChat", "轮询超时或失败,最终状态: " + status);
}
}
} catch (Exception e) {
e.printStackTrace();
}
}).start();
});
// 1. 初次加载历史记录
loadHistory();
// 2. 注册观察者:监听数据库变化
mChatObserver = new android.database.ContentObserver(new android.os.Handler()) {
@Override
public void onChange(boolean selfChange) {
super.onChange(selfChange);
android.util.Log.d("ChatFragment", "Database changed, reloading...");
loadHistory(); // 数据库一变就重新加载
String text = mInput.getText().toString().trim();
if (!text.isEmpty()) {
// 1. 本地插入用户消息
ChatMessage userMsg = new ChatMessage(0, 0, text);
mMessages.add(userMsg);
mAdapter.notifyItemInserted(mMessages.size() - 1);
mRecyclerView.smoothScrollToPosition(mMessages.size() - 1);
mInput.setText("");
// TODO: Step 3 将在此处调用 CozeClient
}
};
getContext().getContentResolver().registerContentObserver(CHAT_URI, true, mChatObserver);
});
return view;
}
@Override
public void onDestroyView() {
super.onDestroyView();
if (mChatObserver != null) {
getContext().getContentResolver().unregisterContentObserver(mChatObserver);
}
}
private void loadHistory() {
new Thread(() -> {
android.database.Cursor cursor = getContext().getContentResolver().query(
CHAT_URI,
null, null, null, "created_at ASC" // 按时间顺序排列
);
List<ChatMessage> history = new ArrayList<>();
if (cursor != null) {
while (cursor.moveToNext()) {
// 根据 Step 1 定义的列顺序取值
int senderType = cursor.getInt(cursor.getColumnIndex(net.micode.notes.data.Notes.ChatColumns.SENDER_TYPE));
int msgType = cursor.getInt(cursor.getColumnIndex(net.micode.notes.data.Notes.ChatColumns.MSG_TYPE));
String content = cursor.getString(cursor.getColumnIndex(net.micode.notes.data.Notes.ChatColumns.CONTENT));
long time = cursor.getLong(cursor.getColumnIndex(net.micode.notes.data.Notes.ChatColumns.CREATED_AT));
ChatMessage msg = new ChatMessage(senderType, msgType, content);
msg.createdAt = time;
history.add(msg);
}
cursor.close();
}
// 回到主线程更新 UI
if (getActivity() != null) {
getActivity().runOnUiThread(() -> {
mMessages.clear();
mMessages.addAll(history);
mAdapter.notifyDataSetChanged();
if (mMessages.size() > 0) {
mRecyclerView.scrollToPosition(mMessages.size() - 1);
}
});
}
}).start();
}
}

@ -78,7 +78,6 @@ import net.micode.notes.tool.ResourceParser;
import net.micode.notes.tool.ResourceParser.TextAppearanceResources;
import net.micode.notes.ui.DateTimePickerDialog.OnDateTimeSetListener;
import net.micode.notes.ui.NoteEditText.OnTextViewChangeListener;
import net.micode.notes.tool.ai.AiReminderScheduler;
import net.micode.notes.widget.NoteWidgetProvider_2x;
import net.micode.notes.widget.NoteWidgetProvider_4x;
@ -1613,15 +1612,6 @@ public class NoteEditActivity extends AppCompatActivity implements OnClickListen
saveImages();
setResult(RESULT_OK);
// [新增] 刷新 AI 助理的闹钟计划
try {
// 每次保存成功,都让调度器重新扫描一遍所有日程,更新系统闹钟
AiReminderScheduler.updateAllReminders(this);
android.util.Log.d("AiAssistant", "Reminders scheduled successfully after save.");
} catch (Exception e) {
android.util.Log.e("AiAssistant", "Failed to schedule reminders", e);
}
}
return saved;
}

@ -1442,21 +1442,19 @@ public class NotesListActivity extends AppCompatActivity implements OnClickListe
}
});
break;
// [新增] 处理 Push
case R.id.menu_push:
// 手术点:更新提示语
Toast.makeText(this, "正在备份数据并同步 AI 大脑...", Toast.LENGTH_SHORT).show();
Toast.makeText(this, "正在上传数据到云端...", Toast.LENGTH_SHORT).show();
// [修复] 去掉前面的 androidx.work.Data直接赋值
// 构造参数MODE_PUSH
inputData = new androidx.work.Data.Builder()
.putInt(net.micode.notes.sync.SyncWorker.KEY_SYNC_MODE, net.micode.notes.sync.SyncWorker.MODE_PUSH)
.build();
// [修复] 去掉前面的 androidx.work.OneTimeWorkRequest直接赋值
syncRequest = new androidx.work.OneTimeWorkRequest.Builder(net.micode.notes.sync.SyncWorker.class)
.setInputData(inputData)
.build();
// 提交任务
androidx.work.WorkManager.getInstance(this).enqueue(syncRequest);
break;
case R.id.menu_setting: {

Loading…
Cancel
Save