Last active
June 25, 2016 21:23
-
-
Save Fbalashov/7dea76140ac06ef36fc97b1c82d080eb to your computer and use it in GitHub Desktop.
Declarative Persistence in Android
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?xml version="1.0" encoding="utf-8"?> | |
<RelativeLayout | |
xmlns:android="http://schemas.android.com/apk/res/android" | |
xmlns:tools="http://schemas.android.com/tools" | |
android:layout_width="match_parent" | |
android:layout_height="match_parent" | |
android:paddingBottom="@dimen/activity_vertical_margin" | |
android:paddingLeft="@dimen/activity_horizontal_margin" | |
android:paddingRight="@dimen/activity_horizontal_margin" | |
android:paddingTop="@dimen/activity_vertical_margin" | |
tools:context="com.fbalashov.persistableannotations.MainActivity"> | |
<TextView | |
android:id="@+id/text_view" | |
android:layout_width="wrap_content" | |
android:layout_height="wrap_content" | |
android:textSize="18sp"/> | |
<Button | |
android:id="@+id/increment_button" | |
android:layout_width="wrap_content" | |
android:layout_height="wrap_content" | |
android:text="@string/increment_button" | |
android:layout_below="@id/text_view"/> | |
</RelativeLayout> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.fbalashov.persistableannotations; | |
import android.os.Bundle; | |
import android.support.v7.app.AppCompatActivity; | |
/** | |
* @author Fuad.Balashov on 6/22/2016. | |
*/ | |
public class BaseActivity extends AppCompatActivity { | |
@Override | |
public void onCreate(Bundle savedInstanceState) { | |
super.onCreate(savedInstanceState); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.fbalashov.persistableannotations; | |
import android.support.v7.app.AppCompatActivity; | |
import android.os.Bundle; | |
import android.text.Editable; | |
import android.text.TextWatcher; | |
import android.view.View; | |
import android.widget.Button; | |
import android.widget.EditText; | |
import android.widget.TextView; | |
public class MainActivity extends AppCompatActivity { | |
private int persistedCount = 0; | |
@Override | |
public void onCreate(Bundle savedInstanceState) { | |
super.onCreate(savedInstanceState); | |
setContentView(R.layout.activity_main); | |
final TextView textView = (TextView) findViewById(R.id.text_view); | |
Button button = (Button) findViewById(R.id.increment_button); | |
button.setOnClickListener(new View.OnClickListener() { | |
@Override | |
public void onClick(View v) { | |
persistedCount++; | |
textView.setText("Button clicked " + persistedCount + " times"); | |
} | |
}); | |
textView.setText("Button clicked " + persistedCount + " times"); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.fbalashov.persistableannotations; | |
import android.os.Bundle; | |
import android.view.View; | |
import android.widget.Button; | |
import android.widget.TextView; | |
public class MainActivity extends BaseActivity { | |
@Persistable private int persistedCount = 0; | |
@Override | |
public void onCreate(Bundle savedInstanceState) { | |
super.onCreate(savedInstanceState); | |
setContentView(R.layout.activity_main); | |
final TextView textView = (TextView) findViewById(R.id.text_view); | |
Button button = (Button) findViewById(R.id.increment_button); | |
button.setOnClickListener(new View.OnClickListener() { | |
@Override | |
public void onClick(View v) { | |
persistedCount++; | |
textView.setText("Button clicked " + persistedCount + " times"); | |
} | |
}); | |
textView.setText("Button clicked " + persistedCount + " times"); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@Override | |
public Object onRetainCustomNonConfigurationInstance() { | |
Map<String, Object> objectsToPersist = new HashMap<>(); | |
// get all fields with the Persistable annotation | |
Field[] fields = this.getClass().getDeclaredFields(); | |
for (Field field : fields) { | |
if (field.isAnnotationPresent(Persistable.class)) { | |
// for each field, make the field accessible (in case it's private) and then write its value into the map | |
field.setAccessible(true); | |
try { | |
objectsToPersist.put(field.getName(), field.get(this)); | |
} catch (IllegalAccessException e) { | |
e.printStackTrace(); | |
} | |
} | |
} | |
return objectsToPersist; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@Override | |
public final Object onRetainCustomNonConfigurationInstance() { | |
Map<String, Object> objectsToPersist = new HashMap<>(); | |
// get all fields with the Persistable annotation | |
List<Field> annotatedFields = getAllFieldsWithAnnotation(new ArrayList<Field>(), Persistable.class, this.getClass(), BaseActivity.class); | |
for (Field field : annotatedFields) { | |
// for each field, make the field accessible (in case it's private) and then write its value into the map | |
field.setAccessible(true); | |
try { | |
objectsToPersist.put(field.getName(), field.get(this)); | |
} catch (IllegalAccessException e) { | |
e.printStackTrace(); | |
} | |
} | |
return objectsToPersist; | |
} | |
/** | |
* Finds all the fields with the given annotation (public and private0 in the given class. Recursively repeats | |
* this for super classes until reaching the given endClass. | |
* @param annotatedFields an empty list that will be populated with any fields that match the annotationClazz | |
* @param annotationClass the annotation to look for | |
* @param startClazz the starting subclass to look for fields in | |
* @param endClazz the super class at which to stop looking for fields | |
* @return all fields with the given annotation | |
*/ | |
private List<Field> getAllFieldsWithAnnotation(List<Field> annotatedFields, Class<Persistable> annotationClass, Class startClazz, Class<BaseActivity> endClazz) { | |
Field[] fields = startClazz.getDeclaredFields(); | |
for (Field field : fields) { | |
if(field.isAnnotationPresent(annotationClass)) { | |
annotatedFields.add(field); | |
} | |
} | |
if (endClazz.equals(startClazz)) { | |
return annotatedFields; | |
} | |
return getAllFieldsWithAnnotation(annotatedFields, annotationClass, startClazz.getSuperclass(), endClazz); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@Override | |
public void onCreate(Bundle savedInstanceState) { | |
super.onCreate(savedInstanceState); | |
// Right after super.onCreate we get the retained instance state and reinitiate any persisted fields. | |
if (getLastCustomNonConfigurationInstance() instanceof Map) { | |
List<Field> annotatedFields = getAllFieldsWithAnnotation(new ArrayList<Field>(), Persistable.class, this.getClass(), BaseActivity.class); | |
for (Field field : annotatedFields) { | |
// for each field, make the field accessible (in case it's private) and then set it's value based on the value in the map | |
field.setAccessible(true); | |
try { | |
field.set(this, ((Map<String, Object>) getLastCustomNonConfigurationInstance()).get(field.getName())); | |
} catch (IllegalAccessException e) { | |
e.printStackTrace(); | |
} | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@Override | |
public void onCreate(Bundle savedInstanceState) { | |
super.onCreate(savedInstanceState); | |
// Right after super.onCreate we get the retained instance state and reinitiate any persisted fields. | |
if (getLastCustomNonConfigurationInstance() instanceof Map) { | |
reinitializePersistedFields(((Map<String, Object>) getLastCustomNonConfigurationInstance())); | |
} | |
} | |
/** | |
* Reinitializes any fields that have the Persistable annotation after state change | |
*/ | |
private void reinitializePersistedFields(Map<String, Object> persistedObjects) { | |
// get all fields with the Persistable annotation | |
List<Field> annotatedFields = getAllFieldsWithAnnotation(new ArrayList<Field>(), Persistable.class, this.getClass(), BaseActivity.class); | |
for (Field field : annotatedFields) { | |
// for each field, make the field accessible (in case it's private) and then set it's value based on the value in the map | |
field.setAccessible(true); | |
try { | |
field.set(this, persistedObjects.get(field.getName())); | |
} catch (IllegalAccessException e) { | |
e.printStackTrace(); | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Any field marked with this annotation will be persisted on state changes. | |
*/ | |
@Retention(RetentionPolicy.RUNTIME) | |
@Target(ElementType.FIELD) | |
protected @interface Persistable{} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment