这个 Runnable 不会发生内存泄漏吗?
Is this Runnable safe from memory leak?
我完全是 Java 的初学者,并且创建了一个简单的 Java Android 片段,其中在 1.5 秒后的 Runnable 中,我将 TextView
从Hello World
到 Hola Mundo
。它完美地工作,基本上 WeakReference
应该可以防止这种内存泄漏的发生,对吗?我怀疑每当发生设备方向时是否绝对没有内存泄漏。我很想检查一下,但无法在我的模拟 Android 中改变方向。
这是代码:
package com.example.helloworld;
import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.widget.TextView;
import android.util.Log;
import java.lang.ref.WeakReference;
public class HelloWorldActivity extends Activity
{
private Handler h = new Handler();
private static TextView txtview;
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
txtview = (TextView) findViewById(R.id.mainview);
h.postDelayed(new WeakRunnable(txtview),1500);
}
private static final class WeakRunnable implements Runnable {
private final WeakReference<TextView> mtextview;
protected WeakRunnable(TextView textview){
mtextview = new WeakReference<TextView>(textview);
}
@Override
public void run() {
TextView textview = mtextview.get();
if (textview != null) {
txtview.setText("Hola Mundo");
textview = null; // No idea if setting to null afterwards is a good idea
}
Log.d("com.example.helloworld", "" + textview);
}
}
}
编辑
内存泄漏是安全的,但一些答案也与 UI 线程阻塞有关。事实上,此代码在主 (UI) 线程中运行处理程序。为了生成一个新线程,我手动生成一个线程,如下所示:
package com.example.helloworld;
import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.widget.TextView;
import android.util.Log;
import java.lang.ref.WeakReference;
public class HelloWorldActivity extends Activity
{
private static TextView txtview;
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
txtview = (TextView) findViewById(R.id.mainview);
Thread t = new Thread(new WeakRunnable(txtview));
t.start();
}
private static final class WeakRunnable implements Runnable {
private final WeakReference<TextView> mtextview;
protected WeakRunnable(TextView textview){
mtextview = new WeakReference<TextView>(textview);
}
@Override
public void run() {
TextView textview = mtextview.get();
if (textview != null) {
/*
try {
Thread.sleep(1500);
} catch (InterruptedException e) {
e.printStackTrace();
}
*/
txtview.setText("Hola Mundo");
textview = null;
}
Log.d("com.example.helloworld", "" + Thread.currentThread().getName()); // Outputs "Thread-<num>" if not running on UI thread
}
}
}
现在的问题是我似乎无法以任何方式延迟生成的线程,否则它会起作用。
这个:
try {
Thread.sleep(1500);
} catch (InterruptedException e) {
e.printStackTrace();
}
使应用程序自行退出,我不明白为什么。有些东西告诉我,我以错误的方式延迟它。
EDIT2
感谢 link @EugenMatynov 给我:update ui from another thread in android 我明白了应用程序退出的原因。这一切都归结为原因 您不能从主线程以外的线程调用 UI 方法。 并且从另一个线程更新 UI 是不好的做法线程。
h.postDelayed(new WeakRunnable(txtview),1500);
我认为它会阻塞 UI 线程。
这是内存泄漏的一个很好的示例。
https://github.com/badoo/android-weak-handler
I have a doubt if there's absolutely no memory leak whenever device
orientation occurs.
有可能。持续 1.5 秒。队列清空后,处理程序可以被垃圾回收,旧的 Activity 也是如此。为了安全覆盖 onPause,并调用 handler.removeCallbacks(null);
来清除 Handler 的队列
我认为如果你使用你的代码是没有泄漏的:
private static Handler h = new Handler();
或
txtview.postDelayed(new WeakRunnable(txtview),1500);
因为您已将视图存储为弱引用。方法:
txtview.postDelayed(new WeakRunnable(txtview),1500);
只需调用 UI 线程的主处理程序,因此如果 activity 被销毁,视图为 null 且可运行的不执行任何操作。
同样由于弱引用,activity 可以被垃圾回收,因为没有对它的强引用。
请这样做,否则会阻塞 UIThread,不推荐这样做。为此,您还可以使用 TimerTask,在此处查看:http://developer.android.com/reference/java/util/TimerTask.html
import android.widget.TextView;
import android.util.Log;
import java.lang.ref.WeakReference;
public class HelloWorldActivity extends Activity
{
private Handler h = new Handler();
private static TextView txtview;
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
txtview = (TextView) findViewById(R.id.mainview);
h.postDelayed(new Runnable() {
@Override
public void run() {
changeText();
}
}, 1500);
}
public void changeText(){
txtview.setText("Hola mundo.");
h.removeCallbacksAndMessages(null);
}
}
顺便说一句,您可以通过以下方式更改模拟器中的方向:Ctrl+F12
我完全是 Java 的初学者,并且创建了一个简单的 Java Android 片段,其中在 1.5 秒后的 Runnable 中,我将 TextView
从Hello World
到 Hola Mundo
。它完美地工作,基本上 WeakReference
应该可以防止这种内存泄漏的发生,对吗?我怀疑每当发生设备方向时是否绝对没有内存泄漏。我很想检查一下,但无法在我的模拟 Android 中改变方向。
这是代码:
package com.example.helloworld;
import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.widget.TextView;
import android.util.Log;
import java.lang.ref.WeakReference;
public class HelloWorldActivity extends Activity
{
private Handler h = new Handler();
private static TextView txtview;
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
txtview = (TextView) findViewById(R.id.mainview);
h.postDelayed(new WeakRunnable(txtview),1500);
}
private static final class WeakRunnable implements Runnable {
private final WeakReference<TextView> mtextview;
protected WeakRunnable(TextView textview){
mtextview = new WeakReference<TextView>(textview);
}
@Override
public void run() {
TextView textview = mtextview.get();
if (textview != null) {
txtview.setText("Hola Mundo");
textview = null; // No idea if setting to null afterwards is a good idea
}
Log.d("com.example.helloworld", "" + textview);
}
}
}
编辑
内存泄漏是安全的,但一些答案也与 UI 线程阻塞有关。事实上,此代码在主 (UI) 线程中运行处理程序。为了生成一个新线程,我手动生成一个线程,如下所示:
package com.example.helloworld;
import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.widget.TextView;
import android.util.Log;
import java.lang.ref.WeakReference;
public class HelloWorldActivity extends Activity
{
private static TextView txtview;
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
txtview = (TextView) findViewById(R.id.mainview);
Thread t = new Thread(new WeakRunnable(txtview));
t.start();
}
private static final class WeakRunnable implements Runnable {
private final WeakReference<TextView> mtextview;
protected WeakRunnable(TextView textview){
mtextview = new WeakReference<TextView>(textview);
}
@Override
public void run() {
TextView textview = mtextview.get();
if (textview != null) {
/*
try {
Thread.sleep(1500);
} catch (InterruptedException e) {
e.printStackTrace();
}
*/
txtview.setText("Hola Mundo");
textview = null;
}
Log.d("com.example.helloworld", "" + Thread.currentThread().getName()); // Outputs "Thread-<num>" if not running on UI thread
}
}
}
现在的问题是我似乎无法以任何方式延迟生成的线程,否则它会起作用。
这个:
try {
Thread.sleep(1500);
} catch (InterruptedException e) {
e.printStackTrace();
}
使应用程序自行退出,我不明白为什么。有些东西告诉我,我以错误的方式延迟它。
EDIT2
感谢 link @EugenMatynov 给我:update ui from another thread in android 我明白了应用程序退出的原因。这一切都归结为原因 您不能从主线程以外的线程调用 UI 方法。 并且从另一个线程更新 UI 是不好的做法线程。
h.postDelayed(new WeakRunnable(txtview),1500); 我认为它会阻塞 UI 线程。 这是内存泄漏的一个很好的示例。 https://github.com/badoo/android-weak-handler
I have a doubt if there's absolutely no memory leak whenever device orientation occurs.
有可能。持续 1.5 秒。队列清空后,处理程序可以被垃圾回收,旧的 Activity 也是如此。为了安全覆盖 onPause,并调用 handler.removeCallbacks(null);
来清除 Handler 的队列
我认为如果你使用你的代码是没有泄漏的:
private static Handler h = new Handler();
或
txtview.postDelayed(new WeakRunnable(txtview),1500);
因为您已将视图存储为弱引用。方法:
txtview.postDelayed(new WeakRunnable(txtview),1500);
只需调用 UI 线程的主处理程序,因此如果 activity 被销毁,视图为 null 且可运行的不执行任何操作。
同样由于弱引用,activity 可以被垃圾回收,因为没有对它的强引用。
请这样做,否则会阻塞 UIThread,不推荐这样做。为此,您还可以使用 TimerTask,在此处查看:http://developer.android.com/reference/java/util/TimerTask.html
import android.widget.TextView;
import android.util.Log;
import java.lang.ref.WeakReference;
public class HelloWorldActivity extends Activity
{
private Handler h = new Handler();
private static TextView txtview;
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
txtview = (TextView) findViewById(R.id.mainview);
h.postDelayed(new Runnable() {
@Override
public void run() {
changeText();
}
}, 1500);
}
public void changeText(){
txtview.setText("Hola mundo.");
h.removeCallbacksAndMessages(null);
}
}
顺便说一句,您可以通过以下方式更改模拟器中的方向:Ctrl+F12