Tôi đã là một nhà phát triển java được 2 năm.
Nhưng tôi chưa bao giờ viết WeakReference trong mã của mình. Làm cách nào để sử dụng WeakReference để làm cho ứng dụng của tôi hiệu quả hơn, đặc biệt là ứng dụng Android?
Tôi đã là một nhà phát triển java được 2 năm.
Nhưng tôi chưa bao giờ viết WeakReference trong mã của mình. Làm cách nào để sử dụng WeakReference để làm cho ứng dụng của tôi hiệu quả hơn, đặc biệt là ứng dụng Android?
Câu trả lời:
Sử dụng một WeakReference
trong Android không khác gì sử dụng một trong Java cũ đơn giản. Đây là một hướng dẫn tuyệt vời cung cấp một lời giải thích chi tiết: Hiểu các tài liệu tham khảo yếu .
Bạn nên suy nghĩ về việc sử dụng bất cứ khi nào bạn cần một tham chiếu đến một đối tượng, nhưng bạn không muốn tham chiếu đó để bảo vệ đối tượng khỏi trình thu gom rác. Một ví dụ cổ điển là bộ đệm mà bạn muốn là rác được thu thập khi mức sử dụng bộ nhớ quá cao (thường được thực hiện với WeakHashMap
).
Hãy chắc chắn để kiểm tra SoftReference
và PhantomReference
là tốt.
EDIT: Tom đã đưa ra một số lo ngại về việc thực hiện bộ đệm với WeakHashMap
. Đây là một bài viết đặt ra các vấn đề: WeakHashMap không phải là bộ đệm!
Tom nói đúng rằng đã có những phàn nàn về hiệu suất của Netbeans kém doWeakHashMap
bộ nhớ đệm.
Tôi vẫn nghĩ rằng nó sẽ là một kinh nghiệm học tập tốt để thực hiện bộ đệm WeakHashMap
và sau đó so sánh nó với bộ đệm cuộn bằng tay của chính bạn được thực hiện với SoftReference
. Trong thế giới thực, có lẽ bạn sẽ không sử dụng một trong hai giải pháp này, vì sẽ hợp lý hơn khi sử dụng thư viện của bên thứ 3 như Apache JCS .
WeakHashMap
được sử dụng như một bộ đệm là gây tử vong. Các mục có thể được gỡ bỏ ngay khi chúng được tạo. Điều này có thể sẽ không xảy ra khi bạn đang thử nghiệm, nhưng cũng có thể khi sử dụng. Đáng chú ý, NetBeans có thể được đưa đến điểm dừng CPU 100% hiệu quả bằng cách này.
WeakHashMap
ngay cả khi bạn đúng rằng đó là một lựa chọn tồi;)
[EDIT2] Tôi tìm thấy một ví dụ hay khác về WeakReference
. Xử lý Bitmap Tắt trang Chủ đề giao diện người dùng trong Hiển thị Bitmap Hướng dẫn đào tạo hiệu quả , hiển thị một cách sử dụng WeakReference
trong 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);
}
}
}
}
Nó nói rằng,
WeakReference cho ImageView đảm bảo rằng AsyncTask không ngăn ImageView và bất cứ thứ gì nó tham chiếu khỏi rác được thu thập . Không có gì đảm bảo ImageView vẫn ở xung quanh khi tác vụ kết thúc, do đó bạn cũng phải kiểm tra tham chiếu trong onPostExecute (). ImageView có thể không còn tồn tại, ví dụ, nếu người dùng điều hướng khỏi hoạt động hoặc nếu thay đổi cấu hình xảy ra trước khi tác vụ kết thúc.
Chúc mừng mã hóa!
[EDIT] Tôi đã tìm thấy một ví dụ thực sự tốt WeakReference
từ facebook-android-sdk . Lớp ToolTipPopup không có gì ngoài một lớp widget đơn giản hiển thị tooltip phía trên khung nhìn neo. Tôi chụp ảnh màn hình.
Lớp học thực sự đơn giản (khoảng 200 dòng) và đáng để xem xét. Trong lớp đóWeakReference
lớp được sử dụng để giữ tham chiếu đến chế độ xem neo, điều này có ý nghĩa hoàn hảo, bởi vì nó có thể cho chế độ xem neo là rác được thu thập ngay cả khi một đối tượng chú giải công cụ tồn tại lâu hơn chế độ xem neo.
Chúc mừng mã hóa! :)
Hãy để tôi chia sẻ một ví dụ làm việc của WeakReference
lớp. Đó là một đoạn mã nhỏ từ tiện ích khung Android được gọi AutoCompleteTextView
.
Nói tóm lại, WeakReference
lớp được sử dụng để giữ View
đối tượng để ngăn chặn rò rỉ bộ nhớ trong ví dụ này.
Tôi sẽ chỉ sao chép và dán lớp PopupDataSetObserver, đây là một lớp lồng nhau AutoCompleteTextView
. Nó thực sự đơn giản và các ý kiến giải thích tốt về lớp học. Chúc mừng mã hóa! :)
/**
* 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());
}
};
}
Và PopupDataSetObserver
được sử dụng trong cài đặt bộ điều hợp.
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);
}
Một điều cuối cùng. Tôi cũng muốn biết ví dụ hoạt động WeakReference
trong ứng dụng Android và tôi có thể tìm thấy một số mẫu trong các ứng dụng mẫu chính thức của nó. Nhưng tôi thực sự không thể hiểu một số cách sử dụng chúng. Ví dụ, các ứng dụng ThreadSample và DisplayingBitmaps sử dụng WeakReference
mã của nó, nhưng sau khi chạy một số thử nghiệm, tôi phát hiện ra rằng phương thức get () không bao giờ trả về null
, vì đối tượng khung nhìn được tham chiếu được tái chế trong bộ điều hợp, thay vào đó là rác được thu thập.
Một số câu trả lời khác có vẻ không đầy đủ hoặc quá dài. Đây là một câu trả lời chung.
Bạn có thể làm các bước sau:
WeakReference
biếnMyClass
có một tài liệu tham khảo yếu 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
có một tài liệu tham khảo mạnh mẽ để 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);
}
}
MyClass
là A vàAnotherClass
được B.WeakReference
là để một lớp khác thực hiện một giao diện. Điều này được thực hiện trong Mẫu Listener / Observer .// allow MyClass to get a weak reference to this class void someMethod() { mMyClass = new MyClass(); mMyClass.someMethod(this); }
??
weakreference
chính đối tượng trong doSomething
chức năng để không bị null
trước khi gọi get
hàm.
Ánh xạ "chuẩn hóa" là nơi bạn giữ một thể hiện của đối tượng trong bộ nhớ và tất cả các đối tượng khác tra cứu trường hợp cụ thể đó thông qua con trỏ hoặc cơ chế somesuch. Đây là nơi mà các tài liệu tham khảo yếu có thể giúp đỡ. Câu trả lời ngắn gọn là các đối tượng WeakReference có thể được sử dụng để tạo con trỏ tới các đối tượng trong hệ thống của bạn trong khi vẫn cho phép các đối tượng đó được thu thập bởi bộ thu gom rác khi chúng vượt ra khỏi phạm vi. Ví dụ: nếu tôi có mã như thế này:
class Registry {
private Set registeredObjects = new HashSet();
public void register(Object object) {
registeredObjects.add( object );
}
}
Bất kỳ đối tượng nào tôi đăng ký sẽ không bao giờ được thu hồi bởi GC vì có một tham chiếu đến nó được lưu trữ trong tập hợp registeredObjects
. Mặt khác, nếu tôi làm điều này:
class Registry {
private Set registeredObjects = new HashSet();
public void register(Object object) {
registeredObjects.add( new WeakReference(object) );
}
}
Sau đó, khi GC muốn lấy lại các đối tượng trong Set, nó sẽ có thể làm như vậy. Bạn có thể sử dụng kỹ thuật này để lưu vào bộ nhớ cache, lập danh mục, v.v ... Xem bên dưới để tham khảo các thảo luận chuyên sâu hơn về GC và bộ nhớ đệm.
Tham chiếu: Người thu gom rác và WeakReference