Skip to content

Commit 99c75d5

Browse files
author
xiaoqi
committed
update sample
1 parent a733de8 commit 99c75d5

13 files changed

Lines changed: 297 additions & 57 deletions

File tree

.idea/misc.xml

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

README.md

Lines changed: 210 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,217 @@
1-
# AutoSave
2-
A framework can automatically generate OnSaveInstanceState code
1+
[![license](https://img.shields.io/badge/license-Apache2.0-brightgreen.svg?style=flat)](https://github.com/didi/VirtualAPK/blob/master/LICENSE)
2+
[![Release Version](https://img.shields.io/badge/release-1.0.0-red.svg)](https://bintray.com/noober/maven/AutoSaver)
3+
# 引入
34

4-
使用方法介绍 :http://blog.csdn.net/qq_25412055/article/details/54355935
5-
##how to use:
6-
   
5+
android 内存被回收是一个开发者的常见问题。当我们**跳转到一个二级界面,或者切换到后台**的时候,如果时间过长或者手机的**内存不足**,当我们再返回这个界面的时候,activity或fragment就会被内存回收。这时候虽然界面被重新执行了onCreate,但是很多变量的值却已经被置空,这样就导致了很多潜在的bug,已经很多空指针的问题。
6+
7+
其实这种问题需要解决的话也很简单。大家知道,当Activity或者Fragment被内存回收后,我们再进入这个界面,它会自动重新进行onCreate操作,并且系统会帮助我们保存一些值。但是系统只会保存界面上的一些元素,比如textview中的文字,但是很多全局变量仍然会被置空。
8+
对于保存这些变量,我们可以重写**onSaveInstanceState**这个方法,在onCreate中即可恢复数据。代码如下:
9+
|
710

8-
project gradle:
9-
dependencies {
10-
classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'
11-
....
12-
}
11+
public int a;
12+
@Override
13+
protected void onCreate(Bundle savedInstanceState) {
14+
super.onCreate(savedInstanceState);
15+
setContentView(R.layout.activity_main);
16+
initData();
17+
//内存回收,界面重新onCreate后,恢复数据
18+
if(savedInstanceState != null){
19+
a = savedInstanceState.getInt("A");
20+
}
21+
}
22+
23+
private void initData() {
24+
...
25+
}
26+
27+
@Override
28+
protected void onSaveInstanceState(Bundle outState) {
29+
//保存数据
30+
outState.putInt("A", a);
31+
super.onSaveInstanceState(outState);
32+
}
33+
34+
通过这样的操作,便可以解决内存回收后变量a的值变为初始值0的问题。
35+
36+
问题到这里,似乎已经可以解决内存被回收的问题了。但是随着项目的开发,一个Activity中的变量以及**代码会变得非常多**,这时候我们需要去保存某个值就会使代码变得越来越凌乱,同时不断重复的去写outState.putXX已经savedInstanceState.getXX这样的代码都是很重复的,一不小心还会去写错中间的key值。
37+
38+
于是我写了这个很轻量级的框架,来解决这个问题。先给出引入这个框架后的代码写法:
39+
40+
@NeedSave
41+
public String test;
42+
@NeedSave
43+
private boolean b;
44+
@NeedSave
45+
public Boolean c;
46+
@NeedSave
47+
public ArrayList<String> t;
48+
@NeedSave
49+
public Integer i;
50+
@NeedSave(isParcelable = true)
51+
public ParcelableObject example;
52+
@NeedSave
53+
public SerializableObject example;
54+
@NeedSave
55+
public Float f1;
56+
@NeedSave
57+
public float f2;
58+
@NeedSave
59+
public char achar;
60+
@NeedSave
61+
public char achars[];
62+
@NeedSave
63+
public int sssss[];
64+
@NeedSave
65+
public Bundle bundle;
66+
@NeedSave
67+
public int a;
68+
69+
@Override
70+
protected void onCreate(Bundle savedInstanceState) {
71+
super.onCreate(savedInstanceState);
72+
setContentView(R.layout.activity_main);
73+
initData();
74+
SaveHelper.bind(this,savedInstanceState);
75+
}
76+
77+
private void initData() {
78+
//TODO
79+
}
80+
81+
@Override
82+
protected void onSaveInstanceState(Bundle outState) {
83+
SaveHelper.save(this,outState);
84+
super.onSaveInstanceState(outState);
85+
}
86+
87+
这里我特地写了很多的变量,但是无论这个Activity中有多少变量,我在onCreate和onSaveInstanceState代码中都只要去各写一行代码,同时给变量加一个标签标记一个即可:
88+
89+
@NeedSave
90+
SaveHelper.bind(this,savedInstanceState);
91+
SaveHelper.save(this,outState);
1392

14-
app gradle:
15-
apply plugin: 'android-apt'
93+
这样就不会因为这种太多的重复的操作去导致代码逻辑的混乱,同时也避免了敲代码时因为key写错导致的错误。
94+
95+
# 效果展示
96+
我们来看一下测试代码:
97+
## 不进行数据保存操作
98+
99+
![](https://user-gold-cdn.xitu.io/2017/12/14/16053bf7ed7fb8f7?w=744&h=621&f=png&s=71616)
100+
很简单,就是通过点击事情,去给变量“testString”赋值,然后再去模拟内存被回收的情况,看一下显示的值是否是内存被回收前的。
101+
102+
![](https://user-gold-cdn.xitu.io/2017/12/14/16053ce960cd9ee3?w=416&h=585&f=gif&s=522365)
103+
104+
## 调用框架代码后的内存恢复
105+
加入框架代码:
106+
107+
![](https://user-gold-cdn.xitu.io/2017/12/14/16053c324e7de04c?w=696&h=787&f=png&s=95432)
108+
109+
加入代码之后的效果:
110+
111+
112+
![](https://user-gold-cdn.xitu.io/2017/12/14/16053cf18fe46d78?w=418&h=605&f=gif&s=450838)
113+
114+
115+
116+
117+
118+
# 原理介绍
119+
120+
## @NeedSave
121+
122+
这是一个注解,这个注解只能使用在全局变量中,特别注意,被加上这个注解的变量必须是**public**,否则会不生效。
123+
当前支持保存的类型有:
124+
125+
String
126+
boolean Boolean
127+
ArrayList
128+
int int[] Integer
129+
Parcelable
130+
Serializable
131+
float Float
132+
char[] char
133+
Bundle
134+
135+
注意,如果是Parcelable类型,需要特别在注解中加入 @NeedSave(isParcelable = true) 这样标记
136+
## SaveHelper.bind(this,savedInstanceState);
137+
这个方法其实是恢复数据的时候去调用的。
138+
139+
public static <T> void bind(T recover, Bundle savedInstanceState){
140+
if(savedInstanceState != null){
141+
ISaveInstanceStateHelper<T> saveInstanceStateHelper = findSaveHelper(recover);
142+
if(saveInstanceStateHelper != null){
143+
saveInstanceStateHelper.recover(savedInstanceState, recover);
144+
}
145+
}
146+
}
147+
148+
savedInstanceState不会null的时候,说明就是需要内存恢复的时候,这时候就会去通过findSaveHelper方法找到一个实现类,然后去调用recover方法恢复数据。
149+
## SaveHelper.save(this,outState);
150+
这是一个保存数据的方法,**注意**的是,这个方法必须在super.onSaveInstanceState(outState);之前调用。
151+
152+
public static <T> void save(T save, Bundle outState){
153+
ISaveInstanceStateHelper<T> saveInstanceStateHelper = findSaveHelper(save);
154+
if(saveInstanceStateHelper != null){
155+
saveInstanceStateHelper.save(outState, save);
156+
}
157+
}
158+
159+
它最终调用的是ISaveInstanceStateHelper实现类的save方法。
160+
161+
## ISaveInstanceStateHelper实现类
162+
这个类是一个接口,专门用来保存和恢复数据用。这个类是不要我们自己写的,在代码编译的时候会**自动生成**模板代码。整个调用过程中也只有寻找ISaveInstanceStateHelper实现类的findSaveHelper这个方法调用了反射,其他时候不会去用到反射,而影响效率。
163+
自动生成代码所在位置:
164+
165+
![](https://user-gold-cdn.xitu.io/2017/12/9/1603a6d7496e99bf?w=465&h=275&f=png&s=15537)
166+
167+
自动生成的代码如下:
168+
169+
public class MainActivity_SaveStateHelper implements ISaveInstanceStateHelper<MainActivity> {
170+
@Override
171+
public void save(Bundle outState, MainActivity save) {
172+
outState.putString("TEST",save.test);
173+
outState.putBoolean("C",save.c);
174+
outState.putSerializable("T",save.t);
175+
outState.putInt("I",save.i);
176+
outState.putParcelable("EXAMPLE",save.example);
177+
outState.putFloat("F1",save.f1);
178+
outState.putFloat("F2",save.f2);
179+
outState.putChar("ACHAR",save.achar);
180+
outState.putCharArray("ACHARS",save.achars);
181+
outState.putIntArray("SSSSS",save.sssss);
182+
outState.putIntArray("SASA",save.sasa);
183+
outState.putBundle("BUNDLE",save.bundle);
184+
outState.putInt("A",save.a);
185+
}
16186

17-
repositories {
18-
maven {
19-
url 'https://dl.bintray.com/xqandroid/maven/'
187+
@Override
188+
public void recover(Bundle savedInstanceState, MainActivity recover) {
189+
if(savedInstanceState != null) {
190+
recover.test = savedInstanceState.getString("TEST");
191+
recover.c = savedInstanceState.getBoolean("C");
192+
recover.t = (ArrayList<String>)savedInstanceState.getSerializable("T");
193+
recover.i = savedInstanceState.getInt("I");
194+
recover.example = savedInstanceState.getParcelable("EXAMPLE");
195+
recover.f1 = savedInstanceState.getFloat("F1");
196+
recover.f2 = savedInstanceState.getFloat("F2");
197+
recover.achar = savedInstanceState.getChar("ACHAR");
198+
recover.achars = savedInstanceState.getCharArray("ACHARS");
199+
recover.sssss = savedInstanceState.getIntArray("SSSSS");
200+
recover.sasa = savedInstanceState.getIntArray("SASA");
201+
recover.bundle = savedInstanceState.getBundle("BUNDLE");
202+
recover.a = savedInstanceState.getInt("A");
20203
}
204+
}
21205
}
22206

23-
dependencies {
24-
compile 'com.xiaoqi:xqauto-api:1.1.1'
25-
apt 'com.xiaoqi:xqauto-processor:1.1.1'
26-
compile 'com.xiaoqi:xqauto-savehelper:1.1.1'
27-
}
207+
# 总结
208+
看到这里大家已经猜到其实这个框架的实现原理和BufferKnife是相同的。而bufferknife的原理很多文章都有,这里就不过多介绍了。
209+
210+
github地址:[https://github.com/JavaNoober/AutoSave](https://github.com/JavaNoober/AutoSave)
211+
212+
引入方式,在app的gradle中加入下面依赖即可:
213+
214+
compile 'com.noober:savehelper:1.0.0'
215+
compile 'com.noober:savehelper-api:1.0.0'
216+
annotationProcessor 'com.noober:processor:1.0.0'
217+

build.gradle

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,9 @@ task clean(type: Delete) {
3333
//添加
3434
ext {
3535
userOrg = 'noober'
36-
groupId = 'com.noober.savehelper'
36+
groupId = 'com.noober'
3737
uploadName = 'AutoSaver'
38-
publishVersion = '1.0.1'
38+
publishVersion = '1.0.0'
3939
desc = "A light weight framework can automatically generate 'OnSaveInstanceState' code"
4040
website = 'https://github.com/JavaNoober/AutoSave'
4141
// gradlew clean build bintrayUpload -PbintrayUser=xiaoqiandroid -PbintrayKey=xxxxxxxxxxxxxxxx -PdryRun=false

sample/build.gradle

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
apply plugin: 'com.android.library'
1+
apply plugin: 'com.android.application'
22

33
android {
44
compileSdkVersion 26
@@ -23,12 +23,14 @@ android {
2323

2424

2525
dependencies {
26+
implementation 'com.android.support.constraint:constraint-layout:1.0.2'
2627
compile fileTree(include: ['*.jar'], dir: 'libs')
2728
androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
2829
exclude group: 'com.android.support', module: 'support-annotations'
2930
})
3031
implementation 'com.android.support:appcompat-v7:+'
3132
testImplementation 'junit:junit:4.12'
32-
annotationProcessor 'com.noober.savehelper:processor:1.0.1'
33-
implementation 'com.noober.savehelper:savehelper:1.0.1'
33+
implementation 'com.noober:savehelper:1.0.0'
34+
annotationProcessor 'com.noober:processor:1.0.0'
35+
implementation 'com.noober:savehelper-api:1.0.0'
3436
}

sample/src/main/AndroidManifest.xml

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,16 @@
55
<application
66
android:allowBackup="true"
77
android:label="@string/app_name"
8+
android:theme="@style/Theme.AppCompat.NoActionBar"
89
android:supportsRtl="true">
9-
<activity android:name="com.recover.autosavesample.MainActivity">
10+
<activity android:name=".SampleActivity">
11+
</activity>
12+
<activity android:name=".TestActivity">
13+
<intent-filter>
14+
<action android:name="android.intent.action.MAIN"/>
15+
16+
<category android:name="android.intent.category.LAUNCHER"/>
17+
</intent-filter>
1018
</activity>
1119
</application>
1220

sample/src/main/java/com/recover/autosavesample/BaseFragment.java

Lines changed: 0 additions & 25 deletions
This file was deleted.

sample/src/main/java/com/recover/autosavesample/MainActivity.java renamed to sample/src/main/java/com/recover/autosavesample/SampleActivity.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99

1010
import java.util.ArrayList;
1111

12-
public class MainActivity extends AppCompatActivity {
12+
public class SampleActivity extends AppCompatActivity {
1313

1414
@NeedSave
1515
public String test;

sample/src/main/java/com/recover/autosavesample/MainFragment.java renamed to sample/src/main/java/com/recover/autosavesample/SampleFragment.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import android.os.Bundle;
44
import android.support.annotation.Nullable;
5+
import android.support.v4.app.Fragment;
56
import android.view.LayoutInflater;
67
import android.view.View;
78
import android.view.ViewGroup;
@@ -12,7 +13,7 @@
1213

1314
import java.util.ArrayList;
1415

15-
public class MainFragment extends BaseFragment {
16+
public class SampleFragment extends Fragment {
1617
@NeedSave
1718
public int a;
1819
@NeedSave
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
package com.recover.autosavesample;
2+
3+
import android.support.v7.app.AppCompatActivity;
4+
import android.os.Bundle;
5+
import android.view.View;
6+
import android.widget.Button;
7+
import android.widget.TextView;
8+
9+
import com.noober.api.NeedSave;
10+
import com.noober.savehelper.SaveHelper;
11+
12+
public class TestActivity extends AppCompatActivity {
13+
14+
private TextView textView;
15+
private Button button;
16+
private final static String testContent = "This is a test code:";
17+
18+
@NeedSave
19+
public String testString = "11111111";
20+
@Override
21+
protected void onCreate(Bundle savedInstanceState) {
22+
super.onCreate(savedInstanceState);
23+
setContentView(R.layout.activity_test);
24+
SaveHelper.bind(this, savedInstanceState);
25+
textView = findViewById(R.id.tv_content);
26+
button = findViewById(R.id.button);
27+
textView.setText(testContent + testString);
28+
button.setOnClickListener(new View.OnClickListener() {
29+
@Override
30+
public void onClick(View v) {
31+
testString = "222222222";
32+
textView.setText(testContent + testString);
33+
}
34+
});
35+
}
36+
37+
@Override
38+
protected void onSaveInstanceState(Bundle outState) {
39+
SaveHelper.save(this, outState);
40+
super.onSaveInstanceState(outState);
41+
}
42+
}

0 commit comments

Comments
 (0)