问题描述
由于recyclerview
,我在内存泄漏方面遇到了麻烦,它说View detached and has parent
在LeakCanary中。我尝试将recyclerview
上的onDestroyView
设置为null,但仍然没有任何反应。下面是我的片段和LeakCanary的堆栈跟踪:
public class CancelledOrdersFragment extends Fragment {
private RecyclerView recyclerView;
private FirebaseFirestore db = FirebaseFirestore.getInstance();
private CancelledOrdersAdapter adapter;
private OrderTransactionsModel model;
public CancelledOrdersFragment() {
}
@Override
public View onCreateView(LayoutInflater inflater,ViewGroup container,Bundle savedInstanceState) {
View itemView = inflater.inflate(R.layout.fragment_cancelled_orders,container,false);
recyclerView = itemView.findViewById(R.id.cancelled_orders_rv);
linearlayoutmanager linearlayoutmanager1 = new linearlayoutmanager(itemView.getContext());
linearlayoutmanager1.setorientation(linearlayoutmanager.VERTICAL);
recyclerView.setLayoutManager(linearlayoutmanager1);
Paper.init(itemView.getContext());
String storeID = Paper.book().read("userid");
Query query = db.collection("Transactions").whereEqualTo("storeID",storeID).whereEqualTo("transactionStatus","cancelled").orderBy("orderTimeout",Query.Direction.DESCENDING);
PagedList.Config Bconfig = new PagedList.Config.Builder()
.setEnablePlaceholders(false)
.setPrefetchdistance(10)
.setPageSize(8)
.build();
FirestorePagingOptions<OrderTransactionsModel> options = new FirestorePagingOptions.Builder<OrderTransactionsModel>()
.setLifecycleOwner(getActivity())
.setQuery(query,Bconfig,snapshot -> {
OrderTransactionsModel transactionsModel = snapshot.toObject(OrderTransactionsModel.class);
String transID = transactionsModel.getTransactionID();
String tranCOde = transactionsModel.getTransactionCode();
double storetotal = transactionsModel.getStoretotal();
HashMap<String,Object> CouponUsed = transactionsModel.getCouponUsed();
HashMap<String,Date> OrderStatus = transactionsModel.getorderStatus();
model = new OrderTransactionsModel(transID,storeID,storetotal,CouponUsed,OrderStatus,tranCOde);
return model;
})
.build();
adapter = new CancelledOrdersAdapter(options);
recyclerView.setAdapter(adapter);
adapter.notifyDataSetChanged();
return itemView;
}
@Override
public void onDestroyView() {
super.onDestroyView();
adapter.stopListening();
recyclerView = null;
}
@Override
public void onViewStateRestored(@Nullable Bundle savedInstanceState) {
super.onViewStateRestored(savedInstanceState);
adapter.startListening();
}
┬───
2020-08-19 16:23:59.404 11647-13298/com.dreamakers.clustore.clustorestore D/LeakCanary: │ GC Root: Local variable in native code
2020-08-19 16:23:59.404 11647-13298/com.dreamakers.clustore.clustorestore D/LeakCanary: │
2020-08-19 16:23:59.404 11647-13298/com.dreamakers.clustore.clustorestore D/LeakCanary: ├─ android.net.ConnectivityThread instance
2020-08-19 16:23:59.404 11647-13298/com.dreamakers.clustore.clustorestore D/LeakCanary: │ Leaking: NO (PathClassLoader↓ is not leaking)
2020-08-19 16:23:59.404 11647-13298/com.dreamakers.clustore.clustorestore D/LeakCanary: │ Thread name: 'ConnectivityThread'
2020-08-19 16:23:59.404 11647-13298/com.dreamakers.clustore.clustorestore D/LeakCanary: │ ↓ ConnectivityThread.contextClassLoader
2020-08-19 16:23:59.404 11647-13298/com.dreamakers.clustore.clustorestore D/LeakCanary: ├─ dalvik.system.PathClassLoader instance
2020-08-19 16:23:59.404 11647-13298/com.dreamakers.clustore.clustorestore D/LeakCanary: │ Leaking: NO (InternalLeakCanary↓ is not leaking and A ClassLoader is never leaking)
2020-08-19 16:23:59.404 11647-13298/com.dreamakers.clustore.clustorestore D/LeakCanary: │ ↓ PathClassLoader.runtimeInternalObjects
2020-08-19 16:23:59.404 11647-13298/com.dreamakers.clustore.clustorestore D/LeakCanary: ├─ java.lang.Object[] array
2020-08-19 16:23:59.404 11647-13298/com.dreamakers.clustore.clustorestore D/LeakCanary: │ Leaking: NO (InternalLeakCanary↓ is not leaking)
2020-08-19 16:23:59.404 11647-13298/com.dreamakers.clustore.clustorestore D/LeakCanary: │ ↓ Object[].[1614]
2020-08-19 16:23:59.404 11647-13298/com.dreamakers.clustore.clustorestore D/LeakCanary: ├─ leakcanary.internal.InternalLeakCanary class
2020-08-19 16:23:59.404 11647-13298/com.dreamakers.clustore.clustorestore D/LeakCanary: │ Leaking: NO (OrdersActivity↓ is not leaking and a class is never leaking)
2020-08-19 16:23:59.404 11647-13298/com.dreamakers.clustore.clustorestore D/LeakCanary: │ ↓ static InternalLeakCanary.resumedActivity
2020-08-19 16:23:59.404 11647-13298/com.dreamakers.clustore.clustorestore D/LeakCanary: ├─ com.dreamakers.clustore.clustorestore.Activity.OrdersActivity instance
2020-08-19 16:23:59.404 11647-13298/com.dreamakers.clustore.clustorestore D/LeakCanary: │ Leaking: NO (Activity#mDestroyed is false)
2020-08-19 16:23:59.404 11647-13298/com.dreamakers.clustore.clustorestore D/LeakCanary: │ ↓ OrdersActivity.mLifecycleRegistry
2020-08-19 16:23:59.404 11647-13298/com.dreamakers.clustore.clustorestore D/LeakCanary: │ ~~~~~~~~~~~~~~~~~~
2020-08-19 16:23:59.404 11647-13298/com.dreamakers.clustore.clustorestore D/LeakCanary: ├─ androidx.lifecycle.LifecycleRegistry instance
2020-08-19 16:23:59.404 11647-13298/com.dreamakers.clustore.clustorestore D/LeakCanary: │ Leaking: UNKNowN
2020-08-19 16:23:59.404 11647-13298/com.dreamakers.clustore.clustorestore D/LeakCanary: │ ↓ LifecycleRegistry.mObserverMap
2020-08-19 16:23:59.404 11647-13298/com.dreamakers.clustore.clustorestore D/LeakCanary: │ ~~~~~~~~~~~~
2020-08-19 16:23:59.404 11647-13298/com.dreamakers.clustore.clustorestore D/LeakCanary: ├─ androidx.arch.core.internal.FastSafeIterableMap instance
2020-08-19 16:23:59.404 11647-13298/com.dreamakers.clustore.clustorestore D/LeakCanary: │ Leaking: UNKNowN
2020-08-19 16:23:59.404 11647-13298/com.dreamakers.clustore.clustorestore D/LeakCanary: │ ↓ FastSafeIterableMap.mEnd
2020-08-19 16:23:59.404 11647-13298/com.dreamakers.clustore.clustorestore D/LeakCanary: │ ~~~~
2020-08-19 16:23:59.404 11647-13298/com.dreamakers.clustore.clustorestore D/LeakCanary: ├─ androidx.arch.core.internal.SafeIterableMap$Entry instance
2020-08-19 16:23:59.404 11647-13298/com.dreamakers.clustore.clustorestore D/LeakCanary: │ Leaking: UNKNowN
2020-08-19 16:23:59.404 11647-13298/com.dreamakers.clustore.clustorestore D/LeakCanary: │ ↓ SafeIterableMap$Entry.mKey
2020-08-19 16:23:59.404 11647-13298/com.dreamakers.clustore.clustorestore D/LeakCanary: │ ~~~~
2020-08-19 16:23:59.404 11647-13298/com.dreamakers.clustore.clustorestore D/LeakCanary: ├─ com.dreamakers.clustore.clustorestore.Adapter.CancelledOrdersAdapter instance
2020-08-19 16:23:59.404 11647-13298/com.dreamakers.clustore.clustorestore D/LeakCanary: │ Leaking: UNKNowN
2020-08-19 16:23:59.404 11647-13298/com.dreamakers.clustore.clustorestore D/LeakCanary: │ ↓ CancelledOrdersAdapter.mObservable
2020-08-19 16:23:59.404 11647-13298/com.dreamakers.clustore.clustorestore D/LeakCanary: │ ~~~~~~~~~~~
2020-08-19 16:23:59.404 11647-13298/com.dreamakers.clustore.clustorestore D/LeakCanary: ├─ androidx.recyclerview.widget.RecyclerView$AdapterDataObservable instance
2020-08-19 16:23:59.404 11647-13298/com.dreamakers.clustore.clustorestore D/LeakCanary: │ Leaking: UNKNowN
2020-08-19 16:23:59.404 11647-13298/com.dreamakers.clustore.clustorestore D/LeakCanary: │ ↓ RecyclerView$AdapterDataObservable.mObservers
2020-08-19 16:23:59.404 11647-13298/com.dreamakers.clustore.clustorestore D/LeakCanary: │ ~~~~~~~~~~
2020-08-19 16:23:59.404 11647-13298/com.dreamakers.clustore.clustorestore D/LeakCanary: ├─ java.util.ArrayList instance
2020-08-19 16:23:59.404 11647-13298/com.dreamakers.clustore.clustorestore D/LeakCanary: │ Leaking: UNKNowN
2020-08-19 16:23:59.404 11647-13298/com.dreamakers.clustore.clustorestore D/LeakCanary: │ ↓ ArrayList.elementData
2020-08-19 16:23:59.404 11647-13298/com.dreamakers.clustore.clustorestore D/LeakCanary: │ ~~~~~~~~~~~
2020-08-19 16:23:59.404 11647-13298/com.dreamakers.clustore.clustorestore D/LeakCanary: ├─ java.lang.Object[] array
2020-08-19 16:23:59.404 11647-13298/com.dreamakers.clustore.clustorestore D/LeakCanary: │ Leaking: UNKNowN
2020-08-19 16:23:59.404 11647-13298/com.dreamakers.clustore.clustorestore D/LeakCanary: │ ↓ Object[].[0]
2020-08-19 16:23:59.404 11647-13298/com.dreamakers.clustore.clustorestore D/LeakCanary: │ ~~~
2020-08-19 16:23:59.404 11647-13298/com.dreamakers.clustore.clustorestore D/LeakCanary: ├─ androidx.recyclerview.widget.RecyclerView$RecyclerViewDataObserver instance
2020-08-19 16:23:59.405 11647-13298/com.dreamakers.clustore.clustorestore D/LeakCanary: │ Leaking: UNKNowN
2020-08-19 16:23:59.405 11647-13298/com.dreamakers.clustore.clustorestore D/LeakCanary: │ ↓ RecyclerView$RecyclerViewDataObserver.this$0
2020-08-19 16:23:59.405 11647-13298/com.dreamakers.clustore.clustorestore D/LeakCanary: │ ~~~~~~
2020-08-19 16:23:59.405 11647-13298/com.dreamakers.clustore.clustorestore D/LeakCanary: ├─ androidx.recyclerview.widget.RecyclerView instance
2020-08-19 16:23:59.405 11647-13298/com.dreamakers.clustore.clustorestore D/LeakCanary: │ Leaking: YES (View detached and has parent)
2020-08-19 16:23:59.405 11647-13298/com.dreamakers.clustore.clustorestore D/LeakCanary: │ mContext instance of com.dreamakers.clustore.clustorestore.Activity.OrdersActivity with mDestroyed = false
2020-08-19 16:23:59.405 11647-13298/com.dreamakers.clustore.clustorestore D/LeakCanary: │ View#mParent is set
2020-08-19 16:23:59.405 11647-13298/com.dreamakers.clustore.clustorestore D/LeakCanary: │ View#mAttachInfo is null (view detached)
2020-08-19 16:23:59.405 11647-13298/com.dreamakers.clustore.clustorestore D/LeakCanary: │ View.mID = R.id.cancelled_orders_rv
2020-08-19 16:23:59.405 11647-13298/com.dreamakers.clustore.clustorestore D/LeakCanary: │ View.mWindowAttachCount = 1
2020-08-19 16:23:59.405 11647-13298/com.dreamakers.clustore.clustorestore D/LeakCanary: │ ↓ RecyclerView.mParent
2020-08-19 16:23:59.405 11647-13298/com.dreamakers.clustore.clustorestore D/LeakCanary: ╰→ android.widget.FrameLayout instance
2020-08-19 16:23:59.405 11647-13298/com.dreamakers.clustore.clustorestore D/LeakCanary: Leaking: YES (ObjectWatcher was watching this because com.dreamakers.clustore.clustorestore.Activity.CancelledOrdersFragment received Fragment#onDestroyView() callback (references to its views should be cleared to prevent leaks))
2020-08-19 16:23:59.405 11647-13298/com.dreamakers.clustore.clustorestore D/LeakCanary: key = 1bb796b4-4c87-4320-b90a-a348a14e616e
2020-08-19 16:23:59.405 11647-13298/com.dreamakers.clustore.clustorestore D/LeakCanary: watchDurationMillis = 8633
2020-08-19 16:23:59.405 11647-13298/com.dreamakers.clustore.clustorestore D/LeakCanary: retainedDurationMillis = 3631
2020-08-19 16:23:59.405 11647-13298/com.dreamakers.clustore.clustorestore D/LeakCanary: mContext instance of com.dreamakers.clustore.clustorestore.Activity.OrdersActivity with mDestroyed = false
2020-08-19 16:23:59.405 11647-13298/com.dreamakers.clustore.clustorestore D/LeakCanary: View#mParent is null
2020-08-19 16:23:59.405 11647-13298/com.dreamakers.clustore.clustorestore D/LeakCanary: View#mAttachInfo is null (view detached)
2020-08-19 16:23:59.405 11647-13298/com.dreamakers.clustore.clustorestore D/LeakCanary: View.mWindowAttachCount = 1
解决方法
泄漏跟踪表明OrdersActivity仍然有效(没有被破坏,一切都很好),并且其生命周期注册表中有一个包含CancelledOrdersAdapter的mObserverMap。
根据代码,似乎CancelledOrdersAdapter和R.id.cancelled_orders_rv RecyclerView的生命周期应该保持一致。
但是,当拆开回收台视图时,CancelledOrdersAdapter将保留在内存中,因为它注册为活动生命周期的观察者(此时该活动并未被破坏)。该修复程序可能会将CancelledOrdersAdapter注册为片段视图生命周期的观察者,即Fragment.viewLifecycleOwner