Mobil Programlama

Android

Ağ Kullanımını Yönetmek

Lisans: Creative Commons 26.11.2020 tarihinde güncellendi
Bakabileceğiniz Etiketler: Eğitmen: Geleceği Yazanlar Ekibi

Bu ders içeriğinde, ağ kaynaklarının kullanımını en detay seviyede denetleyebileceğimiz uygulamaları nasıl yazacağımız üzerinde duracağız. Eğer uygulamanız pek çok ağ işlemi gerçekleştiriyorsa, kullanıcınıza uygulamanın veri alışkanlıklarını (uygulamanın ne sıklıkla veri eşlemesi yapacağı, veri indirme/gönderme işlemini Wi-Fi açıkken yapıp yapmayacağı gibi) ayarlayabilmesi için yollar sağlamalısınız. Bu ayarları onların önüne koyduğunuzda, kullanıcılar sunduğunuz ayarlar sayesinde zaten ne kadar veri kullanmak istediklerini sınırlayabildikleri için büyük ihtimalle uygulamanızın veri erişimini sistem ayarları tarafında kısıtlamayı daha az tercih edecekler.

 

Bir cihazın ağ bağlantısını kontrol etmek

Bir cihaz birçok ağ bağlantısı çeşidine sahip olabilir. Bu belgede Wi-Fi ve mobil ağ bağlantısı üzerine yoğunlaşıyoruz. Olası ağ bağlantılarının tam listesine ulaşmak isterseniz ConnectivityManager belgesine bakabilirsiniz.

Wi-Fi genellikle daha hızlıdır. Mobil veri pahalı olabildiği için genellikle ölçülü kullanılmalıdır. Uygulamalarda yaygın kullanılan strateji, büyük boyutlu verilerin sadece Wi-Fi bağlantısı bulunduğunda çekilmesi yönündedir.

Ağ bağlantısını kullanmadan önce müsait olup olmadığını kontrol etmenizde fayda var. Bu kontrol ile uygulamanızın kazara yanlış kanalı kullanmasını engelleyebilirsiniz. Eğer bir ağ bağlantısı müsait değilse, uygulamanız bunu uygun şekilde kullanıcıya bildirmelidir. Ağ bağlantısını kontrol etmek için aşağıdaki sınıfları kullanabilirsiniz:

  • ConnectivityManager: Ağ bağlantısının durumu ile alakalı sorgulara cevap verir. Aynı zamanda bağlantıda değişiklik olduğu zaman uyarır.
  • NetworkInfo: Belirlenen tipteki ağın (mobil ya da Wi-Fi) durumunu verir.

Aşağıdaki kod parçası Wi-Fi ve mobil ağ bağlantısının nasıl test edileceğini gösterir. Ağ bağlantısını kullanmanın mümkün olup olmadığını, bağlantının olup olmadığını ve soketlere ulaşılıp veri taşımaya müsait olup olmadığının kontrolünün nasıl yapıldığını görebilirsiniz:


private static final String DEBUG_TAG = "NetworkStatusExample";

...

ConnectivityManager connMgr = (ConnectivityManager) 
        getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo networkInfo = connMgr.getNetworkInfo(ConnectivityManager.TYPE_WIFI); 
boolean isWifiConn = networkInfo.isConnected();
networkInfo = connMgr.getNetworkInfo(ConnectivityManager.TYPE_MOBILE);
boolean isMobileConn = networkInfo.isConnected();
Log.d(DEBUG_TAG, "Wifi connected: " + isWifiConn);
Log.d(DEBUG_TAG, "Mobile connected: " + isMobileConn);

Bağlantı öncesi kararınızı bir ağın "mevcut" (available) olup olmadığına dayanarak vermemelisiniz. Ağ üzerinde işlem yapmadan önce her zaman isConnected() metodu ile kontrol etmelisiniz çünkü isConnected() metodu, telefonun durumuna göre değişen bir yapıdadır ve dolaşımda ya da uçak modundayken farklılık gösterebilir.

Bir ağ arayüzünün (interface) uygun olup olmadığını kontrol etmenin daha kısa yolu şu şekildedir: getActiveNetworkInfo() metodu ilk bağlanılan ağı bulması durumunda NetworkInfo örneğini (instance) döndürür, aksi takdirde eğer hiçbir bağlı ağ arayüzü bulamaz ise 'null' döndürür (İnternet bağlantısı yok demektir).


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

Daha detaylı durum sorgusu yapmak isterseniz NetworkInfo.DetailedState sınıfını kullanabilirsiniz ancak bu çok nadir görülen bir gerekliliktir.

 

Ağ kullanımını yönetmek

Kullanıcınıza uygulamanızın ağ kullanımını daha açık yönetmesi için bir tercihler Activity'si kodlayabilirsiniz. Örneğin:

  • Kullanıcıya cihaz sadece Wi-Fi ağına bağlı olduğunda video yükleme izni verebilirsiniz.
  • Veri eşleme işlemlerini ağ uygunluğu, zaman aralığı gibi değişik ölçütlerle sınırlandırabilirsiniz.

