内存泄漏
1.类的静态变量持有大数据对象 静态变量长期维持到大数据对象的引用,阻止垃圾回收。还有一些静态的Activity,静态的View
2.非静态内部类存在静态实例 非静态内部类会维持一个到外部类实例的引用,如果非静态内部类的实例是静态的,就会间接长期维持着外部类的引用,阻止被回收掉。
3.对于使用了BraodcastReceiver,ContentObserver,File,Cursor,Stream,Bitmap等资源的使用,应该在Activity销毁时及时关闭或者注销,否则这些资源将不会被回收,造成内存泄漏。 解决办法使用try catch Finally 里面关闭它,或者用带资源的try()将资源初始化写在括号里面。,不过据了解现在Bitmap不用手动调用recycle,垃圾回收器会自动回收,因为手动调用的话很可能会造成其他地方调用了被回收Bitmap,非要手动的话用引用计数法
4.Handler内存泄漏 Handler作为内部类存在于Activity中,但是Handler生命周期与Activity生命周期往往并不是相同的,比如当Handler对象有Message在排队,则无法释放,进而导致本该释放的Acitivity也没有办法进行回收。 解决办法:声明handler为static类,这样内部类就不再持有外部类的引用了,就不会阻塞Activity的释放 ,如果内部类实在需要用到外部类的对象,可在其内部声明一个弱引用引用外部类。
public class MainActivity extends Activity {
private CustomHandler mHandler;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mHandler = new CustomHandler(this);
}
static class CustomHandlerextends Handler {
// 内部声明一个弱引用,引用外部类
private WeakReference<MainActivity > activityWeakReference;
public MyHandler(MyActivity activity) {
activityWeakReference= new WeakReference<MainActivity >(activity);
}
// ... ...
}
5.不要在onDraw里面或者onMeasure创建对象,这样会造成频繁GC
6.单例模式造成的内存泄漏
public class AppManager {
private static AppManager instance;
private Context context;
private AppManager(Context context) {
this.context = context;
//应该改成
this.context = context.getApplicationContext();
}
public static AppManager getInstance(Context context) {
if (instance != null) {
instance = new AppManager(context);
}
return instance;
}
}
由于生命周期不一样,如果传进来的是Activity的Context,会造成Activity无法回收造成内存泄漏,解决办法就是用Application的Context
7.线程造成内存泄漏
new AsyncTask<Void, Void, Void>() {
@Override
protected Void doInBackground(Void... params) {
SystemClock.sleep(10000);
return null;
}
}.execute();
new Thread(new Runnable() {
@Override
public void run() {
SystemClock.sleep(10000);
}
}).start();
上面两种情况都会造成内存泄漏,因为匿名内部类都是默认持有外部引用的,如果再Activity关闭时线程工作还没有做完,将可能造成内存泄漏,和之前handler其实属于差不多算是同类问题,也是使用静态内部类+弱引用来解决
static class MyAsyncTask extends AsyncTask<Void, Void, Void> {
private WeakReference<Context> weakReference;
public MyAsyncTask(Context context) {
weakReference = new WeakReference<>(context);
}
@Override
protected Void doInBackground(Void... params) {
SystemClock.sleep(10000);
return null;
}
@Override
protected void onPostExecute(Void aVoid) {
super.onPostExecute(aVoid);
MainActivity activity = (MainActivity) weakReference.get();
if (activity != null) {
//...
}
}
}
static class MyRunnable implements Runnable{
@Override
public void run() {
SystemClock.sleep(10000);
}
}
new Thread(new MyRunnable()).start();
new MyAsyncTask(this).execute();
总结:只要是匿名内部类都会持有外部引用,这时候就要考虑是否会造成内存泄漏了
常见工作线程方式
1直接单个线程
public class MyRunnable implements Runnable {
@Override
public void run() {
//耗时操作
}
public void startThread() {
MyRunnable myRunnable = new MyRunnable();
Thread thread = new Thread(myRunnable);
thread.start();
}
}
2.线程池
常见有四种线程池
Executors.newFixedThreadPool(3);//固定大小线程池
Executors.newCachedThreadPool();//可变大小线程池
Executors.newSingleThreadExecutor();//串行线程池
Executors.newScheduledThreadPool(int corePoolSize)//定期循环执行任务线程池
当然也可以定义线程池
public class SimpleExecutor implements Executor {
@Override
public void execute(Runnable command) {
new Thread(command).start();
}
}
3.HandlerThread是一个集成了Looper和MessageQueue的线程,当启动HandlerThread时,会同时生成Looper和MessageQueue,然后等待消息进行处理.常见用法
public class ThreadDemo extends Activity {
private static final String TAG = "bb";
private int count = 0;
private Handler mHandler ;
private Runnable mRunnable = new Runnable() {
public void run() {
//为了方便 查看,我们用Log打印出来
Log.e(TAG, Thread.currentThread().getId() + " " +count);
count++;
// setTitle("" +count);
//每2秒执行一次
mHandler.postDelayed(mRunnable, 2000);
}
};
@Override
public void onCreate(Bundle savedInstanceState) {
Log.e(TAG, "Main id "+Thread.currentThread().getId() + " " +count);
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
//通过Handler启动线程
HandlerThread handlerThread = new HandlerThread("threadone");//创建一个handlerThread线程
handlerThread.start();//启动该线程
mHandler = new Handler(handlerThread.getLooper());//设计handler的looper
mHandler.post(mRunnable); //加入mRunnable线程体到子线程的消息队列
}
@Override
protected void onDestroy() {
//将线程与当前handler解除
mHandler.removeCallbacks(mRunnable);
super.onDestroy();
}
}
- AsyncQueryHandler是用于在ContentProvider上面执行异步的CRUD操作的工具类,CRUD操作会被放到一个单独的子线程中执行,当操作结束获取到结果后,将通过消息的方式传递给调用AsyncQueryHandler的线程,通常就是主线程。AsyncQueryHandler是一个抽象类,集成自Handler,通过封装ContentResolver、HandlerThread、AsyncQueryHandler等实现对ContentProvider的异步操作。
最简单的demo
AsyncQueryHandler asyncQueryHandler = new AsyncQueryHandler(activity.getContentResolver()){
@Override
protected void onInsertComplete(int token, Object cookie, Uri uri) {
super.onInsertComplete(token, cookie, uri);
Log.d(TAG, "onInsertComplete return uri: " + uri);
}
};
asyncQueryHandler.startInsert(-1, null, mUri, values);
查询,更新也是一样的,第一个参数为识别码,只要对应的在OnXXXXCompelete方法里面对应switch就可以了
- IntentService具有Service一样的生命周期,同时也提供了在后台线程中处理异步任务的机制
继承OnHandleIntent方法,通过intent来携带数据
ublic class SimpleIntentService extends IntentService {
public SimpleIntentService() {
super(SimpleIntentService.class.getName());
setIntentRedelivery(true);
}
@Override
protected void onHandleIntent(Intent intent) {
//该方法在后台调用,这里可以拿到intent所携带的数据
}
}
- AsyncTask是在Executor框架基础上进行的封装,官方文档说这个不适合长时间的操作,简单用法如下
public class FullTask extends AsyncTask<String,String,String> {
@Override
protected void onPreExecute() {
super.onPreExecute();
//主线程执行
}
@Override
protected String doInBackground(String... params) {
return null;
//子线程执行
}
@Override
protected void onProgressUpdate(String... values) {
super.onProgressUpdate(values);
//主线程执行
}
@Override
protected void onPostExecute(String s) {
super.onPostExecute(s);
//主线程执行
}
@Override
protected void onCancelled() {
super.onCancelled();
//主线程执行
}
}
- Loader是Android3.0开始引入的一个异步数据加载框架
官方文档详见:Loader官方文档
区别:
切换回主线程方法##
EventBus,runOnUithread()
主要参考链接