나는 2 년 동안 자바 개발자였습니다.
그러나 코드에 WeakReference를 작성하지 않았습니다. WeakReference를 사용하여 응용 프로그램, 특히 Android 응용 프로그램을보다 효율적으로 만드는 방법은 무엇입니까?
답변
WeakReference
Android에서 a 를 사용하는 것은 평범한 Java에서 사용하는 것과 다르지 않습니다. 다음은 자세한 설명을 제공하는 훌륭한 안내서입니다 . 약한 참조 이해 .
객체에 대한 참조가 필요할 때마다 하나를 사용하는 것을 고려해야하지만 가비지 수집기에서 객체를 보호하기 위해 해당 참조를 원하지 않습니다. 전형적인 예는 메모리 사용량이 너무 많을 때 (종종로 구현 됨 WeakHashMap
) 가비지 수집하려는 캐시입니다 .
확인하시기 바랍니다 SoftReference
및 PhantomReference
뿐만 아니라.
편집 : Tom은으로 캐시를 구현하는 것에 대해 약간의 우려를 제기했습니다 WeakHashMap
. 다음은 문제를 설명하는 기사입니다. WeakHashMap은 캐시가 아닙니다!
Tom은 캐싱 으로 인한 Netbeans 성능 저하에 대한 불만 이 있었다고 생각 WeakHashMap
합니다.
나는 여전히 캐시를 구현 한 WeakHashMap
다음 그것을 사용하여 직접 구현 한 캐시와 비교 하는 것이 좋은 학습 경험이라고 생각합니다 SoftReference
. 실제 환경에서는 Apache JCS 와 같은 타사 라이브러리를 사용하는 것이 더 적합하므로 이러한 솔루션 중 하나를 사용하지 않을 것입니다 .
답변
[EDIT2] 다른 좋은 예를 찾았습니다 WeakReference
. 비트 맵 표시 의 UI 스레드 페이지에서 비트 맵 처리 효율적으로 훈련 안내서, WeakReference
AsyncTask에서 한 가지 사용법을 보여줍니다 .
class BitmapWorkerTask extends AsyncTask<Integer, Void, Bitmap> {
private final WeakReference<ImageView> imageViewReference;
private int data = 0;
public BitmapWorkerTask(ImageView imageView) {
// Use a WeakReference to ensure the ImageView can be garbage collected
imageViewReference = new WeakReference<ImageView>(imageView);
}
// Decode image in background.
@Override
protected Bitmap doInBackground(Integer... params) {
data = params[0];
return decodeSampledBitmapFromResource(getResources(), data, 100, 100));
}
// Once complete, see if ImageView is still around and set bitmap.
@Override
protected void onPostExecute(Bitmap bitmap) {
if (imageViewReference != null && bitmap != null) {
final ImageView imageView = imageViewReference.get();
if (imageView != null) {
imageView.setImageBitmap(bitmap);
}
}
}
}
그것은 말합니다
ImageView에 대한 WeakReference는 AsyncTask가 ImageView 및 그 참조가 가비지 수집되는 것을 막지 않도록합니다 . 작업이 완료 될 때 ImageView가 계속 유지된다는 보장은 없으므로 onPostExecute ()에서 참조를 확인해야합니다. 예를 들어 사용자가 활동에서 벗어나거나 작업이 완료되기 전에 구성 변경이 발생하면 ImageView가 더 이상 존재하지 않을 수 있습니다.
행복한 코딩!
[편집] facebook-android-sdkWeakReference
에서 정말 좋은 예를 찾았습니다 . ToolTipPopup 클래스는 앵커 뷰 위에 툴팁을 표시하는 간단한 위젯 클래스입니다. 스크린 샷을 찍었습니다.
수업은 정말 간단하고 (약 200 줄) 볼 가치가 있습니다. 그 수업에서WeakReference
클래스는 앵커 뷰에 대한 참조를 보유하는 데 사용됩니다. 툴팁 인스턴스가 앵커 뷰보다 오래 지속되는 경우에도 앵커 뷰를 가비지 수집 할 수 있기 때문에 완벽합니다.
행복한 코딩! 🙂
한 가지 실례를 공유하겠습니다 WeakReference
수업의 . 안드로이드 프레임 워크 위젯의 작은 코드 스 니펫입니다 AutoCompleteTextView
.
요컨대, WeakReference
수업은 View
이 예제에서 메모리 누수 를 방지하기 위해 객체를 .
중첩 된 클래스 인 PopupDataSetObserver 클래스를 복사하여 붙여 넣기 만하면됩니다. AutoCompleteTextView
됩니다. 정말 간단하고 의견은 수업을 잘 설명합니다. 행복한 코딩! 🙂
/**
* Static inner listener that keeps a WeakReference to the actual AutoCompleteTextView.
* <p>
* This way, if adapter has a longer life span than the View, we won't leak the View, instead
* we will just leak a small Observer with 1 field.
*/
private static class PopupDataSetObserver extends DataSetObserver {
private final WeakReference<AutoCompleteTextView> mViewReference;
private PopupDataSetObserver(AutoCompleteTextView view) {
mViewReference = new WeakReference<AutoCompleteTextView>(view);
}
@Override
public void onChanged() {
final AutoCompleteTextView textView = mViewReference.get();
if (textView != null && textView.mAdapter != null) {
// If the popup is not showing already, showing it will cause
// the list of data set observers attached to the adapter to
// change. We can't do it from here, because we are in the middle
// of iterating through the list of observers.
textView.post(updateRunnable);
}
}
private final Runnable updateRunnable = new Runnable() {
@Override
public void run() {
final AutoCompleteTextView textView = mViewReference.get();
if (textView == null) {
return;
}
final ListAdapter adapter = textView.mAdapter;
if (adapter == null) {
return;
}
textView.updateDropDownForFilter(adapter.getCount());
}
};
}
그리고 PopupDataSetObserver
어댑터 설정에 사용됩니다.
public <T extends ListAdapter & Filterable> void setAdapter(T adapter) {
if (mObserver == null) {
mObserver = new PopupDataSetObserver(this);
} else if (mAdapter != null) {
mAdapter.unregisterDataSetObserver(mObserver);
}
mAdapter = adapter;
if (mAdapter != null) {
//noinspection unchecked
mFilter = ((Filterable) mAdapter).getFilter();
adapter.registerDataSetObserver(mObserver);
} else {
mFilter = null;
}
mPopup.setAdapter(mAdapter);
}
마지막 한가지. 또한 WeakReference
Android 애플리케이션 의 실제 예제를 알고 싶었고 공식 샘플 애플리케이션에서 샘플을 찾을 수있었습니다. 그러나 나는 실제로 그들의 사용법 중 일부를 이해할 수 없었습니다. 예를 들어 ThreadSample 및 DisplayingBitmaps 응용 프로그램 WeakReference
은 해당 코드에서 사용하지만 여러 테스트를 실행 한 후 null
참조 된 뷰 객체가 가비지 수집 된 어댑터가 아닌 어댑터에서 재활용되므로 get () 메서드가 결코 반환하지 않는 것으로 나타났습니다 .
답변
다른 답변 중 일부는 불완전하거나 지나치게 길어 보입니다. 일반적인 답변은 다음과 같습니다.
Java 및 Android에서 WeakReference를 사용하는 방법
다음 단계를 수행 할 수 있습니다.
- 만들기
WeakReference
변수 - 약한 참조 설정
- 약한 참조를 사용하십시오
암호
MyClass
에 대한 약한 참조가 AnotherClass
있습니다.
public class MyClass {
// 1. Create a WeakReference variable
private WeakReference<AnotherClass> mAnotherClassReference;
// 2. Set the weak reference (nothing special about the method name)
void setWeakReference(AnotherClass anotherClass) {
mAnotherClassReference = new WeakReference<>(anotherClass);
}
// 3. Use the weak reference
void doSomething() {
AnotherClass anotherClass = mAnotherClassReference.get();
if (anotherClass == null) return;
// do something with anotherClass
}
}
AnotherClass
에 대한 강력한 참조가 MyClass
있습니다.
public class AnotherClass {
// strong reference
MyClass mMyClass;
// allow MyClass to get a weak reference to this class
void someMethod() {
mMyClass = new MyClass();
mMyClass.setWeakReference(this);
}
}
노트
- 참조가 약한 이유는 가비지 콜렉터가 더 이상 필요하지 않은 오브젝트를 처리 할 수 있기 때문입니다. 두 객체가 서로 강한 참조를 유지하면 가비지 수집 할 수 없습니다. 메모리 누수입니다.
- 두 객체가 서로를 참조해야하는 경우 객체 A (일반적으로 수명이 짧은 객체)는 객체 B (일반적으로 수명이 긴 객체)에 대해 약한 참조를 가져야하지만 B는 A에 대한 강한 참조를 가져야합니다. 위의 예
MyClass
에서 A는 과AnotherClass
B였다. - a를 사용하는 대안
WeakReference
은 다른 클래스가 인터페이스를 구현하도록하는 것입니다. 이는 리스너 / 오브 서버 패턴 에서 수행됩니다 .
실제 예
답변
“정규화 된”매핑은 문제가있는 개체의 한 인스턴스를 메모리에 유지하고 다른 모든 개체는 포인터 나 이와 같은 메커니즘을 통해 특정 인스턴스를 찾는 곳입니다. 약점 참조가 도움이 될 수있는 곳입니다. 짧은 대답은 WeakReference 객체를 사용하여 시스템의 객체에 대한 포인터를 만들 수 있지만 가비지 수집기 가 범위를 벗어난 후에도 객체를 회수 할 수 있다는 것입니다. 예를 들어 다음과 같은 코드가 있다면 :
class Registry {
private Set registeredObjects = new HashSet();
public void register(Object object) {
registeredObjects.add( object );
}
}
에 등록 된 객체에 대한 참조가 있기 때문에 등록한 모든 객체는 GC에서 회수하지 않습니다 registeredObjects
. 반면에 내가 이것을하면 :
class Registry {
private Set registeredObjects = new HashSet();
public void register(Object object) {
registeredObjects.add( new WeakReference(object) );
}
}
그런 다음 GC가 세트의 객체를 회수하려고 할 때 그렇게 할 수 있습니다. 캐싱, 카탈로그 등을 위해이 기술을 사용할 수 있습니다. GC 및 캐싱에 대한보다 자세한 논의에 대한 참조는 아래를 참조하십시오.
참조 : 가비지 수집기 및 약한 참조