ฉันเป็นนักพัฒนา java มา 2 ปีแล้ว
แต่ฉันไม่เคยเขียน WeakReference ในรหัสของฉัน วิธีใช้ WeakReference เพื่อทำให้แอปพลิเคชันของฉันมีประสิทธิภาพมากขึ้นโดยเฉพาะแอปพลิเคชัน Android
ฉันเป็นนักพัฒนา java มา 2 ปีแล้ว
แต่ฉันไม่เคยเขียน WeakReference ในรหัสของฉัน วิธีใช้ WeakReference เพื่อทำให้แอปพลิเคชันของฉันมีประสิทธิภาพมากขึ้นโดยเฉพาะแอปพลิเคชัน Android
คำตอบ:
การใช้งานWeakReference
ใน Android นั้นไม่แตกต่างไปจากการใช้งานใน Java แบบเก่า นี่คือคำแนะนำที่ดีซึ่งจะช่วยให้คำอธิบายรายละเอียด: ความเข้าใจอ้างอิงอ่อนแอ
คุณควรคิดถึงการใช้สิ่งใดสิ่งหนึ่งเมื่อคุณต้องการการอ้างอิงไปยังวัตถุ แต่คุณไม่ต้องการการอ้างอิงนั้นเพื่อปกป้องวัตถุจากตัวรวบรวมขยะ ตัวอย่างคลาสสิกคือแคชที่คุณต้องการรวบรวมขยะเมื่อการใช้หน่วยความจำสูงเกินไป (มักใช้กับWeakHashMap
)
ให้แน่ใจว่าได้ตรวจสอบSoftReference
และPhantomReference
เช่นกัน
แก้ไข: Tom ทำให้เกิดความกังวลเกี่ยวกับการนำแคชWeakHashMap
ไปใช้ นี่คือบทความที่จัดทำปัญหา: WeakHashMap ไม่ใช่แคช!
ทอมถูกต้องที่มีการร้องเรียนเกี่ยวกับประสิทธิภาพของ Netbeans ที่ไม่ดีเนื่องจากการWeakHashMap
แคช
ผมยังคิดว่ามันจะเป็นประสบการณ์การเรียนรู้ที่ดีที่จะใช้กับแคชแล้วเปรียบเทียบกับแคชมือรีดของคุณเองดำเนินการกับWeakHashMap
SoftReference
ในโลกแห่งความจริงที่คุณอาจจะไม่ใช้อย่างใดอย่างหนึ่งของการแก้ปัญหาเหล่านี้เพราะมันทำให้รู้สึกมากขึ้นในการใช้ห้องสมุดของบุคคลที่ 3 เช่นApache JCS
WeakHashMap
ใช้เป็นแคชร้ายแรง สามารถลบรายการได้ทันทีที่สร้างขึ้น สิ่งนี้อาจจะไม่เกิดขึ้นเมื่อคุณทำการทดสอบ แต่อาจใช้งานได้ดี จากการสังเกตเห็น NetBeans นั้นสามารถหยุดการทำงานของ CPU ได้อย่างมีประสิทธิภาพ 100%
WeakHashMap
แม้ว่าคุณจะเป็นที่ถูกต้องว่ามันเป็นทางเลือกที่ดี;)
[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);
}
}
}
}
มันบอกว่า,
WeakReference เพื่อให้แน่ใจ ImageView ที่ AsyncTask ไม่ได้ป้องกัน ImageView และสิ่งที่อ้างอิงจากการเก็บขยะ ไม่มีการรับประกัน ImageView จะยังคงอยู่เมื่องานเสร็จดังนั้นคุณต้องตรวจสอบการอ้างอิงใน onPostExecute () ImageView อาจไม่มีอยู่อีกต่อไปตัวอย่างเช่นผู้ใช้นำทางออกจากกิจกรรมหรือหากมีการเปลี่ยนแปลงการกำหนดค่าเกิดขึ้นก่อนที่งานจะเสร็จสิ้น
การเข้ารหัสที่มีความสุข!
[แก้ไข]ผมพบว่าเป็นตัวอย่างที่ดีจริงๆWeakReference
จากFacebook-หุ่นยนต์ SDK คลาสToolTipPopupเป็นเพียงคลาสวิดเจ็ตธรรมดาที่แสดงคำแนะนำเครื่องมือเหนือมุมมองจุดยึด ฉันจับภาพหน้าจอ
ชั้นเรียนง่ายมาก (ประมาณ 200 บรรทัด) และควรค่าแก่การดู ในคลาสนั้นWeakReference
คลาสถูกใช้เพื่อเก็บการอ้างอิงถึงมุมมองจุดยึดซึ่งเหมาะสมอย่างยิ่งเพราะมันเป็นไปได้ที่สมอมุมมองจะถูกเก็บขยะแม้ในกรณีที่อินสแตนซ์คำแนะนำเครื่องมือมีชีวิตยาวนานกว่ามุมมองจุดยึด
การเข้ารหัสที่มีความสุข! :)
ให้ฉันแบ่งปันตัวอย่างการทำงานของWeakReference
ชั้นเรียน มันเป็นข้อมูลโค้ดเล็กน้อยจาก Android 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
เพราะมุมมองวัตถุอ้างอิงรีไซเคิลในอะแดปเตอร์แทนแล้วเก็บขยะ
คำตอบอื่น ๆ บางส่วนดูเหมือนไม่สมบูรณ์หรือยาวเกินไป นี่คือคำตอบทั่วไป
คุณสามารถทำตามขั้นตอนต่อไปนี้:
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);
}
}
MyClass
คือ A และAnotherClass
เป็น B.WeakReference
คือให้คลาสอื่นใช้อินเตอร์เฟส ซึ่งจะดำเนินการในรูปแบบฟัง / สังเกตการณ์// allow MyClass to get a weak reference to this class void someMethod() { mMyClass = new MyClass(); mMyClass.someMethod(this); }
??
weakreference
วัตถุในdoSomething
ฟังก์ชั่นnull
ก่อนว่าจะไม่เรียกget
ใช้ฟังก์ชัน
การแมป "canonicalized" เป็นที่ที่คุณเก็บอินสแตนซ์หนึ่งของวัตถุที่เป็นปัญหาในหน่วยความจำและอื่น ๆ ทั้งหมดค้นหาอินสแตนซ์นั้นผ่านพอยน์เตอร์หรือกลไกบางอย่าง ที่นี่การอ้างอิงที่อ่อนแอสามารถช่วยได้ คำตอบสั้น ๆ คือสามารถใช้วัตถุ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 และการแคช