Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Proposal] Introduce kvs-schema #311

Merged
merged 5 commits into from
Feb 22, 2016

Conversation

rejasupotaro
Copy link
Contributor

Overview

  • Introduced kvs-schema
  • Simplified SettingSwitchRowView
  • Deleted PrefUtil

Problem & Solution

Currently, this app retrieves shared preferences through PrefUtil. It's a typical way but it has some problems.

Problem 1: Difficult to guess value types

PrefUtil has keys below.

public static final String KEY_CURRENT_LANGUAGE_ID = "current_language_id";
public static final String KEY_NOTIFICATION_SETTING = "notification_setting";
public static final String KEY_HEADS_UP_SETTING = "heads_up_setting";
public static final String KEY_SHOW_LOCAL_TIME = "show_local_time";

It looks that notification_setting could take json and show_local_time could take date. At first glance, I didn't understand what kind of data are stored in this app 😕

Problem 2: Need to declare similar accessors repeatedly

In this way, we need to declare new accessor when we add new value types.

public static void put(Context context, @NonNull String name, boolean value) {
    SharedPreferences.Editor edit = getPref(context).edit();
    edit.putBoolean(name, value);
    edit.apply();
}

public static void put(Context context, @NonNull String name, String value) {
    SharedPreferences.Editor edit = getPref(context).edit();
    edit.putString(name, value);
    edit.apply();
}

public static void put(Context context, @NonNull String name, int value) {
    SharedPreferences.Editor edit = getPref(context).edit();
    edit.putInt(name, value);
    edit.apply();
}

public static void put(Context context, @NonNull String name, float value) {
    SharedPreferences.Editor edit = getPref(context).edit();
    edit.putFloat(name, value);
    edit.apply();
}

public static void put(Context context, @NonNull String name, Set<String> value) {
    SharedPreferences.Editor edit = getPref(context).edit();
    edit.putStringSet(name, value);
    edit.apply();
}

...

Solution

I introduced kvs-schema that is a library to manage shared preferences. kvs-schema generates methods below statically using annotation processor.

  • get*
  • put*
  • remove*
  • has*
  • set* (for Kotlin)

By this change, we can just focus on key-value management.

How to introduce kvs-schema

For the case of existing app

Step 1: Add dependencies

Add dependencies to your build.gradle.

compile 'com.github.rejasupotaro.kvs-schema:library:2.0.0'
apt 'com.github.rejasupotaro.kvs-schema:compiler:2.0.0'

Step 2: Declare schema class.

In this case, PrefUtil had keys below.

public static final String KEY_CURRENT_LANGUAGE_ID = "current_language_id";
public static final String KEY_NOTIFICATION_SETTING = "notification_setting";
public static final String KEY_HEADS_UP_SETTING = "heads_up_setting";
public static final String KEY_SHOW_LOCAL_TIME = "show_local_time";

Hence, the schema class becomes like below.

@Table("io.github.droidkaigi.confsched_preferences")
public class DefaultPrefsSchema {
    @Key("current_language_id")
    String languageId;
    @Key("notification_setting")
    boolean notificationFlag;
    @Key("heads_up_setting")
    boolean headsUpFlag;
    @Key("show_local_time")
    boolean showLocalTimeFlag;

    private static DefaultPrefs prefs;

    public static synchronized DefaultPrefs get(Context context) {
        if (prefs == null) {
            prefs = new DefaultPrefs(context);
        }
        return prefs;
    }
}

Notes 📝

  • The table name should be the same as the file name. This app already has default shared preferences and its name is io.github.droidkaigi.confsched_preferences.xml (package name + "_preferences" by default). So I declared the table name as "io.github.droidkaigi.confsched_preferences".
  • The key names should be the same as existing key names as well. On the other hand, you can change field names as you like.
    • I recommend to use flag suffix for boolean field like showLocalTimeFlag. kvs-schema generates method from field name. If you use is* for boolean, the getter method name becomes getIs*. It doesn't look cool 😕
  • I declared DefaultPrefsSchema.get as a static synchronized method. This method may not be called from many threads at the same time. I guess that the synchronization cost is not so high.

How to add new key

Just add @Key("key_name") Type field to DefaultPrefsSchema.

@rejasupotaro
Copy link
Contributor Author

@konifar I sent just a proposal PR. I would like to hear your opinion.

@hotchemi
Copy link
Contributor

This is what I thought!

binding.notificationSwitchRow.init(PrefUtil.KEY_NOTIFICATION_SETTING, true);
binding.localTimeSwitchRow.init(PrefUtil.KEY_SHOW_LOCAL_TIME, false);

boolean shouldNotify = DefaultPrefsSchema.get(getContext()).getNotificationFlag(true);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder using getContext causes memory leaks cuz it just returns the Context this fragment is currently associated with. Should we use application context?

refs. https://github.com/rejasupotaro/kvs-schema/blob/06d9eaf3b7b156d7e86b6115b0d2bb68129af77c/library/src/main/java/com/rejasupotaro/android/kvs/PrefsSchema.java#L12

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we don't have to use application context. Generally speaking, memory leak could occur when given context is used in different lifetime. Meanwhile in kvs-schema, DefaultPrefsSchema.get runs synchronoushly and this library doesn't hold a reference of context. CMIIW 🙇

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok!

@hotchemi
Copy link
Contributor

Almost awesome! This app will be a showcase of Japanese cool libraries.

@sys1yagi
Copy link

😍

@konifar
Copy link
Owner

konifar commented Feb 22, 2016

👀

@konifar
Copy link
Owner

konifar commented Feb 22, 2016

Thanks for your cool solution and detailed description!
LGTM!

konifar added a commit that referenced this pull request Feb 22, 2016
@konifar konifar merged commit 90bbf0e into konifar:master Feb 22, 2016
@konifar konifar added this to the 1.1.4 milestone Feb 28, 2016
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants