android - 是否可以从 Java/Kotlin 中的 android WorkManager 类启动广播接收器
问题描述
我被一个问题困扰了一个多月了。我想从 Android WorkManager 类启动广播接收器。我想接收/过滤所有传入的短信,然后发布到服务器。但是,我当前的解决方案在 android 系统终止应用程序并且接收器同步停止之前的几个小时内无法工作,或者当我从 PDU 对象(来自电话 Intent)中提取文本消息时,onReceive 方法已经返回。因此,为了解决这个问题,我希望让广播 onReceive 方法在 WorkManager 中运行,以确保进程不会这么快终止。我尝试过阅读,但没有得到适合我的解决方案,或者我可能对广播接收器或 android 后台进程的工作方式不清楚。这是我目前的实现。
@TargetApi(Build.VERSION_CODES.M)
@Override
public void onReceive(final Context context, Intent intent) {
this.context= context;
if (Telephony.Sms.Intents.SMS_RECEIVED_ACTION.equals(intent.getAction())) {
final Bundle data = intent.getExtras();
if (data !=null ) {
try {
final Object[] pdusObj = (Object[]) data.get("pdus");
if (pdusObj != null) {
for (int i = 0; i < pdusObj.length; i++) {
SmsMessage currentMessage =
SmsMessage.createFromPdu((byte[]) pdusObj[i]);
Log.d(TAG, "run: currentMessage: " + currentMessage);
Log.d(TAG, "passReceivedMsg: handleMessage: message " + currentMessage);
int msgNo = counter++;
msgID = "SMS_ID_0" + msgNo;
sender = currentMessage.getDisplayOriginatingAddress();
text_message = currentMessage.getDisplayMessageBody();
long timestampMilliseconds = System.currentTimeMillis();
timestamp = formatter.format(timestampMilliseconds);
Data.Builder dataBuilder = new Data.Builder();
dataBuilder.putString("sender",sender);
dataBuilder.putString("message",text_message);
dataBuilder.putString("timestamp",timestamp);
dataBuilder.putString("sms_id",msgID);
// Log.d(TAG, "onReceive: key:" +key+ " and keyValue "+data.get(key));
WorkManager mWorkManager = WorkManager.getInstance();
OneTimeWorkRequest mRequest = new OneTimeWorkRequest
.Builder(MessageSyncWorker.class)
.setInputData(dataBuilder.build())
.build();
mWorkManager.enqueue(mRequest);
}
}
}
catch (Exception e){
Log.d(TAG, "onReceive: Exception occured "+e.getMessage());
}
}
}
}
下面是我的 MessageSyncWorker 类,它扩展了 Worker-doWork() 方法
@NonNull
@Override
public Result doWork() {
Data inputData1 = getInputData();
sender = inputData1.getString("sender");
text_message = inputData1.getString("message");
timestamp = inputData1.getString("timestamp");
msgID = inputData1.getString("sms_id");
Log.d(TAG, "doWork: Mesage "+text_message);
SharedPreferences sharedPreferences =
PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
BASE_API_URL = sharedPreferences.getString("settings_server_url", "");
Log.d(TAG, "doWork: BASE URL "+BASE_API_URL);
try {
//here I upload the data to the server
uploadMessageData();
} catch (JSONException e) {
e.printStackTrace();
Log.d(TAG, "doWork: uploadMessage method Exception "+e.getMessage());
}
return Result.success();
}
解决方案
最后,在评论区(针对这个问题)中可以看到详细讨论后,我已经破解了它。我现在有工作代码,我相信通过分享我可以帮助其他人遇到类似问题。下面是我是如何做到的。
这是 onReceive() 方法;
@Override
public void onReceive(Context context, Intent intent) {
if (Telephony.Sms.Intents.SMS_RECEIVED_ACTION
.equals(intent.getAction())){
this.context = context;
SmsMessage smsMessage = null;
StringBuilder fullMessage = new StringBuilder();
for (SmsMessage new_smsMessage : Telephony.Sms.Intents.getMessagesFromIntent(intent)){
smsMessage = new_smsMessage;
fullMessage.append(smsMessage.getDisplayMessageBody());
}
if (smsMessage ==null){
return;
}
String sender = smsMessage.getOriginatingAddress();
long timestampMilliseconds = System.currentTimeMillis();
String timestamp = formatter.format(timestampMilliseconds);
Log.d("NeTxt Receiver ", "onReceive: fullMessage: "+fullMessage);
Data.Builder dataBuilder = new Data.Builder();
dataBuilder.putString("fullMessage",fullMessage.toString());
dataBuilder.putString("sender", sender);
dataBuilder.putString("timestamp",timestamp);
//defining constraints
Constraints task_constraints = new Constraints.Builder()
.setRequiredNetworkType(NetworkType.CONNECTED)
.build();
//scheduling the work
WorkManager mWorkManager = WorkManager.getInstance();
OneTimeWorkRequest mRequest = new OneTimeWorkRequest
.Builder(NewTxtWorker.class)
.setInputData(dataBuilder.build())
.setConstraints(task_constraints)
.build();
mWorkManager.enqueue(mRequest);
mWorkManager.getWorkInfoById(mRequest.getId());
}
}
下面是我的 doWork() 方法;
@NonNull
@Override
public Result doWork() {
Data inputData = getInputData();
String sender = inputData.getString("sender");
String text_message = inputData.getString("fullMessage");
String timestamp = inputData.getString("timestamp");
Log.d("Txt WorkManager", "doWork: fullmessage: "+text_message);
assert sender != null;
assert text_message != null;
if (!timestamp.isEmpty()||
!sender.isEmpty()||
!text_message.isEmpty()){
FirebaseFirestore fireDb = FirebaseFirestore.getInstance();
Map<String, Object> message = new HashMap<>();
message.put("text_message", text_message);
message.put("sender", sender);
message.put("timestamp", timestamp);
//sync the received message with the firebase firestore db
fireDb.collection("text_messages")
.add(message)
.addOnSuccessListener(new OnSuccessListener<DocumentReference>() {
@Override
public void onSuccess(DocumentReference documentReference) {
Log.d("Txt WorkManager", "onSuccess: doc Id"
+documentReference.getId());
}
})
.addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(@NonNull Exception e) {
Log.d("Txt WorkManager", "onFailure: "+e.getMessage());
}
}) ;
}
return Result.failure();
}
推荐阅读
- javascript - 在单元测试期间抑制控制台日志中的反应错误
- docker - 如何从 Docker-Composed C# 应用程序连接到本地 SQL Server Express 数据库?
- javascript - Nextjs 路由 - 捕获除公用文件夹之外的所有内容
- javascript - 单击按钮子元素时错误的 event.target
- rest - Cosmos DB REST API 授权标头不允许我替换文档
- postgresql - cloudsqladmin 保持 CloudSQL 实例始终开启?
- bootstrap-4 - 如何正确对齐一项并使用 Bootstrap 4 保持一项居中?
- amazon-web-services - 如何在 aws EKS 中管理 pod 调度?
- spartacus-storefront - Spartacus v3:从 v2 迁移后,无法从“付款详细信息”导航到“审核订单”
- reactjs - ag-grid vs Kendo React 网格的优缺点