1.将大多数的context使用你的application替代
public class MyApplication extends Application{
private static MyApplication app;
@Override
public void onCreate() {
super.onCreate();
app = this;
}
public static MyApplication getSuperContext(){
return
这样,绝大多数的context都可以不用了,直接写MyApplication.getSuperContext()代替,这里提几个不能代替的点:dialog里面的new AlertDialog.Builder(context)是不可以用这个代替的,一定要用activity的,还有就是LayoutInflater.inflate(context),这个也不能用MyApplication.getSuperContext(),不然没用。
2.使用全局变量时,注意序列化保存
这个全局变量注意不要用的太多,不然整个代码的结构不大好,不过对于大多数应用而言,都需要登录,很多地方需要传入用户数据,对于这些地方,可以使用一个全局的静态变量来保存,但注意要序列化之后保存在本地,不然用户数据就是明文方式保存了,安全性太低。
以下内容摘自:《App研发录:架构设计、Crash分析和竞品技术分析》,内容可能略有改动:
public class UserData implements Serializable, Cloneable{
private static final long serialVersionUID = 1L;
private static UserData instance;
//禁止直接初始化,保证唯一对象,类似单例模式
private UserData(){}
public static UserData getIntance(){
//调用这句有两种情况1.首次安装2.内存有缓存
if(instance == null{
//双引号内放入的是存放地址
UserData userData = SerialUtil.restoreObject("存放地址");
//不为空则内容有缓存,为空则首次安装,注意控制该方法的时间
if(instance == null){
instance = new UserData();
SerialUtil.saveObject("存放地址",instance);
}
}
return instance;
}
private int userId;//模拟一下,就这两条了
private String userName;
public UserData setUserId(int userId){
this.userId = userId;
}
public int getUserId(){
return userId;
}
public UserData setUserName(String userName){
this.userName = userName;
}
public String getUserName(){
return userName;
}
//---序列化相关---
public UserData readResolve()
throws Object StreamException,ClineNotSupportedException{
instance = (UserData) this.clone();
return instance;
}
public void readObject(ObjectInputStream ois)
throws IOException, ClassNotFoundException{
ois.defaultReadObject();
}
public Object Clone() throws CloneNotSupportedEception{
return super.clone();
}
public void clear(){
user.setUserId(0);
user.setUserName("");
save();
}
public void save(){
SerialUtil.saveObject("地址",user);
}
}
public class SerialUtil{
public static final void saveObject(String path, Object saveObject){
FileOutputStream fos = null;
ObjectOutputStream oos = null;
File f = new File(path);
try{
fos = new FileOutputStream(f);
oos = new ObjectOutputStream(fos);
oos.writeObject(saveObject);
}catch(FileNotFoundException e){
e.printStackTrace();
}catch(IOException e){
e.printStackTrace();
}finally{
try{
if(oos != null) oos.close();
if(fos != null) fos.close();
}catch(IOException e){
e.printStackTrace();
}
}
}
public static final Object restoreObject(String path){
FileInputStream fis = null;
ObjectInputStream ois = null;
Object object = null;
File f = new File(path);
if(!f.exists()){
return null;
}
try{
fis = new FileInputStream(f);
ois = new ObjectInputStream(fis);
object = ois.readObject();
return object;
}catch(FileNotFoundExcepton e){
e.printStackTrace();
}catch(IOException e){
e.printStackTrace();
}catch(ClassNotFoundException e){
e.printStackTrace();
}finally{
try{
if(oos != null) oos.close();
if(fos != null) fos.close();
}catch(IOException e){
e.printStackTrace();
}
}
}
}
保存数据
UserData.getInstance()
.setUserId(100)
.setUserName("Hello Kitty")
.save();
获取数据
UserData data = UserData.getInstance();
int userId = data.getId();
String userName = data.getUserName();
注销/切换账号时重置数据:
UserData data = UserData.getInstance().clear();
3.使用Intent+onWindowFocusChanged(boolean)保存页面数据
通过测试得知,只要屏幕获得焦点或者失去焦点(类似onResume和onPause)就会调用onWindowFocusChanged。所以可以
@Override
public void onWindowFocusChanged(boolean hasFocus) {//可以
super.onWindowFocusChanged(hasFocus);
Log.e(TAG,"onWindowFocusChanged()"+getIntent()+num);
if(hasFocus) {
num = getIntent().getIntExtra("num", 0);
boolean isFirst = getIntent().getBooleanExtra("isFirst",true);
if(isFirst){
//一些数据初始化
num = 5;
getIntent().putExtra("isFirst",false);
}else//相当于onPause,可以进行数据保存
getIntent().putExtra("num",num);
}
而intent数据是不会被销毁的,home键,或者返回键,或者打开dialog都会调用这个方法哦,只不过要注意把首次初始化的部分用isFirst分开,isFirst需要另外添加。初始化的部分可以放在oncreate当中,将:
boolean isFirst = getIntent().getBooleanExtra("isFirst",true);
if(isFirst){
//一些数据初始化
num = 5;
getIntent().putExtra("isFirst",false);
}
这部分放在onCreate,可以防止onWindowFocusChanged过于臃肿,而且有些数据需要在初始化控件前拿到,所以放在onCreate中可能更优,我这里为了把代码写在一起,所以这样做。
4.做出类似网页cache的缓存,但要加上强制刷新
这里就写个思路:
a.本地单例保存在某Map中,key为数据编号,可以是请求的xx.api?a1 = v1&b1=v2…作为key但是后面的参数要按照a=b字典序排列,value为数据转换成的json,记录一下时间戳
b.开个service,定期清理这个Map,当当前时间-记录时间>预定时间(感觉5分钟左右是合理的)
c.像列表这种的有下拉刷新,下拉刷新时清除map相应内容,强制从网络加载数据
d.取数据时,现在cache里找,cache没有再下载数据
伪代码:
public void doSomething(String url,Callback callback, boolean
5.你可以考虑不使用fragment
fragment可以直接用xxlayout代替,
如果是底部标签,可以用viewpager,然后取出它的滚动属性:
/**
* 手动控制viewpager是否可以左右滑动
* 去除滑动动画
* setNoScroll(boolean noScroll)
*
* @author
public class NoScrollViewPager extends ViewPager
private boolean enableScroll = false;
public NoScrollViewPager(Context context, AttributeSet attrs) {
super(context, attrs);
// TODO Auto-generated constructor stub
init(attrs);
}
public NoScrollViewPager(Context context) {
super(context);
}
@Override
public void scrollTo(int x, int y) {
super.scrollTo(x, y);
}
@Override
public boolean onTouchEvent(MotionEvent arg0) {
/* return false;//super.onTouchEvent(arg0); */
return enableScroll && super.onTouchEvent(arg0);
}
@Override
public boolean onInterceptTouchEvent(MotionEvent arg0) {
return enableScroll && super.onInterceptTouchEvent(arg0);
}
@Override
public void setCurrentItem(int item, boolean smoothScroll) {
super.setCurrentItem(item, smoothScroll);
}
@Override
public void setCurrentItem(int item) {
//false 去除滚动效果
super.setCurrentItem(item,enableScroll);
}
public void init(AttributeSet attrs){
TypedArray t = getContext().obtainStyledAttributes(attrs, R.styleable.NoScrollViewPager);
enableScroll = t.getBoolean(R.styleable.NoScrollViewPager_canScroll, true);
}
}
这里我添加了一个canScroll属性,方便在布局文件中改变,如果需要滚动,在xml中改变这个属性就可以了。当然这条观点仅仅代表我个人。个人感觉fragment不太好用,不如自定义layout。当然如果做跨平台,比如同时要手机,眼镜,手表,电视,那么fragment或许会有好处,但这并不代表不能用非fragment。非fragment
另外,对于需要长期保存的对象,可以加磁盘缓存,磁盘缓存方面建议用数据库,Cipher或者Realm,因为这两个都有加密功能,直接明文保存是不太可取的。因为太长,所以不写了,这是最近半年的读书,身边大神教导,阅读源码,代码测试各种方式得到的宝贵经验,仅供参考。以后如果有一些好的方式,会继续更新。