Google은 흑인 공동체를 위한 인종 간 평등을 진전시키기 위해 노력하고 있습니다. Google에서 어떤 노력을 하고 있는지 확인하세요.

네트워크 사용 관리

이 과정에서는 네트워크 리소스 사용을 세밀하게 제어하는 애플리케이션을 작성하는 방법을 설명합니다. 애플리케이션에서 여러 네트워크 작업을 실행한다면 앱의 데이터 사용 패턴(예: 앱의 데이터 동기화 빈도, Wi-Fi에서만 업로드/다운로드 실행 여부, 로밍 중 데이터 사용 여부)을 사용자가 제어할 수 있도록 사용자 설정을 제공해야 합니다. 이러한 제어 기능을 제공하면 사용자가 사용량 한계에 가까워질 때 앱의 백그라운드 데이터 액세스를 사용 중지할 가능성이 크게 줄어듭니다. 대신 사용자가 앱의 데이터 사용량을 정밀하게 제어할 수 있기 때문입니다.

일정 기간의 네트워크 연결 횟수 및 유형을 포함한 앱의 네트워크 사용에 관한 자세한 내용은 웹 앱네트워크 프로파일러로 네트워크 트래픽 검사를 읽어보세요. 다운로드 및 네트워크 연결이 배터리 수명에 미치는 영향을 최소화하는 앱을 작성하는 방법에 관한 일반 가이드라인은 배터리 수명 최적화배터리 소모 없이 데이터 전송을 참조하세요.

NetworkConnect 샘플도 확인할 수 있습니다.

기기의 네트워크 연결 확인

기기에는 다양한 유형의 네트워크 연결이 있을 수 있습니다. 이 과정에서는 Wi-Fi 또는 모바일 네트워크 연결을 사용하는 것에 중점을 둡니다. 사용 가능한 네트워크 유형의 전체 목록은 ConnectivityManager를 참조하세요.

일반적으로 Wi-Fi 속도가 더 빠릅니다. 또한 모바일 데이터는 데이터 전송량 제한이 있는 경우가 많아서 비용이 많이 들 수 있습니다. 앱에서 사용하는 일반적 전략은 Wi-Fi 네트워크가 사용 가능할 때만 대용량 데이터를 가져오는 것입니다.

네트워크 작업을 실행하기 전에 네트워크 연결 상태를 확인하는 것이 좋습니다. 무엇보다도 이렇게 하면 앱에서 실수로 잘못된 네트워크를 사용하는 것을 방지할 수 있습니다. 네트워크 연결을 사용할 수 없다면 애플리케이션이 적절하게 응답해야 합니다. 네트워크 연결을 확인하려면 일반적으로 다음 클래스를 사용합니다.

  • ConnectivityManager: 네트워크 연결 상태에 관한 쿼리에 답합니다. 또한, 네트워크 연결이 변경될 때 애플리케이션에 알립니다.
  • NetworkInfo: 특정 유형(현재는 모바일 또는 Wi-Fi)의 네트워크 인터페이스 상태를 설명합니다.

이 코드 스니펫은 Wi-Fi 및 모바일 네트워크 연결을 테스트합니다. 이러한 네트워크 인터페이스가 사용 가능한지(즉, 네트워크 연결이 가능한지)와 연결되어 있는지(즉, 네트워크 연결이 있는지 그리고 소켓을 설정하고 데이터를 전달할 수 있는지)를 확인합니다.

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

자바

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

네트워크의 '사용 가능 여부'에 따라 결정을 내려서는 안 됩니다. 네트워크 작업을 실행하기 전에는 항상 isConnected()를 확인해야 합니다. isConnected()에서 비정상적인 모바일 네트워크, 비행기 모드, 제한된 백그라운드 데이터와 같은 사례를 처리하기 때문입니다.

네트워크 인터페이스가 사용 가능한지 확인하는 더 간단한 방법은 다음과 같습니다. getActiveNetworkInfo() 메서드는 처음 연결된 네트워크 인터페이스를 찾아서 이를 나타내는 NetworkInfo 인스턴스를 반환하거나 아무 인터페이스도 연결되지 않은 경우(즉, 인터넷 연결 불가) null 을 반환합니다.

Kotlin

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

자바

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

더 자세한 상태를 쿼리하려면 NetworkInfo.DetailedState를 사용할 수 있으나 이런 경우는 흔하지 않습니다.

네트워크 사용 관리

사용자가 앱의 네트워크 리소스 사용량을 명시적으로 제어하도록 하는 환경설정 활동을 구현할 수 있습니다. 예:

  • 기기가 Wi-Fi 네트워크에 연결된 경우에만 사용자가 동영상을 업로드하도록 허용할 수 있습니다.
  • 네트워크 가용성, 시간 간격 등 특정 기준에 따라 동기화하거나 동기화하지 않을 수 있습니다.

