Netzwerknutzung verwalten

In dieser Lektion wird das Schreiben von Anwendungen mit detaillierter Steuerung beschrieben. über die Nutzung von Netzwerkressourcen. Wenn Ihre Anwendung viele Netzwerkbetriebe betreiben, sollten Sie Nutzereinstellungen bereitstellen, mit denen die Nutzer die wie oft Ihre App Daten synchronisiert, ob Uploads/Downloads nur bei einer WLAN-Verbindung, ob beim Roaming, und so weiter. Mit diesen Kontrollmöglichkeiten ist es weitaus unwahrscheinlicher, dass Nutzer den Zugriff Ihrer App auf Hintergrunddaten deaktivieren, wenn sie sich ihrem Limit nähern, da sie genau steuern können, wie viele Daten Ihre App verwendet.

Um mehr über die Netzwerknutzung deiner App zu erfahren, einschließlich der Anzahl und Arten von Netzwerkverbindungen über einen bestimmten Zeitraum erhalten Sie unter Web- Apps und Netzwerkverkehr mit Netzwerk Profiler Allgemeine Richtlinien zur Apps entwickeln, die die Akkulaufzeit durch Downloads und das Netzwerk reduzieren finden Sie unter Akkulaufzeit optimieren und Daten übertragen, ohne den Akku zu belasten

Sie können sich auch die Website von NetworkConnect Stichprobe.

Netzwerkverbindung eines Geräts prüfen

Ein Gerät kann verschiedene Arten von Netzwerkverbindungen haben. In dieser Lektion geht es um über eine WLAN- oder Mobilfunkverbindung. Eine vollständige Liste aller Mögliche Netzwerktypen finden Sie unter ConnectivityManager

WLAN ist normalerweise schneller. Mobile Daten werden häufig kostenpflichtig teuer sein. Eine gängige Strategie für Apps ist, große Datenmengen nur dann abzurufen, Netzwerk verfügbar ist.

Bevor Sie Netzwerkvorgänge durchführen, sollten Sie den Status der Netzwerkverbindung. Dies könnte unter anderem verhindern, dass Ihre App aus Versehen das falsche Radio nutzen. Wenn keine Netzwerkverbindung verfügbar ist, sollte Ihre Anwendung anmutig reagieren. So überprüfen Sie die Netzwerkverbindung: verwenden normalerweise die folgenden Klassen:

  • ConnectivityManager: beantwortet Fragen zum Status des Netzwerks Konnektivität haben. Anwendungen werden benachrichtigt, wenn eine Netzwerkverbindung besteht. Änderungen.
  • NetworkInfo: Beschreibt den Status eines Netzwerkschnittstelle eines bestimmten Typs (derzeit entweder Mobil oder WLAN)

Mit diesem Code-Snippet wird die Netzwerkkonnektivität für WLAN und Mobilgeräte getestet. Sie bestimmt, ob diese Netzwerkschnittstellen verfügbar sind (d. h. ob Netzwerkschnittstellen Verbindung möglich ist) und/oder verbunden ist (d. h., ob Netzwerk- und ob es möglich ist, Sockets einzurichten und Daten zu übergeben):

Kotlin

private const val DEBUG_TAG = "NetworkStatusExample"
...
val connMgr = getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
var isWifiConn: Boolean = false
var isMobileConn: Boolean = false
connMgr.allNetworks.forEach { network ->
    connMgr.getNetworkInfo(network).apply {
        if (type == ConnectivityManager.TYPE_WIFI) {
            isWifiConn = isWifiConn or isConnected
        }
        if (type == ConnectivityManager.TYPE_MOBILE) {
            isMobileConn = isMobileConn or isConnected
        }
    }
}
Log.d(DEBUG_TAG, "Wifi connected: $isWifiConn")
Log.d(DEBUG_TAG, "Mobile connected: $isMobileConn")

Java

