이 핸들러 클래스는 정적이어야 합니다. 그렇지 않으면 누출이 발생할 수 있습니다.들어오는 처리기
안드로이드 2.3.3 애플리케이션을 서비스로 개발하고 있습니다.주요 활동과 소통하기 위해 서비스 내부에 다음과 같은 내용이 있습니다.
public class UDPListenerService extends Service
{
private static final String TAG = "UDPListenerService";
//private ThreadGroup myThreads = new ThreadGroup("UDPListenerServiceWorker");
private UDPListenerThread myThread;
/**
* Handler to communicate from WorkerThread to service.
*/
private Handler mServiceHandler;
// Used to receive messages from the Activity
final Messenger inMessenger = new Messenger(new IncomingHandler());
// Use to send message to the Activity
private Messenger outMessenger;
class IncomingHandler extends Handler
{
@Override
public void handleMessage(Message msg)
{
}
}
/**
* Target we publish for clients to send messages to Incoming Handler.
*/
final Messenger mMessenger = new Messenger(new IncomingHandler());
[ ... ]
}
그리고 여기는.final Messenger mMessenger = new Messenger(new IncomingHandler());
, 다음과 같은 린트 경고가 표시됩니다.
This Handler class should be static or leaks might occur: IncomingHandler
그것은 무엇을 뜻하나요?
한다면IncomingHandler
클래스는 정적이 아닙니다. 당신의 클래스에 대한 참조가 있을 것입니다.Service
물건.
Handler
동일한 스레드에 대한 개체는 모두 공통의 루퍼 개체를 공유하며, 루퍼 개체는 메시지를 게시하고 이 개체로부터 읽습니다.
메시지에 대상이 포함되어 있으므로Handler
, 메시지 큐에 대상 핸들러가 있는 메시지가 있는 한 핸들러는 가비지를 수집할 수 없습니다.핸들러가 정적이 아니면,Service
아니면Activity
폐기된 후에도 쓰레기를 수거할 수 없습니다.
이로 인해 메시지가 대기열에 남아 있는 한 적어도 한동안은 메모리 누수가 발생할 수 있습니다.오래 지연된 메시지를 게시하지 않는 한 이것은 큰 문제가 되지 않습니다.
만들 수 있습니다.IncomingHandler
정적이고 가.WeakReference
귀하의 서비스:
static class IncomingHandler extends Handler {
private final WeakReference<UDPListenerService> mService;
IncomingHandler(UDPListenerService service) {
mService = new WeakReference<UDPListenerService>(service);
}
@Override
public void handleMessage(Message msg)
{
UDPListenerService service = mService.get();
if (service != null) {
service.handleMessage(msg);
}
}
}
자세한 참조를 위해 로맹 가이의 이 게시물을 참조하십시오.
다른 사람들이 언급한 바와 같이 Lint 경고는 잠재적인 메모리 누출 때문입니다.다음을 통과하면 린트 경고를 피할 수 있습니다.Handler.Callback
시공시Handler
(즉, 당신은 서브클래스를 하지 않습니다.Handler
그리고 없습니다.Handler
비정전 내부 클래스):
Handler mIncomingHandler = new Handler(new Handler.Callback() {
@Override
public boolean handleMessage(Message msg) {
// todo
return true;
}
});
제가 알기로는, 이것은 잠재적인 메모리 누수를 피할 수 없을 것입니다.Message
객체들은 다음과 같은 참조를 갖습니다.mIncomingHandler
참조를 가지는 물체.Handler.Callback
에 대한 참조를 가지는 물체.Service
물건.메시지가 있는 한Looper
메시지 큐,Service
GC가 되지 않습니다.그러나 메시지 대기열에 긴 지연 메시지가 있는 경우가 아니라면 심각한 문제가 되지 않습니다.
다음은 약한 참조 및 정적 핸들러 클래스를 사용하여 문제를 해결하는 일반적인 예입니다(Lint 설명서에 권장됨).
public class MyClass{
//static inner class doesn't hold an implicit reference to the outer class
private static class MyHandler extends Handler {
//Using a weak reference means you won't prevent garbage collection
private final WeakReference<MyClass> myClassWeakReference;
public MyHandler(MyClass myClassInstance) {
myClassWeakReference = new WeakReference<MyClass>(myClassInstance);
}
@Override
public void handleMessage(Message msg) {
MyClass myClass = myClassWeakReference.get();
if (myClass != null) {
...do work here...
}
}
}
/**
* An example getter to provide it to some external class
* or just use 'new MyHandler(this)' if you are using it internally.
* If you only use it internally you might even want it as final member:
* private final MyHandler mHandler = new MyHandler(this);
*/
public Handler getHandler() {
return new MyHandler(this);
}
}
이 방법은 나에게 효과적이었고, 메시지를 처리하는 위치를 내부 클래스로 유지함으로써 코드를 깨끗하게 유지했습니다.
사용할 핸들러
Handler mIncomingHandler = new Handler(new IncomingHandlerCallback());
이너클래스
class IncomingHandlerCallback implements Handler.Callback{
@Override
public boolean handleMessage(Message message) {
// Handle message code
return true;
}
}
@Sogger의 답변으로 일반 핸들러를 만들었습니다.
public class MainThreadHandler<T extends MessageHandler> extends Handler {
private final WeakReference<T> mInstance;
public MainThreadHandler(T clazz) {
// Remove the following line to use the current thread.
super(Looper.getMainLooper());
mInstance = new WeakReference<>(clazz);
}
@Override
public void handleMessage(Message msg) {
T clazz = mInstance.get();
if (clazz != null) {
clazz.handleMessage(msg);
}
}
}
인터페이스:
public interface MessageHandler {
void handleMessage(Message msg);
}
저는 다음과 같이 사용하고 있습니다.하지만 이게 새는게 안전한지 100% 확신할 수는 없습니다.누군가 이에 대해 언급할 수도 있습니다.
public class MyClass implements MessageHandler {
private static final int DO_IT_MSG = 123;
private MainThreadHandler<MyClass> mHandler = new MainThreadHandler<>(this);
private void start() {
// Do it in 5 seconds.
mHandler.sendEmptyMessageDelayed(DO_IT_MSG, 5 * 1000);
}
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case DO_IT_MSG:
doIt();
break;
}
}
...
}
확실하지는 않지만 핸들러가 디스트로이()에서 널인하도록 시도해 볼 수 있습니다.
저는 혼란스러워요.제가 찾은 예제는 정적 속성을 완전히 피하고 UI 스레드를 사용합니다.
public class example extends Activity {
final int HANDLE_FIX_SCREEN = 1000;
public Handler DBthreadHandler = new Handler(Looper.getMainLooper()){
@Override
public void handleMessage(Message msg) {
int imsg;
imsg = msg.what;
if (imsg == HANDLE_FIX_SCREEN) {
doSomething();
}
}
};
}
이 솔루션이 마음에 드는 점은 클래스 변수와 메소드 변수를 섞는 데 문제가 없다는 것입니다.
만약 당신이 코틀린을 사용하고 있다면, 간단히 제거하세요.inner
중첩 클래스를 선언할 때 키워드를 지정합니다.
Kotlin의 중첩된 클래스는 기본적으로 정적이며 다음과 함께 선언합니다.inner
고정적이지 않은 상태로 만듭니다.
중첩 처리기 하위 클래스 선언을 다음에서 변경합니다.
class myService : Service() {
inner class IncomingHandler : Handler(Looper.getMainLooper()) {
/////
}
}
로.
class myService : Service() {
class IncomingHandler : Handler(Looper.getMainLooper()) {
/////
}
}
언급URL : https://stackoverflow.com/questions/11407943/this-handler-class-should-be-static-or-leaks-might-occur-incominghandler
'programing' 카테고리의 다른 글
부트스트랩과 아이오닉의 차이점 (0) | 2023.10.15 |
---|---|
다음 클라우드가 도커에서 데이터베이스를 찾지 못하는 이유는 무엇입니까? (0) | 2023.10.15 |
아이들이 한창일 때까지 (0) | 2023.10.15 |
plsql %NOTFound (0) | 2023.10.15 |
node.js에서 환경 변수를 설정하려면 어떻게 해야 합니까? (0) | 2023.10.15 |