3

問題の説明:

私のAndroidアプリでは、アラームが鳴った後に開始されたAsyncTaskからリモートHTTP(「ポーリング」)呼び出しを行うと、接続の問題が発生します。

Androidの標準設定である[常時オンのモバイルデータを有効にする]([設定]->[ワイヤレスとネットワーク]->[モバイルネットワーク])を[オン]すると、ルックアップは非常にうまく機能します。

動作するソリューション:アラームが鳴り、Androidの「サービス」がアラームインテントを受信し、バックグラウンドスレッド(AsyncTask)を開始します。新しいスレッドは部分的なウェイクロックを取得し、接続を確立(ポーリング)し、ユーザーに通知してウェイクロックを解放します。

ここまでは順調ですね。問題は、常時オンが「オフ」になっている場合、電話がしばらく(> 30分)スタンバイ状態になっていると、ほとんどの場合、ポーリングが失敗することです。

ポーリングスレッドが通知を送信するので、失敗したポーリングの試行に関するフィードバックを直接受け取ります。

動機:

多くのユーザーは、バッテリーの消耗を減らすために「常時オン」をオンにします。そのため、アプリユーザーが問題に遭遇する可能性があります。ユーザーが直面する「エラー」を処理または防止したい。

解決策の試み:

私は大きなブレークスルーなしで多くの実験をしました:

  • 電話に接続を確立するための時間を与えるための複数回の再試行と中間スリープ
  • httpパラメータ(タイムアウトなど)
  • 別のHttpClient(Apache)

質問:

  • 「常時オン」の設定は正確には何を意味し、開発者は何を考慮する必要がありますか?
  • 「常時オン」を「オフ」にしてもデータ接続を確立できるアラームベースのポーリングメカニズムを実装することは一般的に可能かと思います。
  • 代替ソリューションはありますか(C2DMは不可能)?

アップデート:

すべてのAndroidデバイスが「常時オン」に設定されているわけではないようです。デバイスに依存しているようですが、プロバイダーに依存している可能性があります。

4

2 に答える 2

0

AlarmManager を使用している場合は、デバイスをスリープ解除する必要があります。

電話が目覚めた後、接続を確保する前に、あまりにも早く接続しようとしているのだろうか.

検討:

AlarmManager レシーバーで接続を確認しています。接続が存在しない場合は、次のようになります。

AlarmManager レシーバーから戻る前に、別のスレッドを開始します。スレッドで:

  1. ウェイクロックを取得する
  2. CONNECTIVITY_CHANGE のブロードキャスト レシーバーを登録する
  3. 接続が成功するまで妥当な時間待機します (ブロードキャスト レシーバー イベントによって示されます)。
  4. 時間が経過したら、ウェイク ロックを解除してスレッドを停止すると、電話はスリープ状態に戻ります。

CONNECTIVITY_CHANGE ブロードキャスト レシーバーからイベントを受信した後にのみ、接続を試みてください。

于 2011-05-12T17:28:59.863 に答える
0

ライブ通信プロトコルを実装する予定があり、短期間のポーリングで実装しようとしている場合、これは同様の経験で問題を明らかにする可能性があります:

私たちのアプリにも同様の要件があり、いくつかのことに気付きました。

  1. すべてのネットワークに「常時接続のモバイル データを有効にする」設定があるわけではありません。DroidX で Verizon を使用していますが、このオプションはメニューにありません。データは常にオンです。

  2. あなたが思うかもしれないことに反して、たとえあなたが部分的な wake lock を保持していなくても、電話がスリープ状態に入ってもソケットは殺されません。電話がスリープ状態になると、アプリはブロードキャスト イベント (接続変更イベントなど) の受信を停止するため、データ接続が一時的に切断されたときに Android OS に通知することはできません。アラーム ポーリングを行う代わりに、Keep-Alive を使用して HTTP 要求を送信し、応答を受け取るまで無期限に接続を開いたままにするロング ポーリングを検討してください。

  3. ブロック ソケット読み取り操作は、シグナルをドロップしても IOException、EOFException などをスローしないため、別のスレッドでネットワークの状態を定期的にチェックする必要があります。これを行う最も簡単な方法は、NetworkInterface クラスを使用して、次のようなものを構築することです。

.

private OnCheckNetworkConnectivity networkConnectivityCallback = new OnCheckNetworkConnectivity() {
        String ipAddress;

        public boolean isConnected() {
            String newIpAddress = getLocalIpAddress();
            if(newIpAddress != null) {
            if(ipAddress == null) {
                ipAddress = newIpAddress;
                return true;
            }
            if(!newIpAddress.equals(ipAddress)) {
                ipAddress = newIpAddress;
                return false;
            }

            // still the same IP address, we should still have the same connection
            return true;
            }

            ipAddress = null;
            return false;
        }

        public String getLocalIpAddress() {
            try {
                for (Enumeration<NetworkInterface> en = NetworkInterface.getNetworkInterfaces(); en.hasMoreElements();) {
                    NetworkInterface intf = en.nextElement();
                    for (Enumeration<InetAddress> enumIpAddr = intf.getInetAddresses(); enumIpAddr.hasMoreElements();) {
                        InetAddress inetAddress = enumIpAddr.nextElement();
                        if (!inetAddress.isLoopbackAddress()) {
                            return inetAddress.getHostAddress();
                        }
                    }
                }
            } catch (SocketException ex) {
            return null;
            }
            return null;
        }
    };
于 2011-05-09T20:12:43.617 に答える