7

インターネットに同期する必要がある Android アプリがありますが、電話がスリープ状態になるとすぐにインターネットにアクセスできなくなります。ユーザーが「バッテリーモード」を使用している場合にのみ発生し、15分後にデータがオフになります。テストアプリを作成してデータをオンにしましたが、それでもサーバーに接続します。

私が試したこと:

  • データを手動でオフにすると、アプリはデータをオンにして動作します
  • WakeLock も試してみましたが、役に立ちませんでした。
  • 電話が何時間もスリープ状態になっても、アラームは期待どおりに機能します

Motorola Atrix Android 2.3.3 でテスト済み。Wifiに頼ることはできません。実際には、毎週同期されます。どうすればそれを可能にすることができますか?

アラームマネージャー:

alarm_manager = (AlarmManager)getSystemService(Context.ALARM_SERVICE);
Intent intent = new Intent(this, AlarmReceiver.class);
PendingIntent pending = PendingIntent.getBroadcast(this, 0, intent, 
                        PendingIntent.FLAG_UPDATE_CURRENT);
alarm_manager.setRepeating(AlarmManager.RTC_WAKEUP, 
                        System.currentTimeMillis(), 15000, pending);

アラーム受信者:

public class AlarmReceiver extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {
        Log.d("MYTAG", "RECEIVED getMobileDataEnabled: " + getMobileDataEnabled(context));  
        if (!isOnline(context)) {
            Log.d("MYTAG", "NO INET");
            if (turnOnInet(context)) {
                Log.d("MYTAG", "INET IS ON");
            }
        }

        HttpClient httpclient = new DefaultHttpClient();
        HttpPost httppost = new HttpPost("http://xxx.xxx.xxx.xxx/ping/pong/moto/");
            try {
                List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>(1);
                nameValuePairs.add(new BasicNameValuePair("short_code", "ROFL"));
                httppost.setEntity(new UrlEncodedFormEntity(nameValuePairs));
                httpclient.execute(httppost);
                Log.d("MYTAG", "POST FINISHED");
            }
            catch (Exception e) {
                Log.e("MYTAG", "MYTAG", e);
            }
    }

    public boolean isOnline(Context context) {
        ConnectivityManager cm = (ConnectivityManager)context.getApplicationContext().getSystemService(Context.CONNECTIVITY_SERVICE);
        NetworkInfo netInfo = cm.getActiveNetworkInfo();
        if (netInfo != null){
            Log.d("MYTAG", "isAvailable: "+netInfo.isAvailable());
        }
        if (netInfo != null && netInfo.isConnectedOrConnecting()) {
            return true;
        }
        return false;
    }

    public boolean turnOnInet(Context context) {
        ConnectivityManager mgr = (ConnectivityManager)context.getApplicationContext().getSystemService(Context.CONNECTIVITY_SERVICE);
        if (mgr == null) {
            Log.d("MYTAG", "ConnectivityManager == NULL");
            return false;
        }
        try {
            Method setMobileDataEnabledMethod = mgr.getClass().getDeclaredMethod("setMobileDataEnabled", boolean.class);
            if (null == setMobileDataEnabledMethod) {
                Log.d("MYTAG", "setMobileDataEnabledMethod == null");
                return false;
            }    
            setMobileDataEnabledMethod.invoke(mgr, true);
        }
        catch(Exception e) {
            Log.e("MYTAG", "MYTAG", e);
            return false;
        }
        return true;
    }   


    private boolean getMobileDataEnabled(Context context) {
        ConnectivityManager mgr = (ConnectivityManager)context.getApplicationContext().getSystemService(Context.CONNECTIVITY_SERVICE);
        if (mgr == null) {
            Log.d("MYTAG", "getMobileDataEnabled ConnectivityManager == null");
            return false;
        }
        try {
            Method method = mgr.getClass().getMethod("getMobileDataEnabled");
            return (Boolean) method.invoke(mgr);
        } catch (Exception e) {
            Log.e("MYTAG", "MYTAG", e);
            return false;
        }
    }
}