private static final String DEBUG_TAG = "NetworkStatusExample";
...
ConnectivityManager connMgr =
        (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
boolean isWifiConn = false;
boolean isMobileConn = false;
for (Network network : connMgr.getAllNetworks()) {
    NetworkInfo networkInfo = connMgr.getNetworkInfo(network);
    if (networkInfo.getType() == ConnectivityManager.TYPE_WIFI) {
        isWifiConn |= networkInfo.isConnected();
    }
    if (networkInfo.getType() == ConnectivityManager.TYPE_MOBILE) {
        isMobileConn |= networkInfo.isConnected();
    }
}
Log.d(DEBUG_TAG, "Wifi connected: " + isWifiConn);
Log.d(DEBUG_TAG, "Mobile connected: " + isMobileConn);

Beachten Sie, dass Sie Entscheidungen nicht darauf stützen sollten, ob ein Netzwerk "verfügbar" ist. Ich sollten Sie immer prüfen, isConnected() vorher des Netzwerkbetriebs durchführen, da isConnected() Fälle wie instabilen Mobilfunknetzen, Flugmodus und eingeschränkte Hintergrunddaten.

Eine präzisere Methode, um zu prüfen, ob eine Netzwerkschnittstelle verfügbar ist, ist folgt. Die Methode getActiveNetworkInfo() gibt eine NetworkInfo-Instanz zurück. die die erste verbundene Netzwerkschnittstelle darstellt, die gefunden werden kann, oder null, Keine der Schnittstellen ist verbunden. Das bedeutet, dass keine Internetverbindung verfügbar):

Kotlin

fun isOnline(): Boolean {
    val connMgr = getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
    val networkInfo: NetworkInfo? = connMgr.activeNetworkInfo
    return networkInfo?.isConnected == true
}

Java

public boolean isOnline() {
    ConnectivityManager connMgr = (ConnectivityManager)
            getSystemService(Context.CONNECTIVITY_SERVICE);
    NetworkInfo networkInfo = connMgr.getActiveNetworkInfo();
    return (networkInfo != null && networkInfo.isConnected());
}

Um einen detaillierteren Status abzufragen, können Sie NetworkInfo.DetailedState, aber das sollte selten notwendig sein.

Netzwerknutzung verwalten

Sie können eine Einstellungsaktivität implementieren, mit der Nutzer explizit steuern können, die Nutzung der Netzwerkressourcen durch Ihre App. Beispiel:

  • Sie können Nutzern erlauben, Videos nur dann hochzuladen, wenn das Gerät mit einem WLAN.
  • Abhängig von bestimmten Kriterien, z. B. Netzwerk, können Sie eine Synchronisierung durchführen (oder nicht). Verfügbarkeit, Zeitintervall usw.

Wenn Sie eine App entwickeln möchten, die den Netzwerkzugriff unterstützt und die Netzwerknutzung verwaltet, Manifest muss die richtigen Berechtigungen und Intent-Filter haben.

  • Das Manifest, das weiter unten in diesem Abschnitt beschrieben wird, enthält Folgendes: Berechtigungen: <ph type="x-smartling-placeholder">
  • Sie können den Intent-Filter für die ACTION_MANAGE_NETWORK_USAGE , um anzugeben, dass Ihre App eine Aktivität definiert, Optionen zur Steuerung der Datennutzung. ACTION_MANAGE_NETWORK_USAGE – Einstellungen zur Verwaltung der Netzwerkdatennutzung einer bestimmten Anwendung. Wenn Ihre App über eine Einstellungsaktivität verfügt, mit der Nutzer die Netzwerknutzung steuern können, sollten Sie Deklarieren Sie diesen Intent-Filter für diese Aktivität.

In der Beispielanwendung wird diese Aktion von der Klasse SettingsActivity, die eine UI für Einstellungen anzeigt, über die Nutzer entscheiden können, wann sie einen Feed herunterladen.

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.android.networkusage"
    ...>

    <uses-sdk android:minSdkVersion="4"
           android:targetSdkVersion="14" />

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

    <application
        ...>
        ...
        <activity android:label="SettingsActivity" android:name=".SettingsActivity">
             <intent-filter>
                <action android:name="android.intent.action.MANAGE_NETWORK_USAGE" />
                <category android:name="android.intent.category.DEFAULT" />
          </intent-filter>
        </activity>
    </application>
</manifest>

Apps, die mit sensiblen Nutzerdaten umgehen und auf Android 11 und kann Netzwerkzugriff pro Prozess gewähren. Indem Sie explizit angeben, Netzwerkzugriff zulassen, isolieren Sie den gesamten Code, Daten hochladen.

Es ist zwar nicht garantiert, dass deine App versehentlich Daten hochlädt, bietet Ihnen die Möglichkeit, die Wahrscheinlichkeit zu verringern, dass Fehler in Ihrer App zu Fehlern in Ihrer App führen. Datenleck.

Im Folgenden sehen Sie ein Beispiel für eine Manifestdatei mit dem Prozess Funktionalität:

<processes>
    <process />
    <deny-permission android:name="android.permission.INTERNET" />
    <process android:process=":withoutnet1" />
    <process android:process="com.android.cts.useprocess.withnet1">
        <allow-permission android:name="android.permission.INTERNET" />
    </process>
    <allow-permission android:name="android.permission.INTERNET" />
    <process android:process=":withoutnet2">
        <deny-permission android:name="android.permission.INTERNET" />
    </process>
    <process android:process="com.android.cts.useprocess.withnet2" />
