RecyclerView重复点击商品弹出Dialog触发‘System services not available...’错误求助
Hey there, let's break down this frustrating crash you're hitting! That System services not available to Activities before onCreate() error almost always ties to invalid Context handling when creating your custom Dialog—especially when reusing or holding onto stale references between clicks. Here's how to diagnose and fix it:
Common Root Causes
The issue happens because your second click is trying to use a Context that's either:
- Already destroyed (from a previous Dialog instance that wasn't properly cleaned up)
- Not tied to a currently active Activity lifecycle state
- Using Application Context instead of Activity Context (Dialogs require an Activity to attach their window to)
Step-by-Step Solutions
1. Always Use a Valid Activity Context for Dialogs
Never use Application Context to create a Dialog—they need an active Activity to bind their window to. In your RecyclerView Adapter's click handler, grab the Context directly from the ViewHolder's itemView, and safely cast it to your Activity type:
holder.itemView.setOnClickListener { // Safely get the active Activity from the item's context val currentActivity = holder.itemView.context as? AppCompatActivity currentActivity?.let { activity -> // Create a NEW Dialog instance with the valid Activity context val quantityDialog = CustomQuantityDialog(activity) // Set up your Dialog listeners/data here quantityDialog.show() } }
Using as? prevents crashes if the Context isn't an Activity (though this shouldn't happen in a typical RecyclerView setup).
2. Avoid Holding Stale Context References
If your Adapter stores an Activity reference as a member variable, wrap it in a WeakReference to prevent memory leaks and avoid holding onto a destroyed Activity:
class ProductAdapter(private val activityRef: WeakReference<AppCompatActivity>) : RecyclerView.Adapter<ProductViewHolder>() { override fun onBindViewHolder(holder: ProductViewHolder, position: Int) { holder.itemView.setOnClickListener { // Check if the Activity is still valid before using it activityRef.get()?.takeIf { !it.isFinishing && !it.isDestroyed }?.let { activity -> val dialog = CustomQuantityDialog(activity) dialog.show() } } } }
When initializing the Adapter, pass in WeakReference(requireActivity()) (from a Fragment) or WeakReference(this) (from an Activity).
3. Don't Reuse Old Dialog Instances
Never store a Dialog as a member variable in your Adapter or ViewHolder. Each click should create a fresh Dialog instance with the current valid Context—reusing old instances can lead to them being tied to a destroyed Activity.
4. Validate Activity State Before Showing Dialogs
Add a quick check to ensure the Activity is still active before attempting to show your Dialog:
currentActivity?.let { activity -> if (!activity.isFinishing && !activity.isDestroyed) { val dialog = CustomQuantityDialog(activity) dialog.show() } }
This prevents attempts to show a Dialog when the Activity is already in the process of being destroyed.
Why This Works
Dialogs rely on system services like WindowManager, which can only be accessed when an Activity is in a valid lifecycle state (between onCreate() and onDestroy()). By ensuring you're always using a fresh, active Activity Context for each Dialog, you eliminate the stale reference that's causing the crash on the second click.
内容的提问来源于stack exchange,提问作者Demonic218