AndroidManifest.xml

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
4

3 に答える 3

16

HttpPostまず、そのコードを から に取得する必要がありBroadcastReceiverますIntentServiceメインアプリケーション スレッドではネットワーク I/O を実行せず、メイン アプリケーション スレッドでonReceive()呼び出されます。たとえば、時間がかかりすぎると、Android はインターネット操作の途中でコードを終了します。

次に、 が与えられたIntentService場合、 を使用する必要がありますWakeLock。これにより、両方の問題を処理するmyWakefulIntentServiceを使用するように誘導される場合があります。または、WakefulBroadcastReceiver同じ目的を持つ を使用します。

3 番目に、 と を削除turnOnInet()getMobileDataEnabled()ます。それらは必要ありません。信頼性が低く、特にturnOnInet()ユーザーに敵対的です。ユーザーがモバイルデータをオンにしたい場合は、オンにします。

これらすべてを踏まえて、すぐにインターネットに接続できない場合は、一時的な回避策として、ループ内で数回繰り返して、もう一度試してくださいonHandleIntent()。しばらくしてインターネットにアクセスできるようになった場合は、より洗練されたものにすることを検討できます (たとえば、ポーリングではなく、接続変更ブロードキャストをリッスンします。ただし、これにより、独自のバックグラウンド スレッドと管理用のステート マシン)。または、単に固執するIntentService()doWakefulWork()WakefulIntentServiceSystemClock.sleep()WakefulIntentServiceServiceWakeLocksleep()-- このバックグラウンド スレッドを数秒間拘束しても、世界の終わりになることはまずありません。Android 4.0 以降でのユーザー主導の帯域幅管理など、接続できない理由はいくつかあるため、しばらくしても接続できない場合は、無制限に試行し続けないでください。

于 2012-08-19T22:37:44.233 に答える
5

そのアプローチを少し変更することをお勧めしますが、これはまったく悪いことではありません。ユーザーに決定する機会を与えていないという唯一の問題があるため、常に同期していることを確認するのも良いことです。ユーザーとして、自分のデータをオフにすることに決めました。誰にもオンにされたくないだけです。それにはいくつかの理由が考えられ、どれでも十分なはずですが、国を出て、国際データ プランがなく、偶然またはデフォルトでデータ ローミングが有効になっているとします。ある特定のアプリが私のデータをオンにして機密性の高い金額を費やしたことを発見した場合、私はかなり腹を立て、私は個人的になる.

より適切なアプローチと直接的な解決策は、ユーザーがアプリを開くか、wifi 接続にアクセスできるたびに ( ConnectivityManager はあなたの友人です)、いくつかの簡単な条件 (前回の同期) に基づいて、時々ハード/フル同期を行うことです。 1 週間以上、保存されたデータが古い、矛盾があるなど)、残りの場合はソフト同期 (バックグラウンドでデータを更新) を行います。

さらに、定期的に同期することは、ユーザーがアプリを使用しない場合に備えて、ユーザー データを浪費することを意味します。最終的に、これにより、アプリはシステムによって時々シャットダウンされる完璧な候補になります。

それが役に立てば幸い。進捗状況をお知らせください。

関連資料:効率的なネットワーク アクセスのためのダウンロードの最適化

于 2012-08-18T10:28:45.757 に答える
1

正確な答えではありませんが、このアプローチではバッテリーの寿命が完全に損なわれます。睡眠の要点はバッテリーの電力を節約することであり、このアプリは、機能がどれほど便利であっても、顧客にとって迷惑になるだけです.

私がお勧めするのは、アプリが使用されていないときにインターネットに接続することが絶対に必要な場合は、電話が起動したときのトリガーを設定することです. 完全に必要でない場合は、アプリを開くたびにインターネットに再接続することをお勧めします。

于 2012-08-20T23:29:08.377 に答える