</processes>

Präferenzaktivität implementieren

Wie Sie im Manifestauszug weiter oben in diesem Thema sehen können, Die Aktivität „SettingsActivity“ hat einen Intent-Filter für ACTION_MANAGE_NETWORK_USAGE Aktion. SettingsActivity ist eine abgeleitete Klasse von PreferenceActivity Es zeigt einen Einstellungsbildschirm an (siehe Abbildung 1), über den Nutzer die Folgendes:

  • Gibt an, ob Zusammenfassungen für jeden XML-Feed-Eintrag oder nur ein Link für jeden Eintrag angezeigt werden sollen.
  • Gibt an, ob der XML-Feed heruntergeladen werden soll, wenn eine Netzwerkverbindung verfügbar ist, oder nur, wenn WLAN aktiviert ist verfügbar.

Einstellungen Festlegen einer Netzwerkeinstellung

Abbildung 1: Einstellungen.

Hier ist SettingsActivity. Beachten Sie, dass durch die OnSharedPreferenceChangeListener Wenn ein Nutzer eine Einstellung ändert, wird diese ausgelöst onSharedPreferenceChanged(), wodurch refreshDisplay auf „true“ gesetzt wird. Dadurch wird die Anzeige aktualisiert, wenn der Der Nutzer kehrt zur Hauptaktivität zurück:

Kotlin

class SettingsActivity : PreferenceActivity(), OnSharedPreferenceChangeListener {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        // Loads the XML preferences file
        addPreferencesFromResource(R.xml.preferences)
    }

    override fun onResume() {
        super.onResume()

        // Registers a listener whenever a key changes
        preferenceScreen?.sharedPreferences?.registerOnSharedPreferenceChangeListener(this)
    }

    override fun onPause() {
        super.onPause()

        // Unregisters the listener set in onResume().
        // It's best practice to unregister listeners when your app isn't using them to cut down on
        // unnecessary system overhead. You do this in onPause().
        preferenceScreen?.sharedPreferences?.unregisterOnSharedPreferenceChangeListener(this)
    }

    // When the user changes the preferences selection,
    // onSharedPreferenceChanged() restarts the main activity as a new
    // task. Sets the refreshDisplay flag to "true" to indicate that
    // the main activity should update its display.
    // The main activity queries the PreferenceManager to get the latest settings.

    override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences, key: String) {
        // Sets refreshDisplay to true so that when the user returns to the main
        // activity, the display refreshes to reflect the new settings.
        NetworkActivity.refreshDisplay = true
    }
}

Java

public class SettingsActivity extends PreferenceActivity implements OnSharedPreferenceChangeListener {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        // Loads the XML preferences file
        addPreferencesFromResource(R.xml.preferences);
    }

    @Override
    protected void onResume() {
        super.onResume();

        // Registers a listener whenever a key changes
        getPreferenceScreen().getSharedPreferences().registerOnSharedPreferenceChangeListener(this);
    }

    @Override
    protected void onPause() {
        super.onPause();

       // Unregisters the listener set in onResume().
       // It's best practice to unregister listeners when your app isn't using them to cut down on
       // unnecessary system overhead. You do this in onPause().
       getPreferenceScreen().getSharedPreferences().unregisterOnSharedPreferenceChangeListener(this);
    }

    // When the user changes the preferences selection,
    // onSharedPreferenceChanged() restarts the main activity as a new
    // task. Sets the refreshDisplay flag to "true" to indicate that
    // the main activity should update its display.
    // The main activity queries the PreferenceManager to get the latest settings.

    @Override
    public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
        // Sets refreshDisplay to true so that when the user returns to the main
        // activity, the display refreshes to reflect the new settings.
        NetworkActivity.refreshDisplay = true;
    }
}

Auf Änderungen der Einstellungen reagieren

Wenn Nutzende Einstellungen auf dem Einstellungsbildschirm ändern, werden in der Regel Auswirkungen auf das Verhalten der App haben. In diesem Snippet prüft die App Einstellungen in onStart(). wenn es eine Übereinstimmung zwischen der Einstellung und die Netzwerkverbindung des Geräts, z. B. wenn die Einstellung "Wi-Fi" ist und das Gerät eine WLAN-Verbindung hat, lädt die App den Feed herunter und aktualisiert die Display.

Kotlin

class NetworkActivity : Activity() {

    // The BroadcastReceiver that tracks network connectivity changes.
    private lateinit var receiver: NetworkReceiver

