上周做比分更新的时候,老是遭遇leakcanary在AIDL数据回调接口中报内存泄漏,看着好心烦

既然是内存泄漏,就补补Java内存管理的基础知识

Java的内存管理就是对对象的创建和释放,一般创建我们就这直接new, 由Java的垃圾回收器负责回收无用对象占据的内存资源

垃圾回收的机制

引用计数

引用计数是一种简单但速度很慢的垃圾回收技术,对每个对象都含有一个引用计数,当有引用连接到对象时,引用计数加1。当引用离开作用域或被置为null时,引用计数-1。垃圾回收器会检测程序所有对象的引用计数的变化,当引用计数为0时,证明该对象没有被引用,这时候垃圾回收器回收对象占据的内存资源,将不连续的内存空间,整理成连续的内存空间,但是引用计数不能解决循环引用,所以这种方式只是用于说明垃圾回收器的机制
(ps:还有好多技术)
http://www.importnew.com/1993.html

###

内部类

非静态类内部会默认引用外部类,所以非handler如果是非静态内部就引用外部的context造成内部内存泄漏。

四种引用方式

强引用:如果一个对象具有强引用,那就 类似于必不可少的生活用品,垃圾回收器绝不会回收它。当内存空 间不足,Java虚拟机宁愿抛出OutOfMemoryError错误,使程序异常终止,也不会靠随意回收具有强引用的对象来解决内存不足问题。
软引用:如果一个对象具有软引用,内存空间足够,垃圾回收器就不会回收它;
弱引用:弱引用也是用来描述非必需对象的,当JVM进行垃圾回收时,无论内存是否充足,都会回收被弱引用关联的对象。
虚引用:如果一个对象与虚引用关联,则跟没有引用与之关联一样,在任何时候都可能被垃圾回收器回收。
可以看四种应用方式被回收的概率从无到大。

我的解决方式

有很多种UI模板Fragment定义一个抽象类,在抽象类中绑定服务,解除绑定,子类实现更新UI操作
创建一个继承Handler的静态内部类,静态SoftReference,静态UiUpdateHandler
这样保证与外部没有直接引用关系

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
public abstract class ScoreFragment extends Fragment {

protected ICategoryUpdate mCategoryUpdate;
protected static SoftReference<ScoreFragment> mReference;
protected static UiUpdateHandler mUpdateUI;
protected int refreshTime = 5000;
protected ScoreGame mScoreGame;

protected boolean isNoScore;
protected Context mContext;

protected String shareXML;

protected static final String SCORE_GAME = "SCORE_GAME";
protected static final String CATEGORY_NEED = "CATEGORY_NEED";

/*************************************生命周期的方法********************************/
@Override
public void onAttach(Context context) {
super.onAttach(context);
mContext = context;
isNoScore = SharedPrefsUtil.getValue(mContext, APIConstant.SHOW_SCORE, false);
shareXML = SharedPrefsUtil.getValue(mContext, APIConstant.HOME_SHARE,
APIConstant.HOME_SHARE, null);
}

@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getArguments() != null) {
mScoreGame = getArguments().getParcelable(SCORE_GAME);
if (shareXML != null){
HomePage homePage = GsonInstance.getGsonInstance().fromJson(shareXML, HomePage.class);
List<HomeCate> item = homePage.getCate().getItem();
for (HomeCate homeCate : item) {
if (homeCate.getCateid().equals(mScoreGame.getGame().getCateid())){
refreshTime = homeCate.getRefreshtime2() * 1000;
break;
}
}
}
mReference = new SoftReference<>((ScoreFragment) this);
mUpdateUI = new UiUpdateHandler(mReference, mScoreGame.getGame().getId()+"");
}
}


/**
* 绑定服务
*/
@Override
public void onResume() {
super.onResume();
bindToService();
}

/**
* 解除绑定
*/

@Override
public void onPause() {
super.onPause();
try {
if (mCategoryUpdate != null) {
if (mCategoryUpdate.asBinder().isBinderAlive()) {
getActivity().unbindService(mConnection);
}
}

} catch (Exception e) {
e.printStackTrace();
}
}


/*************************************生命周期的方法********************************/
/**
* 更新头部比分
* @param byId
*/
public abstract void updateScore(CategoryUpdateList.ListBean byId);

/**
* 更新小比分
* @param scoreDetail
* @param score2
*/
public abstract void resetAll(CategoryUpdateList.ListBean.ScoreDetailBean scoreDetail, String score2);

/**
* 更新比分的handler
*/
protected static class UiUpdateHandler extends Handler {
private SoftReference<ScoreFragment> mFragmentReference;

private String mLiveId;
UiUpdateHandler(SoftReference<ScoreFragment> fragmentReference, String cateId) {
mFragmentReference = fragmentReference;
mLiveId = cateId;
}
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
if (msg.what == 0x1000){
ScoreFragment fragment = mFragmentReference.get();
CategoryUpdateList list = msg.getData().getParcelable("Update");
if (fragment != null && list != null&& list.getList() != null && list.getList().size() > 0) {
CategoryUpdateList.ListBean byId = fragment.findById(list.getList(),
mLiveId);
DebugLogger.soutString(mLiveId);
fragment.updateScore(byId);
DebugLogger.soutString(fragment.toString());
if (byId!=null)
fragment.resetAll(byId.getScoreDetail(), byId.getScore2());
}
}
}
}

protected static IDataCallback.Stub mCallback = new IDataCallback.Stub() {
@Override
public void onSuccess(CategoryUpdateList list) throws RemoteException {
Message message = Message.obtain();
message.what = 0x1000;
Bundle bundle = new Bundle();
bundle.putParcelable("Update", list);
message.setData(bundle);
mUpdateUI.sendMessage(message);
}

@Override
public void onFailed(String msg) throws RemoteException {

}
};

/**
* 连接服务端
*/
protected ServiceConnection mConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
mCategoryUpdate = ICategoryUpdate.Stub.asInterface(service);
try {
mCategoryUpdate.start();
mCategoryUpdate.setCallback(mCallback);

} catch (RemoteException e) {
e.printStackTrace();
}
}

@Override
public void onServiceDisconnected(ComponentName name) {
try {
mCategoryUpdate.clearCallback(mCallback);
} catch (RemoteException e) {
e.printStackTrace();
}
}
};


/**
* 在指定的类别找到需要更新的id
* @param list
* @param id
* @return
*/
public CategoryUpdateList.ListBean findById(List<CategoryUpdateList.ListBean> list ,String id){
for (int i = 0; i < list.size(); i++) {
if (list.get(i).getLiveid().equals(id)){
return list.get(i);
}
}
return null;
}

/**
* 绑定服务的方法
*/
private void bindToService() {
Intent intent = new Intent(getActivity(), CategoryUpdateService.class);
CategoryServiceNeed need = new CategoryServiceNeed();
need.setRefreashTime(refreshTime);
need.setCateId(mScoreGame.getGame().getCateid());
intent.putExtra(CATEGORY_NEED, need);
getActivity().bindService(intent, mConnection, Activity.BIND_AUTO_CREATE);
}
@Override
public void onDestroy() {
super.onDestroy();
mCategoryUpdate = null;
}
}

为什么使用软引用

因为我需要长期持有这个引用类,而不希望随时都可以回收,只有在内存不足的时候将其回收,所以采用了软引用,之前采用的弱引用,大概更新两三次过后,弱引用就被回收,UI无法更新,所以采用软引用的方式