b2科目四模拟试题多少题驾考考爆了怎么补救
b2科目四模拟试题多少题 驾考考爆了怎么补救

Activity内存泄漏的使用代码编写一个常见问题解决办法

电脑杂谈  发布时间:2021-03-01 16:03:13  来源:网络整理

内存泄漏的示例1.由单例导致的内存泄漏

public class AppManager {
    private static AppManager instance;
    private Context context;
    private AppManager(Context context) {
        this.context = context;
    }
    public static AppManager getInstance(Context context) {
        if (instance == null) {
            instance = new AppManager(context);
        }
        return instance;
    }
}

由于需要传递一个Context,因此该Context的生命周期的长度非常重要:

正确的方法:

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中开始,这种书写方式可能会出现:

public class MainActivity extends AppCompatActivity {
    private static TestResource mResource = null;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        if(mManager == null){
            mResource = new TestResource();
        }
        //...
    }
    class TestResource {
        //...
    }
}

通过这种方式,在Activity内部创建了一个非静态内部类的单例。每次启动活动时,将使用单例数据。尽管避免了资源的重复创建,但是这种写入方式将导致内存泄漏。 ,因为默认情况下非静态内部类将保存外部类的引用,并且非静态内部类用于创建静态实例。实例的生命周期与应用程序的生命周期相同,这将导致静态实例始终保留对Activity的引用,从而导致Activity的内存资源无法正常恢复。正确的方法是:

将内部类设置为静态内部类,或提取内部类并将其封装为单例。如果需要使用上下文,请使用ApplicationContext

3.处理程序导致的内存泄漏

使用Handler引起的内存泄漏问题应该说是最常见的。通常,应在Handler的帮助下处理诸如处理网络任务或封装一些请求回调之类的api。使用Handler的代码编写不正确可能会导致内存泄漏,以下示例:

public class MainActivity extends AppCompatActivity {
    private Handler mHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            //...
        }
    };
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        loadData();
    }
    private void loadData(){
        //...request
        Message message = Message.obtain();
        mHandler.sendMessage(message);
    }
}

java内存泄漏例子_内存泄漏和溢出例子_内存泄漏和溢出例子

这种创建Handler的方式将导致内存泄漏。由于mHandler是Handler的非静态匿名内部类的实例,因此它拥有对外部类Activity的引用。我们知道消息循环在Looper线程中不断轮询。处理消息,然后在Activity退出时,消息队列中有未处理的消息或正在处理消息,并且消息队列中的Message持有对mHandler实例的引用,而mHandler持有对Activity的引用,这导致不能及时恢复活动资源的内存,从而导致内存泄漏,因此另一种方法是:

public class MainActivity extends AppCompatActivity {
    private MyHandler mHandler = new MyHandler(this);
    private TextView mTextView ;
    private static class MyHandler extends Handler {
        private WeakReference 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);
    }
}

创建一个静态Handler内部类,然后使用对Handler所持有对象的弱引用,以便在回收期间还可以回收Handler所持有的对象。尽管避免了活动泄漏,但是在Looper线程的消息队列中仍然有可能要处理消息,因此我们应该在销毁或停止活动期间删除消息队列中的消息。更准确的方法如下:

public class MainActivity extends AppCompatActivity {
    private MyHandler mHandler = new MyHandler(this);
    private TextView mTextView ;
    private static class MyHandler extends Handler {
        private WeakReference 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);删除消息队列中的所有消息和所有可运行对象。当然,您也可以使用mHandler.removeCallbacks();。或mHandler.removeMessages();删除指定的Runnable和Message。

4.线程引起的内存泄漏

线程引起的内存泄漏也很常见。以下两个示例可能是每个人都写的:

//    ——————test1
    new AsyncTask() {
        @Override
        protected Void doInBackground(Void... params) {
            SystemClock.sleep(10000);
            return null;
        }
    }.execute();
//——————test2
    new Thread(new Runnable() {
        @Override
        public void run() {
            SystemClock.sleep(10000);
        }
    }).start();

上述异步任务和Runnable都是匿名内部类,因此它们具有对当前Activity的隐式引用。如果在销毁活动之前任务尚未完成,

这将导致活动的内存资源无法回收,从而导致内存泄漏。正确的方法是使用静态内部类,如下所示:

static class MyAsyncTask extends AsyncTask {
    private WeakReference 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(),以避免在后台执行任务时浪费资源。

5.由于资源未封闭导致内存泄漏

对于诸如BraodcastReceiver,ContentObserver,File,Cursor,Stream,Bitmap等资源的使用,您应该在Activity被销毁时及时关闭或注销,否则这些资源将不会被回收,从而导致内存泄漏


本文来自电脑杂谈,转载请注明本文网址:
http://www.pc-fly.com/a/shoujiruanjian/article-362135-1.html

    相关阅读
      发表评论  请自觉遵守互联网相关的政策法规,严禁发布、暴力、反动的言论

      • 长孙铸
        长孙铸

        某国际学校的老师出了一道开放性问题

      热点图片
      拼命载入中...