プロセスの死後、インターフェースを使用してアクティビティ間で通信するにはどうすればよいですか?

3
Viktor Vostrikov 2020-07-09 14:14.

SDKを構築していて、実際にアクティビティを終了せずに、アクティビティ間にコールバックを実装する必要があります。以前、onActivityResultを使用して、呼び出し元のアクティビティに結果を返しました。ただし、これでアクティビティが終了し、SDKからのアクティビティを終了せずにコールバックを配信する必要があります。私の現在の実装:

fun initializeSDK(){
    SDK.getInstance().initialize(resultsCallbackImpl)
}
val resultsCallbackImpl:ResultsCallback = object : ResultsCallback {
    override fun response1() {
        
    }

    override fun response2() {
        
    }
};

たとえば、クライアントはinitializeSDK()ボタンをクリックした後、自分のアクティビティから呼び出します。次に、クライアントはインターフェイスをパラメータとして渡します。これは、SDKシングルトンのプロパティとして設定されます。次に、そのインターフェイスを使用して結果を返します。

この問題は、プロセスの停止後に発生します。シリアル化されておらず、クライアントにコールバックを返すことができなくなったため、インターフェイスはnullになります。この問題に取り組むには、コードをどのように編集すればよいですか?それも可能ですか?

クライアントがアプリケーションクラスでSDK初期化できることを知っています。その後、プロセスが終了するとリセットされます。ただし、このようなアプローチでは、クライアントが結果をアプリケーションクラスからのアクティビティに戻すことが困難になります。

4 answers

1
Sina 2020-07-13 11:08.

更新:

プロジェクトツリーを右クリックして、IMyAidlInterface.aidlという新しいAIDLファイルを追加します。

package com.test.aidlsample;

import com.test.aidlsample.MyData;

interface IMyAidlInterface {
    List<MyData> getData(long id);
}

オブジェクトをクライアントに返す必要がある場合は、オブジェクトをパーセル可能として宣言および定義し、aidlファイルにもインポートする必要があります。他のaidlファイルの横にあるMyData.aidlは次のとおりです。

package com.test.aidlsample;

// Declare MyData so AIDL can find it and knows that it implements
// the parcelable protocol.
parcelable MyData;

これは、javaフォルダー内のMyData.javaです。

public class MyData implements Parcelable {
    private long productId;
    private String productName;
    private long productValue;

    public MyData(long productId, String productName, long productValue) {
        this.productId = productId;
        this.productName = productName;
        this.productValue = productValue;
    }

    @Override
    public int describeContents() {
        return 0;
    }

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeLong(this.productId);
        dest.writeString(this.productName);
        dest.writeLong(this.productValue);
    }

    protected MyData(Parcel in) {
        this.productId = in.readLong();
        this.productName = in.readString();
        this.productValue = in.readLong();
    }

    public static final Parcelable.Creator<MyData> CREATOR = new Parcelable.Creator<MyData>() {
        @Override
        public MyData createFromParcel(Parcel source) {
            return new MyData(source);
        }

        @Override
        public MyData[] newArray(int size) {
            return new MyData[size];
        }
    };
}

次に、プロジェクトをビルドして、スタブクラスがビルドされるようにします。ビルドが成功したら、サービスを続行します。

public class SdkService extends Service {

    private IMyAidlInterface.Stub binder = new IMyAidlInterface.Stub() {
        @Override
        public List<MyData> getData(long id) throws RemoteException {
            //TODO: get data from db by id;
            List<MyData> data = new ArrayList<>();
            MyData aData = new MyData(1L, "productName", 100L);
            data.add(aData);
            return data;
        }
    };

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

そして、sdkマニフェストにサービスを追加します。次のように、クライアントへの依存関係としてsdkを追加する場合:implementation project(':sdk')AIDLファイルをクライアントに追加する必要はありません。そうでない場合は、それらを追加してクライアントアプリケーションを構築する必要があります。現在、クライアントアクティビティを実装するためだけに残っています。

public class MainActivity extends AppCompatActivity {

    IMyAidlInterface mService;

