WedX - журнал о программировании и компьютерных науках

Можно ли запустить приемник brodacast из класса Android WorkManager в Java / Kotlin

Я зацикливаюсь на одном вопросе уже больше месяца. Я хочу запустить широковещательный приемник из класса Android WorkManager. Я хочу получать / фильтровать все входящие текстовые сообщения, а затем отправлять их на сервер. Однако мое текущее решение не может работать в течение многих часов, пока система Android не убьет приложение и синхронизация приемника не остановится, или к тому времени, когда я извлечу текстовое сообщение из объекта PDU (исходящего из телефонного намерения), метод onReceive уже был возвращен. Поэтому, чтобы решить эту проблему, я хочу, чтобы метод onReceive продолжал работать внутри WorkManager, чтобы гарантировать, что процесс не завершится так быстро. Я пробовал читать, но я не получаю того решения, которое хорошо работает со мной, или, может быть, мне что-то непонятно о широковещательном приемнике или о том, как работают фоновые процессы Android. Это моя текущая реализация. Ниже приведен метод onReceive (), реализованный в MessageReceiver, который расширяет BroadcastReceiver.

    @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, расширяющий метод WorkerdoWork ().

@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() работать дольше или опять же поможет? Зарегистрированные в манифесте экземпляры Receiver - это очень временные вещи, и они должны быть такими. Когда приходит сообщение, создается новый экземпляр вашего Receiver, и широковещательная рассылка передается в его onReceive(), который должен завершиться как можно быстрее. Когда это будет сделано, экземпляр Receiver тоже будет готов и скоро исчезнет. Работа с очередями с WorkManager выполняется практически мгновенно, поэтому нет причин для активности вашего Receiver или его onReceive() метода дольше этого времени. 30.05.2020
  • Я не уверен в точном поведении, которое вы наблюдаете, но я хотел бы отметить, что вы, похоже, не совсем правильно обрабатываете входящие сообщения, предполагая, что MessageSyncWorker предназначен для запуска только один раз для каждого сообщения. Вашему получателю всегда будет передаваться только одно сообщение за раз, хотя оно может состоять из нескольких частей. Каждый элемент в массиве pdusObj - это не отдельное сообщение, а одна часть составного сообщения. Перед постановкой WorkManager задания в очередь необходимо объединить тела сообщений, чтобы получить полное единое сообщение. Возможно, с этим связано нежелательное поведение. 30.05.2020
  • onReceive () уже находится в собственном классе, который расширяет широковещательный приемник. Однако метод возвращается даже до вызова класса диспетчера работы, поскольку я выполняю операции для получения сообщения от PDU, которое, похоже, задерживается. Вот где моя проблема. В текущей реализации я заметил, что в какой-то момент входящее сообщение не синхронизируется с сервером. Проведя небольшое исследование, я заметил, что onReceive () возвращается так быстро, прежде чем я получу элементы сообщения из объекта PDU. Вот где я застрял. 30.05.2020
  • Вот почему я упоминаю то, что делаю, во втором комментарии: я думаю, вы можете неверно истолковать наблюдаемое поведение. Вы должны ожидать, что onReceive() будет сделано хорошо до того, как начнется MessageSyncWorker. Вызов enqueue() просто ставит задание в очередь, которое должно произойти позже. Ваш код не останавливается и не ждет, пока это произойдет. И, как я уже упоминал выше, длинные сообщения будут составными. В настоящее время вы ставите в очередь задание для каждой отдельной части, поэтому, если вы отлаживаете в MessageSyncWorker, это может выглядеть так, как будто оно не завершено, потому что это только часть сообщения. 30.05.2020
  • Теперь я понял. Теперь я понимаю, что вы имели в виду во втором комментарии. позвольте мне попробовать. 30.05.2020
  • Что ж, чтобы исправить многостраничную вещь, вам просто нужно перестроить свой код, чтобы только объединять тела сообщений частей в for цикле, а затем настроить и enqueue() задание после цикла; что-то вроде drive.google.com/file/. (Я не тестировал это; просто переместил его, чтобы дать вам идею.) Я не уверен, что он полностью объясняет поведение, которое вы наблюдаете, но это первое, что я сделал бы. 30.05.2020
  • Теперь ваш аргумент имеет больше смысла. Я инициировал очень длинное сообщение с моей текущей реализацией. Я заметил, что тело сообщения состоит из двух частей, и одна часть потеряна, хорошо синхронизировалась с сервером, но после использования StringBuilder для объединения, как вы рекомендовали, я получил текст как одну часть. 30.05.2020

Ответы:


1

Наконец, я взломал его после подробного обсуждения, что можно увидеть в области комментариев (для этого вопроса). Теперь у меня есть рабочий код, и я верю, что, поделившись им, я смогу помочь кому-то еще, кто застрял в подобном. Ниже я расскажу, как я это сделал.
вот метод 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();
}
01.06.2020
Новые материалы

Объяснение документов 02: BERT
BERT представил двухступенчатую структуру обучения: предварительное обучение и тонкая настройка. Во время предварительного обучения модель обучается на неразмеченных данных с помощью..

Как проанализировать работу вашего классификатора?
Не всегда просто знать, какие показатели использовать С развитием глубокого обучения все больше и больше людей учатся обучать свой первый классификатор. Но как только вы закончите..

Работа с цепями Маркова, часть 4 (Машинное обучение)
Нелинейные цепи Маркова с агрегатором и их приложения (arXiv) Автор : Бар Лайт Аннотация: Изучаются свойства подкласса случайных процессов, называемых дискретными нелинейными цепями Маркова..

Crazy Laravel Livewire упростил мне создание электронной коммерции (панель администратора и API) [Часть 3]
Как вы сегодня, ребята? В этой части мы создадим CRUD для данных о продукте. Думаю, в этой части я не буду слишком много делиться теорией, но чаще буду делиться своим кодом. Потому что..

Использование машинного обучения и Python для классификации 1000 сезонов новичков MLB Hitter
Чему может научиться машина, глядя на сезоны новичков 1000 игроков MLB? Это то, что исследует это приложение. В этом процессе мы будем использовать неконтролируемое обучение, чтобы..

Учебные заметки: создание моего первого пакета Node.js
Это мои обучающие заметки, когда я научился создавать свой самый первый пакет Node.js, распространяемый через npm. Оглавление Глоссарий I. Новый пакет 1.1 советы по инициализации..

Забудьте о Matplotlib: улучшите визуализацию данных с помощью умопомрачительных функций Seaborn!
Примечание. Эта запись в блоге предполагает базовое знакомство с Python и концепциями анализа данных. Привет, энтузиасты данных! Добро пожаловать в мой блог, где я расскажу о невероятных..


Для любых предложений по сайту: [email protected]