Ağ erişimi ve ağ kullanımını yöneten uygulamalar yazmak için manifest dosyanızda doğru izinlerin verilmiş, doğru intent filter'ların kullanılmış olması gerekmektedir.

Manifest dosyanız aşağıdaki izinleri içermelidir:

ACTION_MANAGE_NETWORK_USAGE aksiyonuna karşı (Android 4.0 ile geldi) uygulamanızın veri kullanımın kontrol edileceği bir Activity tanımlanabileceğini göstermek için intent filter tanımlayabilirsiniz. ACTION_MANAGE_NETWORK_USAGE uygulamadaki ağın veri kullanımını yönetmek için gerekli ayarları gösterir. Eğer uygulamanızda kullanıcıya ağ kullanımını kontrol edebileceği ayarları sağlıdığınız bir Activity varsa bu Intent Filter'ı belirtmeniz gerekir. Örnek uygulamada bu işlem, indirmelerin ne zaman yapılacağını soran tercih arayüzünü gösteren SettingsActivity sınıfı tarafından yapılmıştır.

 



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

 

 

Tercihler Activity'sinin kodlanması

Yukarıdaki manifest dosyasından da görebileceğiniz üzere, örnek uygulamanın Activity'si SettingsActivity ACTION_MANAGE_NETWOK_USAGE hareketi için intent filter'a sahip. SettingsActivity, PreferenceActivity'nin alt sınıfıdır. Kullanıcın seçmesi için aşağıdaki tercihler ekranını gösterir:

  • Her XML beslemesi için özetin mi yoksa bağlantının mı gösterileceği
  • Eğer ağ bağlantısı uygunsa XML beslemesinin indirilmesi veya sadece WiFi uygun olduğunda indirilmesi

Resim 1: Örnek bir Tercih Activity'si

SettingsActivity aşağıdaki kod örneğindeki gibidir ve görüldüğü üzere OnSharedPreferenceChangeListener'ı (override) ezer. Kullanıcı bir ayarı değiştirdiğinde onSharedPreferenceChange() metodunu çağırır ve refreshDisplay değişkenini "true"ya çevirir. Bu sayede kullanıcı MainActivity'ye döndüğü zaman görüntünün yenilenmesi sağlanır.



public class SettingsActivity extends PreferenceActivity implements OnSharedPreferenceChangeListener {
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        
        // XML tercih dosyasını yükler
        addPreferencesFromResource(R.xml.preferences);
    }
  
    @Override
    protected void onResume() {
        super.onResume();

        // Anahtar değişikliği olduğunda yeni bir dinleyici (listener) kaydeder.          
        getPreferenceScreen().getSharedPreferences().registerOnSharedPreferenceChangeListener(this);
    }
  
    @Override
    protected void onPause() {
        super.onPause();

       // onResume() metodunda kaydedilen dinleyicinin (listener) kaydını siler. 
       // Bu işlemi sisteminize aşırı yüklenmemek için 
       // uygulama bu dinleyiciyi kullanmadığında ve onPause() metodunda yapmanız en iyi yöntemdir.
       getPreferenceScreen().getSharedPreferences().unregisterOnSharedPreferenceChangeListener(this);    
    }
  
    // Kullanıcı tercihleri değiştirdiğinde, 
    // onSharedPreferenceChanged() methodu ana activity'i yeni bir görev
    // olarak başlatır. refreshDisplay bayrağını "doğruya" çevirir.
    // Bu değişiklik ana activity'nin görüntüyü yenilemesi içindir.
    // Ana activity en yeni ayarları almak için PreferenceManager'a istek yollar. 
    
    @Override
    public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {    
        // refreshDisplay'i doğru olarak değiştirir. Bu sayede kullanıcı ana activity'e
        // döndüğünde görüntü yeni ayarları göstermek için kendini yeniler.
        NetworkActivity.refreshDisplay = true;
    }
}

 

Tercih değişikliklerine yanıt vermek

