2012-08-12 20 views
6

Mam aplikację na Androida, która musi być zsynchronizowana z internetem, ale gdy tylko telefon zasypia, nie mam dostępu do internetu. Dzieje się tak tylko wtedy, gdy użytkownik używa "trybu baterii", gdy wyłącza dane po 15 minutach. Napisałem aplikację testową i jej włączanie danych, ale nadal łączy się z serwerem.Włączanie Internetu w systemie Android podczas snu

Co próbowałem:

  • Po włączeniu dane ręcznie wyłączyć, a następnie aplikacja jest obrócenie go i działa
  • Próbowałem też blokada wybudzenia, ale to nie pomogło.
  • Alarm działa zgodnie z oczekiwaniami, nawet gdy telefon idzie spać godzinami

testowany na Motorola Atrix Androida 2.3.3. Nie mogę polegać na Wifi. W prawdziwym życiu będzie synchronizować co tydzień. Jak możemy to zrobić?

AlarmManager:

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); 

AlarmReceiver:

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

Proszę nie zabijać baterii użytkowników. – SLaks

+0

W "prawdziwym życiu" zsynchronizuje się co tydzień – programmersbook

+0

czy próbowałeś używać flagi RTC zamiast RTC_WAKEUP? Ponieważ przebudzenie nie jest wymuszone, może framework włączy sieć. Ponieważ używasz synchronizacji raz w tygodniu, nie potrzebujesz flagi WAKEUP. – nandeesh

Odpowiedz

5

ja bym sugges t, aby zmienić nieco to podejście, co wcale nie jest złe, nawet przyjemnie jest upewnić się, że jesteś zawsze zsynchronizowany, z jedynym problemem, który nie daje użytkownikowi szansy na podjęcie decyzji, ponieważ jeśli ja, jako użytkownik , zdecyduj się wyłączyć moje dane, po prostu nie chcę, żeby ktoś je włączał. Może istnieć kilka przyczyn takiego stanu rzeczy, a każdy z nich powinien wystarczyć, ale powiedz, że wydostajesz się z kraju i nie masz międzynarodowego planu transmisji danych i przypadkowo lub domyślnie masz włączony roaming danych. Gdybym odkrył, że pewna aplikacja zmieniła moje dane i wydała wrażliwą ilość pieniędzy, byłabym bardzo wkurzona i będę osobista.

Bardziej stosownym podejściem i prostym rozwiązaniem byłoby wykonanie synchronizacji twardej/pełnej od czasu do czasu za każdym razem, gdy użytkownik otworzy aplikację lub ma dostęp do połączenia Wi-Fi (ConnectivityManager is your friend) w oparciu o pewne łatwe warunki (ostatni raz synchronizuj dłużej niż tydzień, nieaktualne zapisane dane, niespójności itp.) i zrób miękką synchronizację (aktualizacja danych w tle) w pozostałych przypadkach.

Ponadto okresowa synchronizacja oznacza marnowanie danych użytkownika w przypadku, gdy użytkownik nie korzysta z aplikacji. To wszystko sprawia, że ​​twoja aplikacja staje się idealnym kandydatem do zamykania systemu raz na jakiś czas.

Mam nadzieję, że to pomaga. Informuj nas o swoich postępach.

Powiązane przeczytać: Optimizing downloads for efficient network access

+0

Dobra uwaga. Zapoznaj się także z artykułami o pisaniu zoptymalizowanych aplikacji korzystających z sieci. Istnieją fragmenty dotyczące grupowania transferów sieciowych i obsługi wielu połączeń. https://developer.att.com/developer/forward.jsp?passedItemId=7200042 –

15

Po pierwsze, trzeba, aby ta HttpPost kod z BroadcastReceiver a do z IntentService. Nigdy nie wykonuj do sieciowych operacji we/wy na głównym wątku aplikacji, a na głównym wątku aplikacji jest wywoływana onReceive(). Na przykład, jeśli potrwa to zbyt długo, Android zakończy Twój kod w trakcie operacji internetowych.

Po drugie, biorąc pod uwagę IntentService, należy użyć WakeLock. To może cię skłonić do użycia my WakefulIntentService, która obsługuje oba problemy. Lub użyj WakefulBroadcastReceiver, który ma ten sam cel.

Po trzecie, usuń turnOnInet() i getMobileDataEnabled(). Nie potrzebujesz ich, są niewiarygodne, a w szczególności turnOnInet() jest wrogi dla użytkownika - jeśli użytkownik chciałby danych mobilnych, włączaliby go.

Teraz, biorąc pod uwagę to wszystko, w swojej onHandleIntent() swojej IntentService() (lub doWakefulWork() swojej WakefulIntentService), jeśli nie ma połączenia z Internetem od razu, jako tymczasowe obejście, SystemClock.sleep() na chwilę i spróbuj ponownie, powtarzanie kilka razy w pętli. Jeśli zauważysz, że uzyskujesz dostęp do Internetu po pewnym czasie, możesz rozważyć uzyskanie bardziej wyrafinowanych (np. Słuchanie transmisji z połączeniem zamiast transmisji głosowej, ale to odwiodłoby Cię od WakefulIntentService i do zwykłego Service z własnym wątkiem tła i automat stanów dla zarządzania WakeLock). Lub po prostu trzymaj się z sleep() - jest mało prawdopodobne, aby to był koniec świata, jeśli zwiążesz ten wątek tła przez kilka sekund. Jeśli jednak nie otrzymasz łączności po skromnym czasie, nie próbuj bezterminowo, ponieważ istnieje wiele powodów, dla których możesz nie uzyskać połączenia, w tym zarządzania pasmem przez użytkownika w systemie Android 4.0+.

+0

Od tygodni mam problemy. Jakieś pomysły, dlaczego właściwie używasz 'WakefulIntentService' wciąż nie daje mojej usługi w tle Internetu po obudzeniu się z głębokiego snu mimo wielokrotnego próbowania połączenia ze snem? Planuję usługę z menadżerem alarmów i wiem, że powinienem zaplanować transmisję, która faktycznie uruchomi usługę, niezależnie od tego, czy widzę pożar usługi na czas, ale urządzenie po prostu nie ma internetu (pingowanie google) . Naprawdę nie mogę. –

+1

@CordRehn: Być może tryb Doze. Jeśli urządzenie nie ma komórkowej transmisji danych, nawiązanie połączenia Wi-Fi wymaga czasu. – CommonsWare

+0

Dzięki za poświęcony czas, przeszukuję teraz tryb Doze. Byłem hojny dając urządzeniu 3 minuty na pomyślne pingowanie google z 10-sekundowymi limitami czasu i 3-sekundowymi przerwami. Nie sądzę, że rozwiązaniem jest po prostu "poczekać dłużej"? –

1

Nie jest to dokładna odpowiedź - ale takie podejście całkowicie zrujnowałoby żywotność baterii. Cały sen to oszczędzanie energii baterii, a ta aplikacja nie zrobiłaby nic więcej, niż tylko irytację dla klientów, bez względu na to, jak użyteczne są te funkcje.

Co sugerowałbym, że jeśli jest absolutnie konieczne połączenie z Internetem, gdy aplikacja nie jest używana - ustaw wyzwalacz, gdy telefon się obudzi. Jeśli nie jest to całkowicie konieczne, najlepiej będzie po prostu ponownie połączyć się z Internetem przy każdym otwarciu aplikacji.

Powiązane problemy