    public override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        // Registers BroadcastReceiver to track network connection changes.
        val filter = IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION)
        receiver = NetworkReceiver()
        this.registerReceiver(receiver, filter)
    }

    public override fun onDestroy() {
        super.onDestroy()
        // Unregisters BroadcastReceiver when app is destroyed.
        this.unregisterReceiver(receiver)
    }

    // Refreshes the display if the network connection and the
    // pref settings allow it.

    public override fun onStart() {
        super.onStart()

        // Gets the user's network preference settings
        val sharedPrefs = PreferenceManager.getDefaultSharedPreferences(this)

        // Retrieves a string value for the preferences. The second parameter
        // is the default value to use if a preference value is not found.
        sPref = sharedPrefs.getString("listPref", "Wi-Fi")

        updateConnectedFlags()

        if (refreshDisplay) {
            loadPage()
        }
    }

    // Checks the network connection and sets the wifiConnected and mobileConnected
    // variables accordingly.
    fun updateConnectedFlags() {
        val connMgr = getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager

        val activeInfo: NetworkInfo? = connMgr.activeNetworkInfo
        if (activeInfo?.isConnected == true) {
            wifiConnected = activeInfo.type == ConnectivityManager.TYPE_WIFI
            mobileConnected = activeInfo.type == ConnectivityManager.TYPE_MOBILE
        } else {
            wifiConnected = false
            mobileConnected = false
        }
    }

    // Uses AsyncTask subclass to download the XML feed from stackoverflow.com.
    fun loadPage() {
        if (sPref == ANY && (wifiConnected || mobileConnected) || sPref == WIFI && wifiConnected) {
            // AsyncTask subclass
            DownloadXmlTask().execute(URL)
        } else {
            showErrorPage()
        }
    }

    companion object {

        const val WIFI = "Wi-Fi"
        const val ANY = "Any"
        const val SO_URL = "http://stackoverflow.com/feeds/tag?tagnames=android&sort;=newest"

        // Whether there is a Wi-Fi connection.
        private var wifiConnected = false
        // Whether there is a mobile connection.
        private var mobileConnected = false
        // Whether the display should be refreshed.
        var refreshDisplay = true

        // The user's current network preference setting.
        var sPref: String? = null
    }
...

}

Java

public class NetworkActivity extends Activity {
    public static final String WIFI = "Wi-Fi";
    public static final String ANY = "Any";
    private static final String URL = "http://stackoverflow.com/feeds/tag?tagnames=android&sort;=newest";

    // Whether there is a Wi-Fi connection.
    private static boolean wifiConnected = false;
    // Whether there is a mobile connection.
    private static boolean mobileConnected = false;
    // Whether the display should be refreshed.
    public static boolean refreshDisplay = true;

    // The user's current network preference setting.
    public static String sPref = null;

    // The BroadcastReceiver that tracks network connectivity changes.
    private NetworkReceiver receiver = new NetworkReceiver();

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        // Registers BroadcastReceiver to track network connection changes.
        IntentFilter filter = new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION);
        receiver = new NetworkReceiver();
        this.registerReceiver(receiver, filter);
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        // Unregisters BroadcastReceiver when app is destroyed.
        if (receiver != null) {
            this.unregisterReceiver(receiver);
        }
    }

    // Refreshes the display if the network connection and the
    // pref settings allow it.

    @Override
    public void onStart () {
        super.onStart();

        // Gets the user's network preference settings
        SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(this);

        // Retrieves a string value for the preferences. The second parameter
        // is the default value to use if a preference value is not found.
        sPref = sharedPrefs.getString("listPref", "Wi-Fi");

        updateConnectedFlags();

        if(refreshDisplay){
            loadPage();
        }
    }

    // Checks the network connection and sets the wifiConnected and mobileConnected
    // variables accordingly.
    public void updateConnectedFlags() {
        ConnectivityManager connMgr = (ConnectivityManager)
                getSystemService(Context.CONNECTIVITY_SERVICE);

        NetworkInfo activeInfo = connMgr.getActiveNetworkInfo();
        if (activeInfo != null && activeInfo.isConnected()) {
            wifiConnected = activeInfo.getType() == ConnectivityManager.TYPE_WIFI;
            mobileConnected = activeInfo.getType() == ConnectivityManager.TYPE_MOBILE;
        } else {
            wifiConnected = false;
            mobileConnected = false;
        }
    }

    // Uses AsyncTask subclass to download the XML feed from stackoverflow.com.
    public void loadPage() {
        if (((sPref.equals(ANY)) && (wifiConnected || mobileConnected))
                || ((sPref.equals(WIFI)) && (wifiConnected))) {
            // AsyncTask subclass
            new DownloadXmlTask().execute(URL);
        } else {
            showErrorPage();
        }
    }
