美文网首页
关于安卓内存泄漏的归纳

关于安卓内存泄漏的归纳

作者: motosheep | 来源:发表于2020-05-14 15:10 被阅读0次

    1、单例对象Context的赋值

    传入的context需要getapplicationcontext,而不能是activity的context,因为单例的生命周期和Application的一样长 ,如果传入的context是activity的context,当activity的生命周期结束的时候,单例模式的对象还会一直持有,从而造成了单例模式的对象不可释放,从而造成内存的泄露。

    正确写法:

    public class AppManager {

        private static AppManager instance;

        private Context context;

        private AppManager(Context context) {

            this.context = context.getApplicationContext();

        }

        public static AppManager getInstance(Context context) {

            if (instance != null) {

                instance = new AppManager(context);

            }

            return instance;

        }

    }

    2、非静态内部类创建一个静态实例

         每次启动Activity时都会使用该单例的数据,这样虽然避免了资源的重复创建,不过这种写法却会造成内存泄漏,因为非静态内部类默认会持有外部类的引用,而又使用了该非静态内部类创建了一个静态的实例,该实例的生命周期和应用的一样长,这就导致了该静态实例一直会持有该Activity的引用,导致Activity的内存资源不能正常回收。正确的做法为:将该内部类设为静态内部类或将该内部类抽取出来封装成一个单例,如果需要使用Context,请使用ApplicationContext 。

    3、handler造成的内存泄露

    (软引用也可以解决)最终解决方法:

    public class MainActivity extends AppCompatActivity {

        private MyHandler mHandler = new MyHandler(this);

        private TextView mTextView ;

     private static class MyHandler extends Handler {

            private WeakReference<Context> reference;

            public MyHandler(Context context) {

                reference = new WeakReference<>(context);

            }

            @Override

            public void handleMessage(Message msg) {

                MainActivity activity = (MainActivity) reference.get();

                if(activity != null){

                    activity.mTextView.setText("");

                }

            }

        }

        @Override

        protected void onCreate(Bundle savedInstanceState) {

            super.onCreate(savedInstanceState);

            setContentView(R.layout.activity_main);

            mTextView = (TextView)findViewById(R.id.textview);

            loadData();

        }

        private void loadData() {

            //...request

            Message message = Message.obtain();

            mHandler.sendMessage(message);

        }

        @Override

        protected void onDestroy() {

            super.onDestroy();

     mHandler.removeCallbacksAndMessages(null);

        }

    }

    使用mHandler.removeCallbacksAndMessages(null);是移除消息队列中所有消息和所有的Runnable。当然也可以使用mHandler.removeCallbacks();或mHandler.removeMessages();来移除指定的Runnable和Message。

    4、线程造成的内存泄露

    正确的做法还是使用静态内部类的方式,如下:

         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();

    这样就避免了Activity的内存资源泄漏,当然在Activity销毁时候也应该取消相应的任务AsyncTask::cancel(),避免任务在后台执行浪费资源。

    五、资源未关闭造成的内存泄漏

         对于使用了BraodcastReceiver,ContentObserver,File,Cursor,Stream,Bitmap等资源的使用,应该在Activity销毁时及时关闭或者注销,否则这些资源将不会被回收,造成内存泄漏。

         以上就是android编程中,常见的5大内存泄漏问题及相应的解决办法,如果大家在编程中遇到了上述泄漏问题,不妨可以试试对应的方法。

    相关文章

      网友评论

          本文标题:关于安卓内存泄漏的归纳

          本文链接:https://www.haomeiwen.com/subject/romtohtx.html