Android 笔记 JAVA 的 WeakReference

本文探讨了在Java中使用WeakReference来避免内存泄漏的方法。通过对比C/C++与Java的内存管理方式,阐述了WeakReference的工作原理及其应用场景,尤其是在缓存管理和资源消耗大的对象管理上的优势。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

WeakReference

在计算机编程的时候,一个特别需要注意的事情就是关于内存使用的。如果程序不注意内存使用状况,很可能会造成内存泄漏,时间越长内存占用越多,造成性能下降。

C和C++语言需要程序员手动清空不需要使用的对象,所以编程较复杂。
JAVA语言的一个好处就是,虚拟机可以自动清理对象,也就是说

Camera camera = new Camera();
camera = null;

只要第二行中设定为null,那虚拟机就会在合适的时候清空这个camera对象所占空间。对于没有使用的简单引用,即便是不设定null,虚拟机也会在合适的时候清空这个对象,只要发现这个对象没有在使用了。

有些时候,虚拟机也不会回收空间,因为这个对象是在某些时候需要的(比如使用cache的时候,这一点我不太明白,但是可以想象的到)。

如果一个对象被WeakReference指向,并且没有其他引用指向的时候,系统会在合适的时候回收空间。

WeakReference<Camera> weakCamera = new WeakReference(Camera)(camera);

通过这个我们创建了一个Weak的Camera对象,我们不需要对这个对象进行任何回收相关的操作,系统就会在合适的时候回收空间了

为此,我们不再需要直接从Camera获得引用(因为这样会获得强引用,那还要W额啊看Reference干什么?),而是通过这个weakCamera获得camera对象

if(weakCamera.get()!=null)
{
    camera = weakCamera.get();
}

这样获得的引用是弱引用,在使用的时候系统不会回收,在使用结束以后会在合适的时候回收。

所以说,WeakReference适合使用在一些比较耗费资源的对象上,对移动设备来说是一个很好的东西。

参考 Java WeakReference的理解与使用

