2012-08-12 8 views
6

Ich habe eine Android-App, die mit dem Internet synchronisiert werden muss, aber sobald das Telefon zu schlafen geht kann ich nicht auf das Internet zugreifen. Es passiert nur, wenn der Benutzer den "Batteriemodus" verwendet, wenn er die Daten nach 15 Minuten ausschaltet. Ich habe eine Test-App geschrieben und die Daten eingeschaltet, aber es verbindet sich immer noch mit dem Server.Schalten Sie das Internet auf Android, wenn im Schlaf

Was ich versucht:

  • Wenn ich die Daten manuell ausschalten, dann die App auf dreht und es funktioniert
  • Ich habe auch versucht WakeLock, aber es hat nicht geholfen.
  • Der Alarm funktioniert wie erwartet, auch wenn das Telefon stundenlang 2.3.3

Getestet auf Motorola Atrix Android schlafen geht. Ich kann mich nicht auf Wifi verlassen. Im wirklichen Leben wird es jede Woche synchronisiert. Wie können wir es möglich machen?

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

Bitte töten Sie nicht die Batterie Ihrer Benutzer. – SLaks

+0

In "real life" wird es jede Woche synchronisiert – programmersbook

+0

haben Sie versucht, RTC-Flag anstelle von RTC_WAKEUP zu verwenden? Da das Wakeup nicht erzwungen wird, schaltet Framework möglicherweise das Netzwerk ein. Da Sie die Synchronisierung einmal in der Woche verwenden, benötigen Sie kein WAKEUP-Flag – nandeesh

Antwort

5

Ich würde sugges Um etwas zu ändern, ist das sogar nicht schlecht, es ist sogar schön sicherzustellen, dass Sie immer synchronisiert sind, mit dem einzigen Problem, dass Sie dem Benutzer nicht die Chance geben, sich zu entscheiden, denn wenn ich als Benutzer , entscheide dich, meine Daten abzuschalten. Ich will nur nicht, dass irgendjemand es anschaltet. Es könnte mehrere Gründe dafür geben, und jeder von ihnen sollte genug sein, aber sagen, dass Sie aus dem Land kommen und Sie keinen internationalen Datentarif haben und durch Zufall oder Voreinstellung haben Sie Data-Roaming aktiviert. Wenn ich herausfinden würde, dass eine bestimmte App meine Daten anschickt und eine sensible Menge Geld ausgegeben hat, wäre ich ziemlich angepisst und ich wäre persönlich.

Ein korrekterer Ansatz und eine direkte Lösung wäre auch, eine harte/vollständige Synchronisierung von Zeit zu Zeit zu machen, wann immer der Benutzer Ihre App öffnet oder Zugang zu einer Wifi-Verbindung (ConnectivityManager is your friend) basierend auf einigen einfachen Bedingungen (letztes Mal) hat Synchronisierung länger als eine Woche, veraltete gespeicherte Daten, Inkonsistenzen usw.) und in den übrigen Fällen eine sanfte Synchronisierung (Daten im Hintergrund aktualisieren).

Darüber hinaus bedeutet das regelmäßige Synchronisieren, Benutzerdaten zu verschwenden, falls der Benutzer die App nicht benutzt. Letztendlich macht dies Ihre App zu einem perfekten Kandidaten, der von Zeit zu Zeit vom System heruntergefahren wird.

Ich hoffe, es hilft. Halten Sie uns auf dem Laufenden.

Verwandte lesen: Optimizing downloads for efficient network access

+0

Guter Punkt. Sehen Sie sich auch die Artikel zum Schreiben optimierter Anwendungen an, die das Netzwerk verwenden. Es gibt Teile zum Gruppieren von Netzwerkübertragungen und zum Behandeln mehrerer Verbindungen. https://developer.att.com/developer/forward.jsp?passedItemId=7200042 –

15

