代码审查最佳方式使用SharedPreferences解决MemoryLeak

时间:2017-11-17 11:08:43

标签: android memory-leaks kotlin sharedpreferences

我尝试解决共享首选项使用中的内存泄漏,我尝试整天做这个,但仍然混淆,我的目标是可以在任何我想要的地方调用pref。这是我的代码。

class Preferences (private val context: Context) {

private val sharedPreferences: SharedPreferences =
        context.getSharedPreferences(context.packageName+"_pref", Context.MODE_PRIVATE)
private val editor: SharedPreferences.Editor

companion object {
    private val KEY_USER = "user"
    private val KEY_EMAIL = "email"
}

init {
    editor = sharedPreferences.edit()
}

private fun isKeyExist(Key: String): Boolean = sharedPreferences.contains(Key)

private fun putString(Key: String, value: String) {
    editor.putString(Key, value)
    editor.apply()
}
private fun putInt(Key: String, value: Int) {
    editor.putInt(Key, value)
    editor.apply()
}
private fun putBoolean(Key: String, value: Boolean) {
    editor.putBoolean(Key, value)
    editor.apply()
}
private fun putDouble(key: String, value: Double) {
    editor.putLong(key, java.lang.Double.doubleToRawLongBits(value))
}

private fun getInt(Key: String): Int = sharedPreferences.getInt(Key, 0)
private fun getString(Key: String): String = sharedPreferences.getString(Key, "")
private fun getBoolean(key: String): Boolean = sharedPreferences.getBoolean(key, false)
private fun getLong(key: String): Long = sharedPreferences.getLong(key, 0)

fun init (){
    if(!isKeyExist(KEY_USER)){
        putString(KEY_USER,"")
    }
    if(!isKeyExist(KEY_EMAIL)){
        putString(KEY_EMAIL,"")
    }
}

private fun resetPref(){
    if(isKeyExist(KEY_USER)){
        putString(KEY_USER,"")
    }
    if(isKeyExist(KEY_EMAIL)){
        putString(KEY_EMAIL,"")
    }
}

var user : String
    get() = getString(KEY_USER)
    set(value) = putString(KEY_USER,value)
var email : String
    get() = getString(KEY_EMAIL)
    set(value) = putString(KEY_EMAIL,value)

因为pref需要上下文,所以我在某个类中初始化pref,扩展Application,如下面的代码,

class BaseApplication : android.app.Application() {

override fun onCreate() {
    super.onCreate()
    preferences = Preferences(applicationContext)
}

companion object {
    @SuppressLint("StaticFieldLeak")
    var preferences : Preferences? = null
}

使用这种方法,可以通过这种简单的方式调用pref,比如活动,片段或没有上下文的某个类,

BaseApplication.preferences!!.user

但它会在我的应用中造成内存泄漏。 如果有人能给我一些如何解决内存泄漏的建议,我将不胜感激。

1 个答案:

答案 0 :(得分:0)

我们将此用作单例模式。使用这个类:

public class Prefs {

private static final String TAG = "Prefs";

static Prefs singleton = null;

static SharedPreferences preferences;

static SharedPreferences.Editor editor;

private static Gson GSON = new Gson();
Type typeOfObject = new TypeToken<Object>() {
}.getType();

Prefs(Context context) {
    preferences = context.getSharedPreferences(TAG, Context.MODE_PRIVATE);
    editor = preferences.edit();
}

public static Prefs with(Context context) {
    if (singleton == null) {
        singleton = new Builder(context).build();
    }
    return singleton;
}

public void save(String key, boolean value) {
    editor.putBoolean(key, value).apply();
}

public void save(String key, String value) {
    editor.putString(key, value).apply();
}

public void save(String key, int value) {
    editor.putInt(key, value).apply();
}

public void save(String key, float value) {
    editor.putFloat(key, value).apply();
}

public void save(String key, long value) {
    editor.putLong(key, value).apply();
}

public void save(String key, Set<String> value) {
    editor.putStringSet(key, value).apply();
}

// to save object in prefrence
public void save(String key, Object object) {
    if (object == null) {
        throw new IllegalArgumentException("object is null");
    }

    if (key.equals("") || key == null) {
        throw new IllegalArgumentException("key is empty or null");
    }

    editor.putString(key, GSON.toJson(object)).apply();
}

// To get object from prefrences

public <T> T getObject(String key, Class<T> a) {

    String gson = preferences.getString(key, null);
    if (gson == null) {
        return null;
    } else {
        try {
            return GSON.fromJson(gson, a);
        } catch (Exception e) {
            throw new IllegalArgumentException("Object storaged with key "
                    + key + " is instanceof other class");
        }
    }
}

public boolean getBoolean(String key, boolean defValue) {
    return preferences.getBoolean(key, defValue);
}

public String getString(String key, String defValue) {
    return preferences.getString(key, defValue);
}

public int getInt(String key, int defValue) {
    return preferences.getInt(key, defValue);
}

public float getFloat(String key, float defValue) {
    return preferences.getFloat(key, defValue);
}

public long getLong(String key, long defValue) {
    return preferences.getLong(key, defValue);
}

public Set<String> getStringSet(String key, Set<String> defValue) {
    return preferences.getStringSet(key, defValue);
}

public Map<String, ?> getAll() {
    return preferences.getAll();
}

public void remove(String key) {
    editor.remove(key).apply();
}

public void removeAll() {
    editor.clear();
    editor.apply();
}

private static class Builder {