네트워크 액세스 및 네트워크 사용 관리를 지원하는 앱을 작성하려면 매니페스트에 올바른 권한과 인텐트 필터가 있어야 합니다.

  • 아래 발췌된 매니페스트에는 다음 권한이 포함됩니다.
  • ACTION_MANAGE_NETWORK_USAGE 작업(Android 4.0에서 도입)의 인텐트 필터를 선언하여 애플리케이션에서 데이터 사용량 제어 옵션을 제공하는 활동을 정의한다는 것을 표시할 수 있습니다. ACTION_MANAGE_NETWORK_USAGE는 특정 애플리케이션의 네트워크 데이터 사용량 관리를 위한 설정을 보여줍니다. 앱에 사용자가 네트워크 사용량을 제어할 수 있는 설정 활동이 있다면 그 활동을 위해 이 인텐트 필터를 선언해야 합니다. 샘플 애플리케이션에서 이 작업은 SettingsActivity 클래스가 처리하며, 이 클래스는 사용자가 피드를 다운로드하는 시점을 선택할 수 있는 환경설정 UI를 표시합니다.
    <?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>
    

환경설정 활동 구현

위의 매니페스트 발췌 부분에서 볼 수 있는 것처럼 샘플 앱의 활동인 SettingsActivityACTION_MANAGE_NETWORK_USAGE 작업의 인텐트 필터가 있습니다. SettingsActivityPreferenceActivity의 서브클래스입니다. 사용자가 다음 사항을 지정할 수 있는 환경설정 화면(그림 1 참조)을 표시합니다.

  • 각 XML 피드 항목의 요약을 표시할지 또는 각 항목의 링크만 표시할지 여부
  • 네트워크 연결이 가능한 경우 또는 Wi-Fi를 사용할 수 있는 경우에만 XML 피드를 다운로드할지 여부
환경설정 패널 네트워크 환경설정

그림 1. 환경설정 활동

다음은 SettingsActivity입니다. 이는 OnSharedPreferenceChangeListener를 구현합니다. 사용자가 환경설정을 변경하면 onSharedPreferenceChanged()를 실행하고, refreshDisplay를 참으로 설정합니다. 따라서 사용자가 기본 활동으로 되돌아가면 화면이 새로고침됩니다.

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
        }
    }
    

자바

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

환경설정 변경에 응답

사용자가 설정 화면에서 환경설정을 변경하면 일반적으로 앱의 동작에 영향을 미칩니다. 이 스니펫에서 앱은 onStart()의 환경설정을 확인합니다. 설정과 기기의 네트워크 연결이 일치하는 경우(예: 설정이 "Wi-Fi"이고 기기에 Wi-Fi 연결이 있는 경우) 앱에서 피드를 다운로드하고 화면을 새로고침합니다.

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
        }
    ...

    }
    

자바

    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();
            }
        }
    ...

    }
    

연결 변경 감지

마지막으로 필요한 부분은 BroadcastReceiver의 서브클래스인 NetworkReceiver입니다. 기기의 네트워크 연결이 변경되면 NetworkReceiver에서 CONNECTIVITY_ACTION 작업을 가로채고 네트워크 연결 상태가 무엇인지 확인한 다음, wifiConnectedmobileConnected 플래그를 적절히 참/거짓으로 설정합니다. 그러면 사용자가 다음에 앱으로 돌아왔을 때 앱이 최신 피드만 다운로드하고 NetworkActivity.refreshDisplaytrue로 설정되어 있으면 화면을 업데이트합니다.

불필요하게 호출되는 BroadcastReceiver를 설정하면 시스템 리소스가 소모될 수 있습니다. 샘플 애플리케이션은 onCreate()에서 BroadcastReceiver NetworkReceiver를 등록하고 onDestroy()에서 등록을 해제합니다. 이 방법은 매니페스트에서 <receiver>를 선언하는 것보다 가볍습니다. 매니페스트에서 <receiver>를 선언하면 몇 주간 앱을 실행하지 않은 앱도 언제든지 대기 상태를 해제할 수 있습니다. 기본 활동 내에서 NetworkReceiver를 등록하고 등록 취소하면 사용자가 앱을 종료한 후 앱이 대기 상태에서 전환되지 않습니다. 매니페스트에서 <receiver>를 선언하고 필요한 위치를 정확하게 알고 있는 경우 setComponentEnabledSetting()을 사용하여 적절하게 사용 설정하거나 사용 중지할 수 있습니다.

다음은 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()
            }
        }
    }
    

자바

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