Zuerst müssen Sie aus dem BroadcastReceiver und in einen IntentService dass HttpPost Code zu erhalten. Nie Netzwerk-E/A im Hauptanwendungs-Thread und onReceive() wird im Hauptanwendungs-Thread aufgerufen. Wenn Sie zum Beispiel zu lange brauchen, wird Android Ihren Code durch Ihren Internet-Betrieb beenden.

Zweitens, mit der IntentService, müssen Sie eine WakeLock verwenden. Das kann dazu führen, dass Sie my WakefulIntentService verwenden, die beide Probleme behandelt. Oder verwenden Sie WakefulBroadcastReceiver, das den gleichen Zweck hat.

Drittens löschen turnOnInet() und getMobileDataEnabled(). Sie brauchen sie nicht, sie sind unzuverlässig und insbesondere turnOnInet() ist benutzerfeindlich - wenn der Benutzer mobile Daten wollte, hätten sie ihn eingeschaltet.

Nun, all das gegeben, in Ihrem onHandleIntent() Ihrer IntentService() (oder Ihre doWakefulWork() Ihrer WakefulIntentService), wenn Sie sofort über keine Internetverbindung haben, als eine vorübergehende Lösung, SystemClock.sleep() für eine Sekunde und versuchen Sie es erneut, wiederhole ein paar Mal in einer Schleife. Wenn Sie feststellen, dass Sie nach einiger Zeit Zugriff auf das Internet haben, können Sie sich überlegen, ob Sie mehr auf Konnektivität, Broadcast oder Polling achten, obwohl dies Sie von WakefulIntentService in einen normalen Service mit Ihrem eigenen Hintergrund-Thread vertreiben würde und eine Zustandsmaschine für WakeLock Management). Oder bleib einfach bei der sleep() - es ist unwahrscheinlich, dass es das Ende der Welt ist, wenn du diesen Hintergrund-Thread für ein paar Sekunden festhältst. Wenn Sie jedoch nach einiger Zeit keine Verbindung erhalten, versuchen Sie es bitte nicht unbegrenzt, da es eine Reihe von Gründen gibt, warum Sie keine Verbindung erhalten, einschließlich benutzergesteuerter Bandbreitenverwaltung unter Android 4.0 und höher.

+0

Ich habe seit Wochen jetzt gekämpft. Irgendwelche Ideen, warum Ihr 'WakefulIntentService' richtig verwendet, gibt meinem Hintergrunddienst-Internet immer noch nicht, wenn es aus dem Tiefschlaf geweckt wurde, obwohl es mehrere Male versucht hat, sich mit dem Schlaf zu verbinden? Ich plane den Dienst mit dem Alarmmanager, und ich weiß, dass ich eine Sendung planen sollte, die dann den Dienst tatsächlich startet, obwohl ich sehe, dass der Dienst pünktlich startet, aber das Gerät hat einfach kein Internet (ping google) . Ich bin wirklich ratlos. –

+1

@CordRehn: Doze-Modus, vielleicht. Oder, wenn das Gerät keine mobilen Daten hat, braucht es Zeit, um eine WiFi-Verbindung herzustellen. – CommonsWare

+0

Danke für deine Zeit, ich werde jetzt den Doze-Modus untersuchen. Ich war großzügig und gab dem Gerät 3 Minuten, um erfolgreich mit 10 Sekunden Timeouts und 3 Sekunden Intervallen ping zu googeln. Ich denke nicht, dass die Lösung nur "länger warten" ist? –

1

Keine genaue Antwort - aber dieser Ansatz würde die Lebensdauer der Batterie absolut ruinieren. Der ganze Sinn des Schlafes ist es, Batteriestrom zu sparen, und diese App würde nichts tun, als ein Ärgernis für Kunden zu sein, egal wie nützlich die Funktionen sind.

Was ich vorschlagen würde ist, dass, wenn es absolut notwendig ist, eine Verbindung zum Internet herzustellen, während die App nicht verwendet wird - einen Auslöser für wenn das Telefon aufwacht. Wenn es nicht vollständig notwendig ist, ist es wahrscheinlich am besten, wenn Sie die App bei jedem Öffnen der App einfach wieder mit dem Internet verbinden.

Verwandte Themen