    private final Context context;

    public Builder(Context context) {
        if (context == null) {
            throw new IllegalArgumentException("Context must not be null.");
        }
        this.context = context.getApplicationContext();
    }

    /**
     * Method that creates an instance of Prefs
     *
     * @return an instance of Prefs
     */
    public Prefs build() {
        return new Prefs(context);
    }
}
}

kotlin版本:

class Prefs internal constructor(context: Context) {
internal var typeOfObject = object : TypeToken<Any>() {

}.type

val all: Map<String, *>
    get() = preferences.all

init {
    preferences = context.getSharedPreferences(TAG, Context.MODE_PRIVATE)
    editor = preferences.edit()
}

fun save(key: String, value: Boolean) {
    editor.putBoolean(key, value).apply()
}

fun save(key: String, value: String) {
    editor.putString(key, value).apply()
}

fun save(key: String, value: Int) {
    editor.putInt(key, value).apply()
}

fun save(key: String, value: Float) {
    editor.putFloat(key, value).apply()
}

fun save(key: String, value: Long) {
    editor.putLong(key, value).apply()
}

fun save(key: String, value: Set<String>) {
    editor.putStringSet(key, value).apply()
}

// to save object in prefrence
fun save(key: String?, `object`: Any?) {
    if (`object` == null) {
        throw IllegalArgumentException("object is null")
    }

    if (key == "" || key == null) {
        throw IllegalArgumentException("key is empty or null")
    }

    editor.putString(key, GSON.toJson(`object`)).apply()
}

// To get object from prefrences

fun <T> getObject(key: String, a: Class<T>): T? {

    val gson = preferences.getString(key, null)
    return if (gson == null) {
        null
    } else {
        try {
            GSON.fromJson(gson, a)
        } catch (e: Exception) {
            throw IllegalArgumentException("Object storaged with key "
                    + key + " is instanceof other class")
        }

    }
}

fun getBoolean(key: String, defValue: Boolean): Boolean {
    return preferences.getBoolean(key, defValue)
}

fun getString(key: String, defValue: String): String? {
    return preferences.getString(key, defValue)
}

fun getInt(key: String, defValue: Int): Int {
    return preferences.getInt(key, defValue)
}

fun getFloat(key: String, defValue: Float): Float {
    return preferences.getFloat(key, defValue)
}

fun getLong(key: String, defValue: Long): Long {
    return preferences.getLong(key, defValue)
}

fun getStringSet(key: String, defValue: Set<String>): Set<String>? {
    return preferences.getStringSet(key, defValue)
}

fun remove(key: String) {
    editor.remove(key).apply()
}

fun removeAll() {
    editor.clear()
    editor.apply()
}

private class Builder(context: Context?) {

    private val context: Context

    init {
        if (context == null) {
            throw IllegalArgumentException("Context must not be null.")
        }
        this.context = context.applicationContext
    }

    /**
     * Method that creates an instance of Prefs
     *
     * @return an instance of Prefs
     */
    fun build(): Prefs {
        return Prefs(context)
    }
}

companion object {

    private val TAG = "Prefs"

    lateinit var singleton: Prefs

    lateinit var preferences: SharedPreferences

    lateinit var editor: SharedPreferences.Editor

    private val GSON = Gson()

    fun with(context: Context): Prefs {
        if (singleton == null) {
            singleton = Builder(context).build()
        }
        return singleton
    }
}
}

您需要使用Google GSON来保存对象。 打电话是这样的:

Prefs.with(context).save("key","value or object or int or boolean");

希望这有帮助。