<think>我们正在讨论在Android中使用Java实现定时器功能。根据引用内容,我们可以使用Handler、ScheduledExecutorService等机制。下面将详细介绍几种方法。1.**使用Handler实现定时器**(适用于需要更新UI的定时任务,因为Handler可以方便地与主线程通信):-创建个Handler,并在其handleMessage方法中发送延迟消息来实现周期性任务。-注意:这种方式在Activity或Fragment销毁时需要移除未处理的消息,以避免内存泄漏。2.**使用Timer和TimerTask**(传统方法,但不如Handler推荐):-Timer是Java标准库中的类,可以在后台线程执行定时任务。-注意:TimerTask在Android中可能不如Handler灵活,且不能直接更新UI。3.**使用ScheduledExecutorService**(推荐用于后台定时任务,精度较高):-从Java5开始引入,作为Timer的替代品,提供更好的精度和线程池管理。4.**使用AlarmManager**(适用于需要系统在特定时间唤醒应用的场景):-这是系统级别的定时服务,即使应用退出也能触发,但相对耗电。5.**使用CountDownTimer**(适用于倒计时场景):-AndroidSDK提供的简单倒计时工具。下面分别给出代码示例:###1.Handler实现定时器(主线程定时任务)```java//在Activity中声明privateHandlermHandler=newHandler(Looper.getMainLooper());privateRunnablemUpdateTask=newRunnable(){@Overridepublicvoidrun(){//执行定时任务,例如更新UIupdateUI();//每隔1秒执行次mHandler.postDelayed(this,1000);}};//启动定时器mHandler.postDelayed(mUpdateTask,1000);//在Activity销毁时停止定时器,防止内存泄漏@OverrideprotectedvoidonDestroy(){super.onDestroy();mHandler.removeCallbacks(mUpdateTask);}```###2.Timer和TimerTask(后台定时任务)```javaTimertimer=newTimer();TimerTasktask=newTimerTask(){@Overridepublicvoidrun(){//在后台线程执行任务doBackgroundWork();}};//延迟1秒后执行,每隔1秒执行次timer.schedule(task,1000,1000);//停止定时器//timer.cancel();```###3.ScheduledExecutorService(推荐后台定时任务)```javaScheduledExecutorServiceexecutor=Executors.newScheduledThreadPool(1);executor.scheduleAtFixedRate(newRunnable(){@Overridepublicvoidrun(){//执行后台任务doBackgroundWork();}},1,1,TimeUnit.SECONDS);//延迟1秒,然后每隔1秒执行//关闭定时器//executor.shutdown();```###4.AlarmManager(系统级定时)```java//创建个PendingIntentIntentintent=newIntent(this,MyReceiver.class);PendingIntentpendingIntent=PendingIntent.getBroadcast(this,0,intent,0);AlarmManageralarmManager=(AlarmManager)getSystemService(Context.ALARM_SERVICE);//设置重复闹钟,从当前时间开始,每隔60秒触发次alarmManager.setRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP,SystemClock.elapsedRealtime()+1000,60000,//间隔时间(毫秒)pendingIntent);//取消闹钟//alarmManager.cancel(pendingIntent);```###5.CountDownTimer(倒计时)```javanewCountDownTimer(30000,1000){//总时间30秒,间隔1秒publicvoidonTick(longmillisUntilFinished){//每秒调用次updateCountdown(millisUntilFinished/1000);}publicvoidonFinish(){//倒计时结束countdownFinished();}}.start();```###注意事项-**精度问题**:`Handler`和`Timer`的精度受系统负载影响,而`ScheduledExecutorService`相对更精确[^4]。-**内存泄漏**:使用Handler或内部类时,注意在Activity/Fragment销毁时移除回调或取消任务。-**线程安全**:在后台线程更新UI需要使用Handler切换到主线程。-**电量优化**:对于长时间后台任务,建议使用`WorkManager`(兼容后台执行限制)。###性能比较|方法|适用场景|精度|是否可后台运行|备注||-----------------------|------------------------|--------|----------------|--------------------------||Handler|UI更新定时任务|般|否(主线程)|简单易用,注意内存泄漏||Timer|后台定时任务|般|是|不推荐,有缺陷||ScheduledExecutorService|后台定时任务|较高|是|推荐,线程池管理||AlarmManager|精确系统唤醒|高|是|耗电,适合严格时间要求||CountDownTimer|倒计时|般|否(主线程)|专用于倒计时|>提示:在Android中,对于需要精确计时的任务,优先考虑`ScheduledExecutorService`或`AlarmManager`;对于UI相关的定时更新,使用`Handler`即可。###相关问题1.如何在Android中实现高精度的定时任务?2.使用Handler实现定时器时如何避免内存泄漏?3.AlarmManager和Handler在定时功能上有何本质区别?</think>在 Android 中使用 Java 实现定时器功能有多种方法,每种方法都有其适用场景和特点。以下是五种主要实现方式及其详细说明: ### 1. Handler 定时器(主线程定时任务) ```java private Handler mHandler = new Handler(Looper.getMainLooper()); private Runnable mUpdateTask = new Runnable() { @Override public void run() { // 执行定时任务(如更新UI) updateUI(); // 每1秒循环执行 mHandler.postDelayed(this, 1000); } }; // 启动定时器 mHandler.postDelayed(mUpdateTask, 1000); // 停止定时器(在Activity销毁时调用) @Override protected void onDestroy() { super.onDestroy(); mHandler.removeCallbacks(mUpdateTask); } ``` **特点**: - 在主线程执行,可直接更新UI - 简单易用,适合UI定时刷新 - 需手动管理生命周期[^1] ### 2. ScheduledExecutorService(高精度后台定时器) ```java ScheduledExecutorService executor = Executors.newScheduledThreadPool(1); executor.scheduleAtFixedRate(new Runnable() { @Override public void run() { // 执行后台定时任务 doBackgroundWork(); } }, 1, 1, TimeUnit.SECONDS); // 初始延迟1秒,周期1秒 // 关闭定时器(在Activity销毁时调用) executor.shutdown(); ``` **特点**: - 线程池管理,精度高(优于Thread.sleep)[^4] - 适合后台计算密集型任务 - 避免ANR(不在主线程运行) ### 3. Timer & TimerTask(传统定时器) ```java Timer timer = new Timer(); TimerTask task = new TimerTask() { @Override public void run() { // 执行定时任务 } }; // 立即开始,每2秒执行 timer.schedule(task, 0, 2000); // 停止定时器 timer.cancel(); ``` **特点**: - Java标准库实现 - 简单但精度有限(受系统负载影响)[^3] - 注意:单个Timer故障会影响所有任务 ### 4. CountDownTimer(倒计时专用) ```java new CountDownTimer(30000, 1000) { // 总时长30秒,间隔1秒 public void onTick(long millisUntilFinished) { // 每秒执行 updateCountdown(millisUntilFinished / 1000); } public void onFinish() { // 倒计时结束 showCompletion(); } }.start(); ``` **特点**: - Android SDK内置倒计时器 - 精确控制倒计时过程 - 自动处理生命周期(无需手动取消) ### 5. AlarmManager(系统级定时) ```java AlarmManager alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE); Intent intent = new Intent(this, AlarmReceiver.class); PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 0, intent, 0); // 设置每天上午8点触发 Calendar calendar = Calendar.getInstance(); calendar.setTimeInMillis(System.currentTimeMillis()); calendar.set(Calendar.HOUR_OF_DAY, 8); alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), AlarmManager.INTERVAL_DAY, pendingIntent); ``` **特点**: - 系统级唤醒,应用关闭仍可执行 - 适合精确时间点任务(如闹钟) - 需配合BroadcastReceiver使用 --- ### 方案选择指南 | **场景** | **推荐方案** | **精度** | **线程** | |-------------------------|---------------------------|----------|-----------| | UI定时刷新 | Handler定时器 | ⭐⭐ | 主线程 | | 后台周期性任务 | ScheduledExecutorService | ⭐⭐⭐⭐ | 后台线程 | | 简单定时逻辑 | Timer & TimerTask | ⭐⭐ | 后台线程 | | 倒计时功能 | CountDownTimer | ⭐⭐⭐ | 主线程 | | 精确时间点/唤醒设备 | AlarmManager | ⭐⭐⭐⭐ | 任意 | --- ### 关键注意事项 1. **内存泄漏处理**: ```java // 使用弱引用包装Activity private static class SafeHandler extends Handler { private final WeakReference<Activity> mActivityRef; SafeHandler(Activity activity) { mActivityRef = new WeakReference<>(activity); } @Override public void handleMessage(Message msg) { Activity activity = mActivityRef.get(); if (activity == null || activity.isFinishing()) return; // 安全处理 } } ``` 2. **精度优化**: - 避免使用`Thread.sleep()`,其精度受系统调度影响[^4] - 高精度场景优先选择`ScheduledExecutorService` 3. **WebView特殊处理**: - 当包含WebView时,使用`View.GONE`替代`View.INVISIBLE`保持H5定时器精度[^2] ```java webViewContainer.setVisibility(View.GONE); // 正确做法 ``` 4. **生命周期管理**: ```java // 在onPause/onDestroy中统释放资源 @Override protected void onDestroy() { super.onDestroy(); if (timer != null) timer.cancel(); if (executor != null) executor.shutdown(); handler.removeCallbacksAndMessages(null); } ``` --- ### 相关问题 1. 如何确保Android定时器在屏幕关闭后继续运行? 2. ScheduledExecutorService和Handler定时器在性能上有何差异? 3. 在WebView中如何保持JavaScript定时器的精度? 4. 如何实现跨进程的定时任务调度?
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值