    /**
     * Class for interacting with the main interface of the service.
     */
    private ServiceConnection mConnection = new ServiceConnection() {
        public void onServiceConnected(ComponentName className,
                                       IBinder service) {
            // This is called when the connection with the service has been
            // established, giving us the service object we can use to
            // interact with the service.  We are communicating with our
            // service through an IDL interface, so get a client-side
            // representation of that from the raw service object.
            mService = IMyAidlInterface.Stub.asInterface(service);

            try {
                List<MyData> data = mService.getData(1L);
                updateUi(data);
            } catch (RemoteException e) {
                // In this case the service has crashed before we could even
                // do anything with it; we can count on soon being
                // disconnected (and then reconnected if it can be restarted)
                // so there is no need to do anything here.
            }

        }

        public void onServiceDisconnected(ComponentName className) {
            // This is called when the connection with the service has been
            // unexpectedly disconnected -- that is, its process crashed.
            mService = null;
        }
    };

    private void updateUi(List<MyData> data) {
        //TODO: Update UI here
    }

    @Override
    protected void onResume() {
        if (mService == null) {
            Intent serviceIntent = new Intent();
            
            //CAREFUL: serviceIntent.setComponent(new ComponentName("your.client.package", "your.sdk.service.path"));
            serviceIntent.setComponent(new ComponentName("com.test.sampleclient", "com.test.aidlsample.SdkService"));
            bindService(serviceIntent, mConnection, Context.BIND_AUTO_CREATE);
        } else {
            try {
                updateUi(mService.getData(1L));
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }
        super.onResume();
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }
}

クライアントアクティビティが可視化されるたびに、SDKサービスからデータを取得します。このテンプレート上にロジックを構築するだけです。SDKアクティビティでは、データをデータベースに保存し、サービスではデータベースからクエリを実行します。このサンプルでは、​​単純なパラメーターを使用しました。

私はあなたのSDKがクライアントアプリのライブラリであると仮定しました。そうでない場合は、おそらくいくつかの小さな変更を行う必要があります。そして、前に述べたように、ここで詳細を見つけることができます:Androidインターフェース定義言語(AIDL)。この件に関するSOには、サンプルがたくさんあり、さらに多くのQ / Aがあります。幸運を。

オリジナル: SDKアクティビティが前面にあるため、現在表示されていないアクティビティからコールバックを取得する必要がありますか?これを行うには、SDKのデータベースを作成し、データベースにデータを永続化し、開始アクティビティでAIDLを介してデータを取得します。

SdkService sdkService;
CallbackData callbackData

private ServiceConnection mConnection = new ServiceConnection() {
    // Called when the connection with the service is established
    public void onServiceConnected(ComponentName className, IBinder service) {
        sdkService = SdkService.Stub.asInterface(service);
    }

    // Called when the connection with the service disconnects unexpectedly
    public void onServiceDisconnected(ComponentName className) {
        Log.e(TAG, "Service has unexpectedly disconnected");
        sdkService = null;
    }
};

onCreateで:

Intent i = new Intent()
i.setClassName("your.sdk.packageName", "your.sdk.service.path.and.name");
bindService(i, mConnection, Context.BIND_AUTO_CREATE);

そして必要なときはいつでも:

if(sdkService != null){
    callbackData = sdkService.getCallbacks();
    updateUI();
}

バインダーの取得は非同期ジョブであることに注意してください。bindServiceを呼び出した直後にsdkService.getCallbackDataを呼び出すと、NullPointerExceptionが発生します。したがって、getCallbacksとupdateUIをonServiceConnected内に移動し、onResumeでbindServiceを呼び出すと、アクティビティが表示されるたびにCallbackDataがあるかどうかを確認して、UIなどを更新できます。

0
Sandeep Dhull 2020-07-12 23:52.

インターフェイスを直接使用してアクティビティ間で通信することはできません。

新しいアクティビティを開始して新しいアクティビティが表示されるとすぐに、Android OSはいつでも最初のアクティビティを強制終了できます(開発者オプション「アクティビティを保持しない」内のフラグを使用してこれを試すことができます)。そのため、SDKのユーザーは、特定のランダムな「nullポインター例外」について不平を言うでしょう。

したがって、現在の画面と前の画面の間でデータを共有したい場合は、フラグメントを使用してソリューションを再考する必要があるかもしれません。フラグメントを使用してUIを公開し、結果をアクティビティに伝達します。アクティビティは、データを必要とする適切なフラグメントを更新します。

修正を求められた既存のアプリで同様の問題に直面しました。最初にホットフィックスをリリースするために、アプリ全体をフラグメントと単一のアクティビティに切り替えました。

0
dominicoder 2020-07-13 11:35.

この問題は、プロセスの停止後に発生します。シリアル化されておらず、クライアントにコールバックを返すことができなくなったため、インターフェイスはnullになります。この問題に取り組むには、コードをどのように編集すればよいですか?それも可能ですか?

これは不可能です。クライアントプロセスが停止すると、実行中のコード(SDKを含む)がすべて消去されます。

クライアントがアプリケーションクラスでSDKを初期化でき、プロセスが終了するとリセットされることを知っています。ただし、このようなアプローチでは、クライアントが結果をアプリケーションクラスのアクティビティに戻すことが困難になります。

だから何?クライアントアクティビティが再起動された場合、SDKを再度呼び出して、その時点から使用できる新しいコールバックインスタンスを設定する必要があります。

0
David Innocent 2020-07-18 02:11.

両方のアクティビティにバインドされているsharedviewmodelを使用できます。2つのアクティビティから観察できるmutablelivedata変数があります。

理想的には、最初のアクティビティで、mutablelivedata変数内に値を入れることができます。次に、2番目のアクティビティでアクティビティを取得します。

次のリンクをたどってガイドラインを示してください。

ViewModelの概要

Related questions

MORE COOL STUFF

ケイト・ブランシェットは3日間一緒に夫と一緒に寝て、25年経ってもまだ夫と結婚しています

ケイト・ブランシェットは3日間一緒に夫と一緒に寝て、25年経ってもまだ夫と結婚しています

ケイト・ブランシェットは、夫に会ったとき、典型的な交際のアドバイスに逆らいました。

マイケルシーンが非営利の俳優である理由

マイケルシーンが非営利の俳優である理由

マイケルシーンは非営利の俳優ですが、それは正確にはどういう意味ですか?

ホールマークスターのコリンエッグレスフィールドがRomaDramaLiveでスリル満点のファンと出会う![エクスクルーシブ]

ホールマークスターのコリンエッグレスフィールドがRomaDramaLiveでスリル満点のファンと出会う![エクスクルーシブ]

特徴的なスターのコリン・エッグレスフィールドは、RomaDrama Liveでのスリル満点のファンとの出会いについて料理しました!加えて、大会での彼のINSPIREプログラム。

「たどりつけば」をオンラインでストリーミングできない理由

「たどりつけば」をオンラインでストリーミングできない理由

ノーザンエクスポージャーが90年代の最も人気のある番組の1つになった理由を確認するには、Blu-rayまたはDVDプレーヤーをほこりで払う必要があります。

バイオニック読書はあなたをより速く読むことができますか?

バイオニック読書はあなたをより速く読むことができますか?

BionicReadingアプリの人気が爆発的に高まっています。しかし、それは本当にあなたを速読術にすることができますか?

ドミニカのボイリング湖:アクセスは簡単ではありませんが、ハイキングする価値があります

ドミニカのボイリング湖:アクセスは簡単ではありませんが、ハイキングする価値があります

ドミニカのボイリング湖は、世界で2番目に大きいボイリング湖です。そこにたどり着くまでのトレッキングは大変で長いですが、努力する価値は十分にあります。

私たちの水をきれいに保つのを助けるためにあなたの髪を寄付してください

私たちの水をきれいに保つのを助けるためにあなたの髪を寄付してください

サロンからのヘアトリミングや個人的な寄付は、油流出を吸収して環境を保護するのに役立つマットとして再利用できます。

ホワイトハウスの最も記憶に残る結婚式を見てください

ホワイトハウスの最も記憶に残る結婚式を見てください

過去200年以上の間にホワイトハウスで結婚したのはほんの数人です。彼らは誰でしたか、そしてそこで結婚式を獲得するために何が必要ですか?

この太陽に優しいショルダーバッグで一日中外出してください

この太陽に優しいショルダーバッグで一日中外出してください

画像クレジット:Richard Mackney / Flickrトラベリングライトは必需品だけを運ぶことを意味するかもしれませんが、デバイスを補充する方法がない外出先では、接続を維持するのが難しくなる可能性があります。それはあなたがすべての生き物の快適さやクールなガジェットを捨てる必要があるという意味ではありません、ただあなたがいくつかのより小さなものを手に入れる必要があるということです、そしておそらくあなた自身をジュースに保つためにいくつかの、例えば非正統的な充電装置を使うでしょう。

ミッドセンチュリーリゾートのポストカードが廃墟に変わるのを見る

ミッドセンチュリーリゾートのポストカードが廃墟に変わるのを見る

ニューヨーク州スプリンググレンにある放棄されたホモワックロッジのボーリング場。キャッツキル南部のこの地域は、ニューヨーク市からのユダヤ人の行楽客に人気があることから、かつてはボルシチベルトとして知られていました。

ブルックリンスレートの美しいボードをあなたのテーブルに座らせましょう

ブルックリンスレートの美しいボードをあなたのテーブルに座らせましょう

ブルックリンスレートブルックリンスレートのマグカップとコースターの賞賛をすでに歌っており、それらの食器製品も同様に堅実です。ブルックリンスレートは、さまざまなサイズとテクスチャのスレートの完全な採石場を販売しています。一部のオプションは赤でも利用できます。上で見ることができるように、彼らは同様にカスタマイズをします。

遺伝子分析により、私たちの体内に生息する微生物の99%がカタログ化されていないことが明らかになりました

遺伝子分析により、私たちの体内に生息する微生物の99%がカタログ化されていないことが明らかになりました

画像:Juan Gaertner / Shutterstock私たちの体の内部は、私たちの細胞とは何の関係もない何十億もの微生物が住んでいる本物の生態系です。これがまだ少し気になることではなかったかのように、これらの微生物の99%が研究されたことがないことがわかりました。

Zendaya Wishes Boyfriend Tom Holland Happy Birthday with Cuddly Photo: He 'Makes Me the Happiest'

Zendaya Wishes Boyfriend Tom Holland Happy Birthday with Cuddly Photo: He 'Makes Me the Happiest'

Zendaya shared a sweet photo in honor of boyfriend Tom Holland's 26th birthday Wednesday

小さな女性:脳卒中を患った後に病院から解放されたアトランタのジューシーな赤ちゃん:「まだ癒し」

小さな女性:脳卒中を患った後に病院から解放されたアトランタのジューシーな赤ちゃん:「まだ癒し」

シーレン「Ms.JuicyBaby」ピアソンは、先月脳卒中で入院した後、「もう一度たくさんのことをする方法を学ばなければならない」ため、言語療法を受けていることを明らかにしました。

エマストーンは彼女のクリフサイドマリブビーチハウスを420万ドルでリストアップしています—中を見てください!

エマストーンは彼女のクリフサイドマリブビーチハウスを420万ドルでリストアップしています—中を見てください!

オスカー受賞者の世紀半ばの家には、3つのベッドルーム、2つのバス、オーシャンフロントの景色があります。

ジーニー・メイ・ジェンキンスは、母乳育児の経験の中で、彼女は「本当に、本当に落ち込んでいる」と言います

ジーニー・メイ・ジェンキンスは、母乳育児の経験の中で、彼女は「本当に、本当に落ち込んでいる」と言います

ジーニー・メイ・ジェンキンスは、生後4か月の娘、モナコに母乳育児をしていると語った。

投資ノート:Bioscout AU$300万シード

投資ノート:Bioscout AU$300万シード

Bioscoutは、農家を運転席に置くという使命を負っています。Artesian(GrainInnovate)やUniseedと並んで、最新のシードラウンドでチームを支援できることをうれしく思います。問題真菌症による重大な作物の損失は、農民にとって試練であることが証明されています。

リトルマーケットリサーチ1| 2022年のクイックグリンプス遠隔医療市場

リトルマーケットリサーチ1| 2022年のクイックグリンプス遠隔医療市場

遠隔医療は、パンデミック後の時代では新しいものではなく、時代遅れの分野でもありません。しかし、業界を詳しく見ると、需要と供給の強力な持続可能性と、米国で絶え間ない革命となる強力な潜在的成長曲線を示しています。

スタートアップ資金調達環境:タイのスタートアップエコシステムの次は何ですか?

スタートアップ資金調達環境:タイのスタートアップエコシステムの次は何ですか?

2021年は、世界的なベンチャーキャピタル(VC)の資金調達にとって記録的な年でした。DealStreetAsiaによると、東南アジアも例外ではなく、この地域では年間で記録的な25の新しいユニコーンが採掘されました。

ムーアの法則を超えて

ムーアの法則を超えて

計算に対する私たちの欲求とムーアの法則が提供できるものとの間には、指数関数的に増大するギャップがあります。私たちの文明は計算に基づいています—建築と想像力の現在の限界を超える技術を見つけなければなりません。

Language