Android - Memory leak with popup window in Recyclerview - android

I'm having trouble with the following error displaying in my app:
"E/WindowManager: android.view.WindowLeaked: Activity com.awt.myapp.MyList has leaked window android.widget.PopupWindow$PopupDecorView{84fdb1f V.E...... .......D 0,0-369,120} that was originally added here..."
Basically I've got a recyclerview and in the adapter I have a bunch of textviews in each row and am binding click listeners to them, as clicking one of these textviews brings up a popup window. The problem is if I hit the Android back button while a popup is still visible the above error appears.
I understand that in my activity that holds the recyclerview I can add an 'onBackPressed()' method, but from here I'm not sure how to get a reference to any of the popup windows within the adapter (and close it at this stage) as I believe this is what I need to do.
Below is my click listener code, I've experimented with some options and having setFocusable just causes the back button to stop working so not sure if that's needed.
tv.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View moreInfoView) {
myPopupWindow.setBackgroundDrawable(new ColorDrawable());
//myPopupWindow.setFocusable(true);
myPopupWindow.setTouchable(false); // Ignores taps
myPopupWindow.setOutsideTouchable(true); // Disappear when tapping anywhere on screen
int position = -tv.getHeight();
myPopupWindow.showAsDropDown(tv, 0, position);
((MyList) context).onToggleMoreInfo("show");
myPopupWindow.setOnDismissListener(new PopupWindow.OnDismissListener() {
#Override
public void onDismiss() {
((MyList) context).onToggleMoreInfo("hide");
}
});
}
});
Hopefully this makes sense, if you need any more info let me know. Any advice would be appreciated.

If you create a listener on your adapter that implements the activity and calls it when you click on the item, you can export popup window logic to activity and override on back pressed to dimiss it.

Related

Keyboard and Focus issue in PopupWindow

I am showing a popup window , if i initialize it as follows :
popupWindow.setBackgroundDrawable(new BitmapDrawable());
popupWindow.setFocusable(false);
And
#Override
public void onBackPressed() {
if (popupWindow.isShowing()) {
showConfirmationDialogForExit();
} else {
super.onBackPressed();
}
}
The Keyboard in my PopupWindow doesn't open ( the popupWindow has EditText ).
Also i have kept a dialog box to confirm the exit of the screen on Back Press which works.
Now opposite to this , if i keep
popupWindow.setFocusable(true);
The keyboard opens and works but the onBackPressed() doesn't check the
popupWindow.isShowing()
here my question is , i want to achieve the backpress check when the popup window is showing and also the keyboard needs to be worked when click on the EditText on that popupWindow.
The solutions i have gone through suggests me to keep
popupWindow.setFocusable(true);
but i am not be able to achieve the goals i am looking for.
Please guide me.
try
popWindow.setFocusable(true);
popWindow.update();
This updates the state of the popup window, if it is currently being displayed, from the currently set state.
If that don't work for you for some reason, you can always just set a local flag when you open the popWindow....
boolean popupshowing = true;
And then use that to check if it is open or not. (I agree it isn't the most elegant solution)

Android: Z-Order with a screen-wide clickblocker-view

Edit: Solved. The problem disappeared when I made all my custom views override Button instead of View.
I'm trying to programmatically create a screen-sized invisible view which should capture all click events, thereby blocking all underlying elements. But I'm having some trouble.
The intended goal is that when the user clicks a certain button, a menu is created. While this menu is up, the other buttons that were on the page should no longer function. Clicking on the menu should make stuff happen, clicking anywhere else should make the menu disappear and make the other elements work again.
I've managed to create the screen wide view just fine, and it captures clicks and destroys the menu whenever the user clicks a point that is not already covered by a button. When the user does click on a spot that contains a button however, only the button's onclickevent is handled, and not that of my clickblocker. It should be the other way around.
This leads me to think it's a z-order problem (but not 100% sure).
Unfortunately I'm trying to target older versions, which don't have support for view.setZ(), and view.bringToFront() doesn't appear to do what I want it to do.
Here's the code for the viewblocker:
public class ClickBlockerView extends View{
public ClickBlockerView(Context context) {
super(context);
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
setMeasuredDimension(C.GetWindowWidth(getContext()), C.GetWindowHeight(getContext()));
}
public static ClickBlockerView CreateClickBlocker(Context context){
ClickBlockerView c = new ClickBlockerView(context);
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
c.setLayoutParams(params);
c.setId(R.id.clickBlocker);
c.setClickable(true);
return c;
}
}
And this is how I'm calling it (from inside another view):
private void createMenuAndClickblocker(){
ClickBlockerView clickblocker = ClickBlockerView.CreateClickBlocker(getContext());
clickblocker.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
destroyMenu();
}
});
((RelativeLayout) this.getParent()).addView(clickblocker);
clickblocker.bringToFront();
createMenu();
requestLayout();
}
Does anyone have some idea how to fix this? Other solutions to the problem are welcome too. I'd rather not have to use xml though (it would have to be added to every activity)
Update:
Apparently, the z-ordering goes fine with spinners and checkboxes, but not with buttons and my custom views. Odd...
Update 2:
When drawn, the shape is shown to correctly fill up the screen, but it is also drawn below the other custom views, even though it is created later and brought to the front.
Strangely enough, the click functionality has meanwhile completely stopped functioning, even though I didn't change anything in the code for this clickblocker.

How to delegate touch events on both popup window and activity android

