Android SharedPreferences Yapısı ve Management Sınıf Oluşturma
Bu makalede SharedPreferences depolama yapısını inceleyeceğiz. Standart kullanımını örnekledikten sonra gelişmiş bir projede kullanabileceğimiz şekilde bir sınıf altında derleyip projemize sunacağız. Yazı sonunda oluşan sınıfı rahatlıkla projelerinizde kullanabilirsiniz. Ne de olsa DRY( don’t repeat yourself ) önemli bir kavram 🙂
SharedPreferences
Android platformu veri saklama ve yönetimi konusunda bir çok alternatif sunmaktadır. Bunlar kullanım alanları açısından çeşitlilik gösterir. En temel olanlarından biri SharedPreferences basit anlamda Key – Value olarak bilgi saklanan bir obje bloğudur.
Context Modları
Context modları oluşturulan depolamanın nasıl davranacağını belirler.
MODE_PRIVATE : Genelde kullandığımız,hatta set edilmediğinde default olarak seçilen moddur. Oluşan Depolamaya sadece tetiklendiği uygulama üzerinden erişim sağlanmasına olanak sağlar.
MODE_WORLD_READABLE : Diğer uygulamaların depolamaya ulaşıp veri okuyabilmesine olanak sağlar.
MODE_WORLD_WRITEABLE : Diğer uygulamaların depolamaya ulaşıp veri okuma yazmasına olanak sağlar.
Şimdi depolama objemizin detaylarına göz atalım
Obje üzerinde düzenlemeler yapmamızı sağlayan yapı Editor Interface’idir. Asıl kullandığımız metotlar editor aracılığıyla bize sunulur. Editör’e göz atalım 🙂
Apply / Commit : Objelerde ki değişikliklerin geçerli olması için Apply veya Commit metotlarının tetiklenmesi gerekir.
Clear: Preferences bloğunun temizlenmesi için kullanılır. Clear ile Preferences blogundaki tüm veri silineceği için dikkatli kullanılmalıdır.
Remove: Key – Value objenin silinmesi için kullanılır.
putInt(String key, int value): Integer bir veri tutmak istediğimizde kullanılır.
Kullanımı aynı olmakla beraber tüm primitive tipler için bir metot vardır. (putFloat, putLong, ..)
Yukarıda açıkladığımız Apply ve Commit için bir iki dip not yazalım.
Commit metotu yapılan değişiklikleri senkron olarak depolamaya kaydeder. Apply ise asenkron çalışır ve yapılan değişiklik sonrası direk olarak depolamaya yazar. Preferences yapısı ve o anda yaptığınız değişikliği ve tek bir süreci temsil ettiğinden Commit yerine Apply da kullanablirsiniz. int değerim 5 , String değerim abc oldu şimdi bunları depolayalım veya int değer 5 depola, String değer abc depola şeklinde ifade etmek gibi…
Bu arada unutmadan önemli bir ayrıntıya parmak basalım. Depolama objesine (SharedPreferences) birden fazla Editor’ün müdahale şansı vardır. Birden fazla editör kısmen de olsa aynı zamanda depolamaya etki etmeye çalışırsa bu yarışı son gelen editör kazanır ve onun dediği olur.
Şimdi Temel kullanımı örnekleyelim.
Depolamaya Veri Yazma
1 2 3 4 5 6 7 8 9 10 11 |
SharedPreferences mySharedPreferences = PreferenceManager.getDefaultSharedPreferences(getApplicationContext()); SharedPreferences.Editor myEditor= preferences.edit(); myEditor.putString("newStr", "newValue"); myEditor.putInt("newInt", 1); myEditor.commit(); |
Depolamadan Veri Okuma
1 2 3 4 5 6 7 8 |
SharedPreferences mySharedPreferences = PreferenceManager.getDefaultSharedPreferences(getApplicationContext()); String newString = mySharedPreferences.getString("newString", "defaultStr"); int newInt = mySharedPreferences.getInt("newInt", 0); |
Yukarıda ki kodlar SharedPreferences kullanımı için yeterli bir örnek. Bu şekilde yazılan bir kod takır takır çalışır, bir problem yok. Şimdi sıra bu makalemizin temel konusuna geldi. Yukarıdaki kod yanlış değil ama sürekli kendini tekrar edecek bir kod. Temel yapımızı SharedPreferences’i ve nasıl çalıştığını anladığımıza göre işi biraz daha geliştirelim. Tıkır tıkır çalıştıralım 🙂
SharedPreferences Management Sınıfı
Öncelikle oluşturacağım sınıfı kısaca açıklamakla başlayalım. SharedPreferences depolamasını derli toplu , okunabilirliği artırılmış kullanımı kolay bir sınıf üzerinden yöneteceğiz. Her zaman primitve type’ lar ile çalışmıyoruz. Oluşturacağımız sınıf Generic type üzerinden class ‘ların yönetimini de desteklemeli. Aynı zamanda uygulamanızda birden fazla SharedPreferences da kullanıyor olabilirsiniz.
Bu kötü bir tasarım mı olurdu ? Hayır olmazdı, İhtiyaca göre tabiki olabilir ? is it bad practice to have multiple sharedPreferences? o halde bizim sınıfımız da bunu desteklesin.
Şimdi kodlara geçelim.
Kodları kısa kısa açıklayacağım.
Sınıfımız birden çok Depolamaya izin vermeli demiştik. Yapıcı metotlar ile bunu sağlıyor olacağız. Dikkat edilmesi gereken yer oluşturulan sınıfın yapıcı metotları Protected yani bulunduğu package ve alt sınıflarından ulaşılabilir olmaya izin veriyor.
defaultPackageName değişkeni ile herhangi bir depolama tercihimiz yoksa kendimiz bir tane oluşturuyoruz. Mobil uygulamanın vazgeçilmezi json olduğundan GenericType olarak aldığımız veriler Gson kütüphanesi yardımıyla Depolama içinde json obje olarak saklanıyor. Bu yazıyı okuyor ve PreferenceManager sınıfını implement etmeyi düşünüyorsanız zaten vardır ama yoksa da Gson ‘ u projenize eklemeniz gerekecek. 🙂 devam edelim…
Yapıcı metotlar sayesinde kullanacağımız depolama oluşturuluyor. Benim ihtiyacım MODE_PRIVATE olduğundan içeriden statik ekledim. İhtiyaç doğrultusunda parametre olarak gönderilebilir. Aşağıdaki sınıf bize bir proje içerisinde kullanabileceğimiz int, bool, float, object, String, T Class tüm tipler ve sınıflar üzerinden işlem yapmamıza olanak sağlıyor. Her tip için get , put metotları oluşturuldu. Generic sınıflar için json çevirisi yapıldı. İstenirse Default değer dönüşleriyle desteklendi.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 |
/** * Created by hbkaradag */ public class PreferencesManager { private static final String defaultPackageName = "myPackageSettings"; private static final String emptyString = ""; private final String preferenceName; private final SharedPreferences targetPreferences; private final Gson gson = new Gson(); protected PreferencesManager(Context targetContext) { this(targetContext, defaultPackageName); } protected PreferencesManager(Context targetContext, String preferenceName) { Context targetContext1 = targetContext; this.preferenceName = preferenceName; targetPreferences = targetContext1.getSharedPreferences(preferenceName, Context.MODE_PRIVATE); } public void clearKey(String key) { if (targetPreferences.contains(key)) { putString(key, null); } } public boolean getBooleanValue(String key) { return targetPreferences.getBoolean(key, false); } public boolean getBooleanValue(String key, boolean defaultValue) { return targetPreferences.getBoolean(key, defaultValue); } public float getFloat(String key) { return targetPreferences.getFloat(key, 0); } public int getInt(String key) { return targetPreferences.getInt(key, 0); } public int getInt(String key, int defaultValue) { return targetPreferences.getInt(key, defaultValue); } public long getLong(String key) { return targetPreferences.getLong(key, 0); } public <T> T getObject(String key, Class<T> targetType) { return getObject(key, targetType, null); } public <T> T getObject(String key, Class<T> targetType, T defaultValue) { if (targetPreferences.contains(key)) { String preferenceTarget = targetPreferences.getString(key, ""); if (!preferenceTarget.equals("")) { return gson.fromJson(preferenceTarget, targetType); } } return defaultValue; } public String getPreferenceName() { return preferenceName; } public String getString(String key) { return getString(key, emptyString); } public String getString(String key, String defaultValue) { return targetPreferences.getString(key, defaultValue); } public boolean putBoolean(String key, boolean value) { SharedPreferences.Editor targetEditor = targetPreferences.edit(); targetEditor.putBoolean(key, value); return targetEditor.commit(); } public boolean putFloat(String key, float targetValue) { SharedPreferences.Editor targetEditor = targetPreferences.edit(); return targetEditor.putFloat(key, targetValue).commit(); } public boolean putInt(String key, int targetValue) { SharedPreferences.Editor targetEditor = targetPreferences.edit(); return targetEditor.putInt(key, targetValue).commit(); } public boolean putLong(String key, long targetValue) { SharedPreferences.Editor targetEditor = targetPreferences.edit(); return targetEditor.putLong(key, targetValue).commit(); } public void putObject(String key, Object targetObject) { putString(key, gson.toJson(targetObject)); } public void putString(String[] keys, String[] values) { SharedPreferences.Editor targetEditor = targetPreferences.edit(); int counter = 0; for (String key : keys) { targetEditor.putString(key, values[counter++]); } targetEditor.apply(); } public void putString(String key, String value) { SharedPreferences.Editor targetEditor = targetPreferences.edit(); targetEditor.putString(key, value); targetEditor.apply(); } } |
Sınıfımızı oluşturduk, Şimdi sıra proje içinde kullanmaya geldi.
Yeni bir sınıf oluşturuyoruz, Bu sınıf içinde static bir değişkende PreferencesManager’ proje için kullanıma açacağız.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
public class ApplicationStatics { private static PreferencesManager _preferenceManager; public static PreferencesManager getSharedPreferences(Context context){ if(_preferenceManager == null){ PreferencesManager _pManager = new PreferencesManager(context,"RamscopePreference"); _preferenceManager = _pManager; } return _preferenceManager; } } |
Son olarak onCreate metodu üzerinden PreferencesManager sınıfımızı çağıralım.
1 2 3 4 5 6 7 8 9 10 11 12 13 |
private PreferencesManager _preferencesManager; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_login); _preferencesManager = ApplicationStatics.getSharedPreferences(ActivityAdi.this); } |
Artık Activity içinde SharedPreferences’i kullanabiliriz.
1 2 3 4 5 6 7 8 9 10 11 12 13 |
// Generic Type UserMolde userModel = api.getUser(); _preferencesManager.putObject("User", userModel); // Set primitive Type _preferencesManager.putBoolean("IsEnabledNotification", true); // Get primitive Type _preferencesManager.getBooleanValue("IsEnabledNotification", default: false); |
Bence artık tıkır tıkır çalışıyor. Kod içinde tek satır ile okunabilirliği yüksek anlaması kolay bir şekilde projemizi yürütebiliriz.
Bu arada bir öneri, örneğin android için Activity’ler AppCompatActivity sınıfından extend olurlar. Aman sizin projeniz asla direkt olarak AppCompatActivity den türemesin. Kendiniz bir sınıf oluşturun mesela BaseActivity. Oluşturduğunuz BaseActivity sınıfı AppCompatActivity’ den extend edilsin. Uygulamanızdaki tüm Activity’ler de BaseActivity’ den extend olsun. BaseActivity boş bir sınıf olabilir, hiç önemli değil. İnanın proje sonunda boş kalmaz ki zaten yapılması gereken şeydir. 😉 mesela siz PreferenceManager sınıfınızı BaseActivity sınıfı içinde kullanabilirsiniz 🙂