web-dev-qa-db-ja.com

Android Oreo JobIntentService Android 7以下でバックグラウンドで実行し続けると、Android 8以上で頻繁にクラッシュします

Oreo以上ではバックグラウンド実行制限( https://developer.Android.com/about/versions/oreo/background )があるため、最近すべてのサービスをフォアグラウンドサービスとJobIntentServiceに置き換えました。ドキュメントによると、JobIntentServiceはAndroid 7&以下の場合はIntent Serviceのように動作し、Android 8以降の場合はJobSchedulerのように動作します。問題があることに気付きました。 Googleが提供する新しいJobIntentService。

Android 8以降:

Android 8以上で継続的にクラッシュが発生しています。同じ問題について言及されているチケットがここにありました https://issuetracker.google.com/issues/6362229 そして、私は数人のオタクが示唆する一時的な修正を追加しました。

Android 7以下:Intent Serviceのように動作するJobIntentServiceは、作業が完了すると停止しません。

ユーザーが何らかのアクションを実行するたびにトリガーされるサービス内にJobIntentServiceを実装しました。

コード

public class SampleJobIntentService extends FixedJobIntentService {

public static void postData(Context context, String data) {
    Intent intent = new Intent(context, SampleJobIntentService.class);
            intent.setAction(INITIAL_ACTION);
            intent.putExtra(SAMPLE_ID, data);
            SampleJobIntentService.enqueueWork(context,intent);
}

public static void enqueueWork(Context context, Intent work) {
    SampleJobIntentService.enqueueWork(context, SampleJobIntentService.class, JOB_ID, work);

 @Override
    protected void onHandleWork(@NonNull Intent intent) {
        if (intent != null) {
            SampleRequest sampleRequest = requests.get(intent.getAction());
            if (sampleRequest != null) {
                try {
                   // perform some networking operations
                } catch (Exception ex) {
                    Log.d("Error for intent ");
                }
                Log.i("send action ");
            } else
                Log.e("action not found for ");
        }
    }
    }

JobIntentServiceによるクラッシュを回避するために、 https://issuetracker.google.com/issues/6362229 からいくつかの参照を取得しました

public abstract class FixedJobIntentService extends JobIntentService {

    @Override
    GenericWorkItem dequeueWork() {
        try {
            return new FixedGenericWorkItem(super.dequeueWork());
        } catch (SecurityException ignored) {
            doStopCurrentWork();
        }
        return null;
    }

    private class FixedGenericWorkItem implements GenericWorkItem {
        final GenericWorkItem mGenericWorkItem;

        FixedGenericWorkItem(GenericWorkItem genericWorkItem) {
            mGenericWorkItem = genericWorkItem;
        }

        @Override
        public Intent getIntent() {
            if (mGenericWorkItem != null) {
                return mGenericWorkItem.getIntent();
            }
            return null;
        }

        @Override
        public void complete() {
            try {
                if (mGenericWorkItem != null) {
                    mGenericWorkItem.complete();
                }
            } catch (IllegalArgumentException ignored) {
                doStopCurrentWork();
            }
        }
    }
}
6
Kalai.G

ええと...、それはとても大きな理論です... !!ここにすべてを置くことはできません。あなたのコンセプトを明確にするために最善を尽くします。


私は既にグーグルのドキュメントを読んで2年を失っています... _use-less_です__no proper documentation_と_no proper sample codes for its developers_ .. !!それで、私は_stack-overflow_のすべての私の投稿でこれについて言及します。他の人の時間を節約するのに役立ちます。


あなたは良いプログラマーのようです。いくつかの_hints to your posted question_が必要です:

ヒント1:

あなた:-私は最近すべてのサービスをフォアグラウンドサービスとJobIntentServiceに置き換えました

フォアグラウンドサービス:

_ALL THE TIME RUNNING PROCESS; WHICH WILL NEVER END... ONCE IT IS STARTED_が必要な場合は、OnStartCommandから_START_STICKY_を返すサービスで使用されます。いずれにしても、なんらかのコストで実装する場合と同様に使用することはお勧めしません...次に、setOngoing(true)を使用して通知を使用する必要があります。どのエンドユーザーは通知をスワイプで削除できません。永遠にそこに残ります...

フォアグラウンドサービスの使用:

受信機にも制限がありました。上記のOreo以降では、すべてのレシーバーとインテントアクションをマニフェストで宣言してレシーバーを作成するだけでは使用できません... BootComplete権限を使用し、_boot_completed_インテントを受け取る単一のreceiverを使用することをお勧めしますOより下の場合はserviceを呼び出し、Oより上はフォアグラウンドサービスを呼び出します。次に、そのフォアグラウンドサービスからすべてのランタイムレシーバーを実装し、Ondestroyメソッドで登録解除します。私はランタイムレシーバーを実装するための公式のサンプルコードを見つけたことはありません。最後に、何ヶ月もかけて苦労してそれを正常に実装しました。

フォアグラウンドサービスを使用する場合:

ブロードキャストレシーバーを実装する場合のみ...ブロードキャストレシーバーを実装しない場合。離れてください.......

ヒント2:

あなた:-私は最近すべてのサービスをフォアグラウンドサービスとJobIntentServiceに置き換えました

**サービスの品質:**

非常に小さな作業を行っているだけ...そして終了するだけです... StopSelf()によって終了する必要があります_...繰り返しますが、_Services can cause data-loss_が複数回呼び出された場合...同じサービススレッドと同様に複数回実行する...サービスに多くの作業を実行させたい場合は、再度_START_STICKY_を使用してください...しかし、これは推奨されておらず、ヒントでいつ使用するかはすでに提案しています1。

** Intentserviceの品質は次のとおりです。**

比較的長時間実行されているタスクを実行していて、_property of execution serially only_がある場合同じintentServiceを何度も呼び出すと、すべての呼び出しがqueueに保持され、_one by one_の終了後に_one by one_が実行されます。上に示したように、これは実際のサービスには当てはまりません。それ自体で終了します...開発者が終了する必要はありません.. !!

**すべてのユニークな品質:**

それらがcrashed Androidになると、アプリをクラッシュさせるので、通知せずに呼び出しを停止できます。_try-catch-exception_から_avoid crash_で処理する必要があります。繰り返します。 。_you are implementing threads within services_の場合_try-catch-exception_ _will not save your application from being crashing_...

**次に、地獄とそれを実装する方法:**

FireBaseJobScedularを使用します:-

  1. 使いやすい
  2. シンプルなJobServiceを使用
  3. より長いまたはより短い時間のタスクを実行できます... _EVEN ALL THE TIME RUNNING TASK_
  4. _EVEN SUPPORTED BY NON STANDARD COMPANIES_は、vivo、mi、oppo、one + 3などのように、_stock-Android_に変更を加え、FunTouchOs、ColorOs、OxygenOsなどの名前を付けます。
  5. バッテリーの設定を「このアプリを最適化しない」に変更するだけです
  6. はいグーグルはそれを公式にサポートし、それを使用することをお勧めします
  7. GooglePlyServiceのインスタンスを作成し、その中で実行します。明らかに非標準の企業も、Googleアプリがそのタスクを実行することを制限しません。
  8. Oreo ..で動作します。_Android P_でテストした場合でも、Androidバージョン5.0をAlarmManagerタスクとして動作します。
  9. それでも、_minsdk above 16_、_target sdk 26_を使用することをお勧めします。これは、アプリを_google play_にアップロードする場合は必須であり、そのニュースは既に聞こえているはずです。および_compile sdk 26_。
  10. JobServiceをマニフェストにバインドし、_receive_boot_complete_の1行のアクセス許可を使用するだけです
  11. それをスケジュールするだけです...そして、それはすべてのメーカーの市場にあるすべてのデバイスで開始されます... _cold boot_および_hot boot_でも
  12. たくさんのコードと_you can focus on actual tasks_を最小限に抑えます。
  13. タスクが完了したら、_return false_を使用してタスクが完了し、JobServiceを終了することを示すことができます。

Well -CTO企業のUNKNOwnであり、さまざまな種類のAndroid携帯電話メーカー全体で_foreground service_によって引き起こされる問題を経験したため、私が提案しているのはなぜですか? _Apple and ios_なので、経験を積む必要がありました。過去18年間開発者のままで、私も今日はほとんどコード化しています...すべての開発プロジェクトとその開発戦略では、私だけが考えています。

私も修正してください...また、_what your tasks_とprojectについては言及していませんが、_foreground service and intent-service_で実行したいことと正確に教えてください。 。、お役に立てれば幸いです。それはあなたが望むものではなく、一般的な理論的な答えです...しかし、実際の答えを与えるために、私は正確にあなたのプロジェクトの範囲を必要とします。

11
sandhya sasane

インテントサービスのように機能するJobIntentServiceは、作業が完了すると停止しません

問題は、拡張クラスFixedJobIntentService dequeueWorkメソッドにあります。

以下のように変更してみてください

GenericWorkItem superValue = super.dequeueWork();
if (superValue != null) {
    return new FixedGenericWorkItem(superValue);
}
return null;

JobIntentSerivceコードを見ると、作業項目プロセッサロジックは下にあります。つまり、キューに作業項目がなくなるまで、すべての項目が処理されます(つまり、項目ごとにonHandleWorkが呼び出されます)。

    while ((work = dequeueWork()) != null) {
        if (DEBUG) Log.d(TAG, "Processing next work: " + work);
        onHandleWork(work.getIntent());
        if (DEBUG) Log.d(TAG, "Completing work: " + work);
        work.complete();
    }

実装の問題は、最初の作業項目を処理した後、super.dequeueWork()がnullを返すことです。これは、気にせず、null値を渡して新しいFixedGenericWorkItemオブジェクトを送信するだけです。後続の呼び出しでnull値がonHandleWorkに渡されることを確認できます。

これが問題の解決に役立つことを願っています。

1
pamradi

これだけのコードが必要だと思います。新しいクラスMyJobIntentServiceを作成し、これだけのコードを記述して、postData()を呼び出してサービスを開始します。

public class MyJobIntentService extends JobIntentService {

public static void postData(Context context, String data) {
    final Intent intent = new Intent(context, MyJobIntentService.class);
    intent.setAction(INITIAL_ACTION);
    intent.putExtra(SAMPLE_ID, data);
    enqueueWork(context, MyJobIntentService.class, 1000, intent);
}

@Override
public IBinder onBind(Intent intent) {
    return null;
}

@Override
public void onDestroy() {
    Ln.d("Cancelled service");
    super.onDestroy();
}

@Override
    protected void onHandleWork(@NonNull Intent intent) {
        if (intent != null) {
            final SampleRequest sampleRequest = requests.get(intent.getAction());
            if (sampleRequest != null) {
                try {
                   // perform some networking operations
                } catch (Exception ex) {
                    Log.d("Error for intent ");
                }
                Log.i("send action ");
            } else {                
               Log.e("action not found for ");
            }
        }
    }
}

そして、あなたのサービスをマニフェストファイルに必ず追加してください

<service
            Android:name="service.MyJobIntentService"
            Android:exported="false"
            Android:permission="Android.permission.BIND_JOB_SERVICE" />
0
Ankur