I have an activity which is having two buttons and a popup window.By click a button popup will display. I want to handle touch events in both popup window and activity.
In the below image i want to handle Ok button click with out dismiss the popup widow. At the same time i need dismiss button event as well.
I have tried
popWindow.setTouchable(true); then activity events are not working.
popWindow.setTouchable(false); then popup window events are not working.
Please see the image for reference.
Thanks in advance.
You can achieve this using WindowManager.
private void popUp(View yourPopUpView,WindowManager.LayoutParams params){
WindowManager manager = (WindowManager)getSystemService(WINDOW_SERVICE);
manager.addView(yourPopUpView,params);
}
remove same view using
private void removePopUp(View yourPopUpView){
WindowManager manager = (WindowManager)getSystemService(WINDOW_SERVICE);
manager.removeView(yourPopUpView);
}
but don't forget to remove that view onResume of your activity. B'coz it will remain after destroy of your activity also..
Hope this helps...

onClick launches Activity incorrectly (in 2.3.6)

I'm working on an interface that provides a set of multiple Button objects, each of which has attached the same OnClickListener. When said Buttons are clicked, they should launch an Activity, as specified in onClick.
Here is my code for reference:
public class Calcs extends SherlockFragment {
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
// ...
CalcLoader buttonListener = new CalcLoader(getActivity());
LinearLayout buttons = (LinearLayout) v.findViewById(R.id.calculatorlist); // v is the inflated View
for (int i = 0; i < buttons.getChildCount(); i++) {
View b = buttons.getChildAt(i);
if (b instanceof Button) {
((Button) b).setOnClickListener(buttonListener);
}
}
// Test Code: Location 1
Intent i = new Intent(getActivity(), MyCalcActivity.class);
getActivity().startActivity(i);
// ...
}
private class CalcLoader implements OnClickListener {
private Activity mOwner;
public CalcLoader(Activity owner) {
mOwner = owner;
// Test Code: Location 2
Intent i = new Intent(mOwner, MyCalcActivity.class);
mOwner.startActivity(i);
}
public void onClick(View v) {
if (v instanceof Button) {
// Actual Code: Location 3
Intent i = new Intent(mOwner, MyCalcActivity.class);
mOwner.startActivity(i);
}
}
}
}
Despite this, however, I'm getting some odd behavior. In the above code, I've placed some startActivity tests, labelled locations 1 and 2. In both cases, the Activity launches correctly, and all is well!
However, at location 3, where the working code should execute, I get some strange behavior from the launched Activity:
At first, the Activity is launched just fine. It displays a single text field and it is focused, with the soft keyboard coming up. This is correct.
Now, when I click the back button, the keyboard closes. This is correct.
Click back again, and the field loses focus. This should NOT happen. Instead, the Activity SHOULD close and return to the previous one.
Click back again, and the entire app closes (instead of returning to the previous Activity). Obviously, this should NOT happen.
To reiterate, when the Activity is started from location 1 or 2, everything functions correctly; the back stack is correct and returns to the initial Activity properly.
What is going wrong here? Why, when I start my Activity from onClick, does it fail, while it works from any other location?
Update: Saving the Intent in the constructor and reusing it in the onClick method produces the same glitched result, as does starting the Activity from the UI thread.
Second update: Making the text field unfocusable had no effect on the glitch; the back button still closed the app. Additionally, running in the 2.3.3 emulator had the same result. Oddly, though, after the second back button press (the text field losing focus), if you wait ~3 seconds, the Activity closes and returns to the main one.
Third update: No key events (onKeyDown or onBackPressed) are fired for the back button that takes focus from the text field. Additionally, if you interact with the Activity after the text field loses focus, it shows the animation of loading a new Activity of the same type, but the glitch is present here as well.
This appears to be an OS-level issue, found in Android 2.2 (API 8), 2.3.1 (API 9), and 2.3.3 (API 10). Eclair (API 7), and APIs 11+ do not have this issue. At this point, I believe I'm looking for some kind of workaround...
Turns out my issue was not caused by something I detailed in my original post, so I apologize for that.
The issue was caused by a SurfaceView item on a tab unrelated to the tab I was testing on. After rebuilding the tabs and layouts from the ground up (and building each time), I discovered the lag-back-glitch was only caused when a SurfaceView was present in a non-focused tab.
I finally found that I was not the only one with this issue.
To solve:
Created an onPause method in the main Activity. In here, I destroy the SurfaceView using container.removeView(..);.
Created an onResume method in the main Activity. In here, I inflate the SurfaceView from a new XML file containing ONLY the SurfaceView item, and add it to the original container.
Lastly, implemented a android.view.SurfaceHolder.Callback in the SurfaceView to erase the contents of the surface before it is removed.
It stumps me that this happens only on APIs 8-10, but I'm glad it's solved now. Kudos to everyone that offered their assistance!

Is it possible to chain event listeners in Android?

I have an activity which contains QuickContactBadges. I'm looking for a way to either chain event listeners on the QuickContactBadge, or to call the default listener from within an override.
Specifically, what I am looking to do is have the QuickContactBadge, when clicked to show the QuickContact card, and then to setResult and finish, to close my activity.
So either I want to add a second listener to the badge in addition to the default one, or implement something like the following:
bdg.setOnClickListener(new View.OnClickListener() {
public void onClick(View view) {
QuickContactBadge bdg = (QuickContactBadge) view;
bdg.base.onClick(); // PSEUDO-CODE LINE
setResult(RESULT_CANCELED, null);
finish();
}
});
Are either of these methods possible, or is there some other way I should be doing this?
Well, the answer to what I was trying to do was not actually in an event listener at all.
The key to getting my activity to close when the QuickBadge is clicked was to add android:noHistory="true" to the activity definition in the application manifest file.
Though, it would still be interesting to know yes/no if there is a way to chain event listeners.

Categories

Resources