...

}

Verbindungsänderungen erkennen

Das letzte Puzzleteil BroadcastReceiver abgeleiteten Klasse, NetworkReceiver. Wenn sich die Netzwerkverbindung des Geräts ändert, NetworkReceiver fängt die Aktion ab CONNECTIVITY_ACTION, ermittelt den Status der Netzwerkverbindung und legt die Flags fest wifiConnected und mobileConnected entsprechend auf „true“ bzw. „false“ zu setzen. Fazit: dass die App bei der nächsten Rückkehr zur App nur die neuesten Feed und aktualisieren Sie die Anzeige, wenn NetworkActivity.refreshDisplay auf true.

Das Einrichten einer BroadcastReceiver, die unnötig aufgerufen wird, kann eine unnötige Belastung verursachen zu Systemressourcen. Die Beispielanwendung registriert den BroadcastReceiver NetworkReceiver Zoll onCreate(), und hebt die Registrierung onDestroy() Das ist mehr als <receiver> im Manifest deklarieren. Wenn Sie Wenn du im Manifest ein <receiver> deklarierst, kann der Ruhemodus deiner App jederzeit beendet werden auch wenn Sie sie seit Wochen nicht geschaltet haben. Durch Registrieren und Aufheben der Registrierung NetworkReceiver innerhalb der Hauptaktivität, stellen Sie sicher, dass die App nicht nach dem Verlassen der App geweckt werden. Wenn Sie ein <receiver> im Manifest und weißt genau, wo du sie brauchst, kann verwenden setComponentEnabledSetting() um sie entsprechend zu aktivieren bzw. zu deaktivieren.

Hier ist NetworkReceiver:

Kotlin

class NetworkReceiver : BroadcastReceiver() {

    override fun onReceive(context: Context, intent: Intent) {
        val conn = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
        val networkInfo: NetworkInfo? = conn.activeNetworkInfo

        // Checks the user prefs and the network connection. Based on the result, decides whether
        // to refresh the display or keep the current display.
        // If the userpref is Wi-Fi only, checks to see if the device has a Wi-Fi connection.
        if (WIFI == sPref && networkInfo?.type == ConnectivityManager.TYPE_WIFI) {
            // If device has its Wi-Fi connection, sets refreshDisplay
            // to true. This causes the display to be refreshed when the user
            // returns to the app.
            refreshDisplay = true
            Toast.makeText(context, R.string.wifi_connected, Toast.LENGTH_SHORT).show()

            // If the setting is ANY network and there is a network connection
            // (which by process of elimination would be mobile), sets refreshDisplay to true.
        } else if (ANY == sPref && networkInfo != null) {
            refreshDisplay = true

            // Otherwise, the app can't download content--either because there is no network
            // connection (mobile or Wi-Fi), or because the pref setting is WIFI, and there
            // is no Wi-Fi connection.
            // Sets refreshDisplay to false.
        } else {
            refreshDisplay = false
            Toast.makeText(context, R.string.lost_connection, Toast.LENGTH_SHORT).show()
        }
    }
}

Java

public class NetworkReceiver extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {
        ConnectivityManager conn =  (ConnectivityManager)
            context.getSystemService(Context.CONNECTIVITY_SERVICE);
        NetworkInfo networkInfo = conn.getActiveNetworkInfo();

        // Checks the user prefs and the network connection. Based on the result, decides whether
        // to refresh the display or keep the current display.
        // If the userpref is Wi-Fi only, checks to see if the device has a Wi-Fi connection.
        if (WIFI.equals(sPref) && networkInfo != null
            && networkInfo.getType() == ConnectivityManager.TYPE_WIFI) {
            // If device has its Wi-Fi connection, sets refreshDisplay
            // to true. This causes the display to be refreshed when the user
            // returns to the app.
            refreshDisplay = true;
            Toast.makeText(context, R.string.wifi_connected, Toast.LENGTH_SHORT).show();

        // If the setting is ANY network and there is a network connection
        // (which by process of elimination would be mobile), sets refreshDisplay to true.
        } else if (ANY.equals(sPref) && networkInfo != null) {
            refreshDisplay = true;

        // Otherwise, the app can't download content--either because there is no network
        // connection (mobile or Wi-Fi), or because the pref setting is WIFI, and there
        // is no Wi-Fi connection.
        // Sets refreshDisplay to false.
        } else {
            refreshDisplay = false;
            Toast.makeText(context, R.string.lost_connection, Toast.LENGTH_SHORT).show();
        }
    }
}