Kullanıcı ayarlar ekranından tercihlerini değiştirdiğinde uygulamanın davranışında değişikliklere sebep olur. Bu kod parçasında, uygulama tercih ayarları onStart() metodu içerisinde kontrol ediliyor. Eğer ayar ve cihazın ağ bağlantısında eşleşme mevcutsa (örneğin ayar Wi-Fi ise ve cihazın Wi-Fi bağlantısı mevcutsa), uygulama beslemeyi yükler ve görüntüyü yeniler.



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";
   
    // Wi-Fi bağlantı olduğunda
    private static boolean wifiConnected = false; 
    // Mobil bağlantı olduğunda
    private static boolean mobileConnected = false;
    // Görüntünün yenilenmesi gerektiğinde
    public static boolean refreshDisplay = true;
    
    // Kullanıcının mevcut ağ bağlantısı tercihi.
    public static String sPref = null;
    
    // Bir BroadcastReceiver türü olan NetworkReceiver ağ bağlantısı değişikliklerini takip eder.
    private NetworkReceiver receiver = new NetworkReceiver();
    
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        
        // BroadcastReceiver'ı ağ bağlantısı değişikliklerini denetlemek için kaydeder.
        IntentFilter filter = new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION);
        receiver = new NetworkReceiver();
        this.registerReceiver(receiver, filter);
    }
    
    @Override 
    public void onDestroy() {
        super.onDestroy();
        // Uygulama sonlandırıldığında BroadcastReceiver'ı kayıt dışı bırakır.
        if (receiver != null) {
            this.unregisterReceiver(receiver);
        }
    }
    
    // Ağ bağlantısı ve tercihler izin verirse görüntüyü yeniler.
    
    @Override
    public void onStart () {
        super.onStart();  
        
        // Kullanıcının ağ tercihlerini alır.
        SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(this);
        
        // Bu tercihler için bir string değer yaratır. İkinci parametre
        // varsayılan tercihtir. Yeni bir tercih yoksa bu kullanılır.
        sPref = sharedPrefs.getString("listPref", "Wi-Fi");

        updateConnectedFlags(); 
       
        if(refreshDisplay){
            loadPage();    
        }
    }
    
    // Ağ bağlantısını kontrol eder ve buna göre wifiConnected
    // ve mobileConnected değerlerini atar.
    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;
        }  
    }
      
    // AsyncTask alt sınıfını kullanarak stackoverflow.com sitesinden XML akışını indirir. 
    public void loadPage() {
        if (((sPref.equals(ANY)) && (wifiConnected || mobileConnected))
                || ((sPref.equals(WIFI)) && (wifiConnected))) {
            // AsyncTask alt sınıfı
            new DownloadXmlTask().execute(URL);
        } else {
            showErrorPage();
        }
    }
...
    
}

 

Bağlantıdaki değişiklikleri saptamak

Bulmacanın son parçası, BroadcastReceiver'ın alt sınıfı olan NetworkReceiver. Cihazın ağ bağlantısı değiştiğinde NetworkRecevier CONNECTIVITY_ACTION eylemini durdurarak ağ bağlantısının durumunu belirleyip wifiConnected ve mobileConnected bayraklarını 'true' ya da 'false' şeklinde ayarlar. Bunun faydası şudur: Bir dahaki sefere kullanıcı uygulamayı kullanırken uygulama sadece en son akışı yükleyecek ve NetworkActivity.refreshDisplay true şeklinde ayarlanmışsa görüntüyü yenileyecektir.

Gereksiz yere çağırılan bir BroadcastReceiver'ı kurmak, sistem kaynaklarının azalmasına sebep olur. Örnek uygulama, onCreate() metodunda BroadcastReceiver'ı NetworkReceiver'a kayıt etmekte, onDestroy() metodundaysa kayıttan kaldırmaktadır. Bu çözüm manifest dosyasında <receiver> şeklinde belirtmekten daha hafif (lightweight) bir çözümdür. <receiver>'ın manifest dosyasında belirtilmesi durumunda, uygulamanız haftalarca kullanılmamış olsa bile herhangi bir zaman uyandırılabilir. NetworkReceiver'ı MainActivity'de kayıt altına almak ya da kayıttan kaldırmak ile uygulamanızın kapatıldıktan sonra hiçbir şekilde uyandırılmayacağını garanti altına almış olursunuz. <receiver>'ı manifest dosyasında belirttiğiniz ve tam olarak nerede ihtiyacınız olduğunu bildiğiniz zaman ise setComponentEnabledSetting() metodu ile aktif hale getirebilir ya da deaktif hale getirebilirsiniz.

NetworkReceiver aşağıdaki gibidir:


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();
       
    // Kullanıcı tercihlerini ve ağ bağlantısını kontrol eder. Sonuca göre
    // görüntüyü yenileyip yenilemeyeceğine karar verir.
    // Eğer kullanıcı sadece Wi-Fi tercihi yapmışsa, Wi-Fi olup olmadığını kontrol eder.
    if (WIFI.equals(sPref) && networkInfo != null && networkInfo.getType() == ConnectivityManager.TYPE_WIFI) {
        // Eğer cihazın Wi-Fi bağlantısı varsa, refreshDisplay değerini
        // "true" ya. Bu da kullanıcı uygulamaya döndüğünde
        // görüntünün yenilenmesini sağlar.
        refreshDisplay = true;
        Toast.makeText(context, R.string.wifi_connected, Toast.LENGTH_SHORT).show();

    // Eğer tercih HERHANGİ bir ağ ise ve bağlantı varsa 
    // refreshDisplay değerini "true" yapar.
    } else if (ANY.equals(sPref) && networkInfo != null) {
        refreshDisplay = true;
                 
    // Aksi takdirde, uygulama içeriği indiremez. Ağ bağlantısı olmaması veya
    // tercihlere uymaması durumunda refreshDisplay değerini "false" yapar.
    } else {
        refreshDisplay = false;
        Toast.makeText(context, R.string.lost_connection, Toast.LENGTH_SHORT).show();
    }
}

 

Bu sayfadaki parçalar Android Open Source Project kapsamında oluşturulmuş ve paylaşılmış içeriğin küçük değişiklikler yapılmış hâlidir ve Creative Commons 2.5 Attribution License'ta belirlenen koşullara göre kullanılmıştır.

Bu eğitim içeriğinin orijinal hâline buradan ulaşabilirsiniz: Managing Network Usage