Skip to content

Commit d0dfd52

Browse files
authored
Merge pull request #271 from microsoft/ardykhalili/fix-memory-leak
[Android] Fix memory leak
2 parents 43512fd + 1c4ac7c commit d0dfd52

File tree

5 files changed

+52
-29
lines changed

5 files changed

+52
-29
lines changed

source/android/adaptivecards/src/main/java/io/adaptivecards/renderer/input/DateInputRenderer.java

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
import android.view.View;
1111
import android.view.ViewGroup;
1212
import android.widget.EditText;
13-
13+
import java.lang.ref.WeakReference;
1414
import java.text.DateFormat;
1515

1616
import io.adaptivecards.objectmodel.BaseCardElement;
@@ -62,7 +62,7 @@ public static DateInputRenderer getInstance()
6262
}
6363

6464
DateInput dateInput = Util.castTo(baseCardElement, DateInput.class);
65-
DateInputHandler dateInputHandler = new DateInputHandler(dateInput, fragmentManager, renderedCard, renderArgs.getContainerCardId());
65+
DateInputHandler dateInputHandler = new DateInputHandler(dateInput, new WeakReference<>(fragmentManager), renderedCard, renderArgs.getContainerCardId());
6666

6767
String dateInputValue = dateInput.GetValue();
6868
String dateString = "";
@@ -102,7 +102,9 @@ public void onClick(View v)
102102
datePickerFragment.setArguments(args);
103103

104104
FragmentManager fm = dateInputHandler.getFragmentManager();
105-
datePickerFragment.show(fm, TITLE);
105+
if (fm != null) {
106+
datePickerFragment.show(fm, TITLE);
107+
}
106108

107109
}
108110
});

source/android/adaptivecards/src/main/java/io/adaptivecards/renderer/input/TimeInputRenderer.java

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
import android.view.ViewGroup;
1212
import android.widget.EditText;
1313

14+
import java.lang.ref.WeakReference;
1415
import java.text.DateFormat;
1516

1617
import io.adaptivecards.objectmodel.BaseCardElement;
@@ -61,8 +62,7 @@ public static TimeInputRenderer getInstance()
6162
}
6263

6364
TimeInput timeInput = Util.castTo(baseCardElement, TimeInput.class);
64-
65-
TimeInputHandler timeInputHandler = new TimeInputHandler(timeInput, fragmentManager, renderedCard, renderArgs.getContainerCardId());
65+
TimeInputHandler timeInputHandler = new TimeInputHandler(timeInput, new WeakReference<>(fragmentManager), renderedCard, renderArgs.getContainerCardId());
6666
String time = "";
6767
String value = timeInput.GetValue();
6868
if (RendererUtil.isValidTime(value) && !value.isEmpty())
@@ -100,7 +100,9 @@ public void onClick(View v)
100100
timePickerFragment.setArguments(args);
101101

102102
FragmentManager fm = timeInputHandler.getFragmentManager();
103-
timePickerFragment.show(fm, TITLE);
103+
if (fm != null) {
104+
timePickerFragment.show(fm, TITLE);
105+
}
104106
}
105107
});
106108

source/android/adaptivecards/src/main/java/io/adaptivecards/renderer/inputhandler/DateInputHandler.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
import io.adaptivecards.renderer.Util;
1212
import io.adaptivecards.renderer.readonly.RendererUtil;
1313

14+
import java.lang.ref.WeakReference;
1415
import java.text.DateFormat;
1516
import java.text.ParseException;
1617
import java.text.SimpleDateFormat;
@@ -19,7 +20,7 @@
1920

2021
public class DateInputHandler extends TextInputHandler
2122
{
22-
public DateInputHandler(BaseInputElement baseInputElement, FragmentManager fragmentManager, RenderedAdaptiveCard renderedAdaptiveCard, long cardId)
23+
public DateInputHandler(BaseInputElement baseInputElement, WeakReference<FragmentManager> fragmentManager, RenderedAdaptiveCard renderedAdaptiveCard, long cardId)
2324
{
2425
super(baseInputElement, renderedAdaptiveCard, cardId);
2526
m_fragmentManager = fragmentManager;
@@ -28,7 +29,7 @@ public DateInputHandler(BaseInputElement baseInputElement, FragmentManager fragm
2829

2930
public FragmentManager getFragmentManager()
3031
{
31-
return m_fragmentManager;
32+
return m_fragmentManager.get();
3233
}
3334

3435
@Override
@@ -129,8 +130,7 @@ public String getDefaultValue() {
129130
return super.getDefaultValue();
130131
}
131132

132-
private FragmentManager m_fragmentManager;
133-
133+
private WeakReference<FragmentManager> m_fragmentManager;
134134
public static final String DATE_FORMAT = "yyyy-MM-dd";
135135
public static DateFormat s_simpleDateFormat = new SimpleDateFormat(DATE_FORMAT);
136136
}

source/android/adaptivecards/src/main/java/io/adaptivecards/renderer/inputhandler/TimeInputHandler.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
import io.adaptivecards.renderer.input.TimeInputRenderer;
1313
import io.adaptivecards.renderer.readonly.RendererUtil;
1414

15+
import java.lang.ref.WeakReference;
1516
import java.text.DateFormat;
1617
import java.text.ParseException;
1718
import java.text.SimpleDateFormat;
@@ -21,15 +22,15 @@
2122

2223
public class TimeInputHandler extends TextInputHandler
2324
{
24-
public TimeInputHandler(BaseInputElement baseInputElement, FragmentManager fragmentManager, RenderedAdaptiveCard renderedAdaptiveCard, long cardId)
25+
public TimeInputHandler(BaseInputElement baseInputElement, WeakReference<FragmentManager> fragmentManager, RenderedAdaptiveCard renderedAdaptiveCard, long cardId)
2526
{
2627
super(baseInputElement, renderedAdaptiveCard, cardId);
2728
m_fragmentManager = fragmentManager;
2829
}
2930

3031
public FragmentManager getFragmentManager()
3132
{
32-
return m_fragmentManager;
33+
return m_fragmentManager.get();
3334
}
3435

3536
@Override
@@ -158,8 +159,7 @@ public String getDefaultValue() {
158159
return super.getDefaultValue();
159160
}
160161

161-
private FragmentManager m_fragmentManager;
162-
162+
private WeakReference<FragmentManager> m_fragmentManager;
163163
public static final String TIME_FORMAT_SUBMIT = "kk:mm";
164164
public static SimpleDateFormat s_simpleDateFormat = new SimpleDateFormat(TIME_FORMAT_SUBMIT);
165165
}

source/android/adaptivecards/src/main/java/io/adaptivecards/renderer/readonly/TextBlockRenderer.java

Lines changed: 34 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
import androidx.core.view.accessibility.AccessibilityNodeInfoCompat;
3131
import androidx.fragment.app.FragmentManager;
3232

33+
import java.lang.ref.WeakReference;
3334
import java.util.HashMap;
3435
import java.util.List;
3536

@@ -219,7 +220,7 @@ else if (action == MotionEvent.ACTION_DOWN)
219220
}
220221
}
221222

222-
private void applyAccessibilityProperties(TextView textView, Context context, RendererUtil.SpecialTextHandleResult textHandleResult)
223+
private void applyAccessibilityProperties(final TextView textView, Context context, RendererUtil.SpecialTextHandleResult textHandleResult)
223224
{
224225
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P)
225226
{
@@ -236,23 +237,41 @@ private void applyAccessibilityProperties(TextView textView, Context context, Re
236237
}
237238
}
238239

239-
AccessibilityManager am = (AccessibilityManager)context.getSystemService(ACCESSIBILITY_SERVICE);
240-
am.addAccessibilityStateChangeListener(new AccessibilityManager.AccessibilityStateChangeListener() {
241-
@Override
242-
public void onAccessibilityStateChanged(boolean b)
243-
{
244-
boolean isTalkBackEnabled = isTalkBackEnabled(am);
245-
if (b && isTalkBackEnabled)
246-
{
247-
textView.setFocusable(true);
248-
}
249-
else
250-
{
251-
textView.setFocusable(false);
240+
final AccessibilityManager am = (AccessibilityManager)context.getSystemService(ACCESSIBILITY_SERVICE);
241+
final WeakReference<TextView> textViewWeakReference = new WeakReference<>(textView);
242+
243+
final AccessibilityManager.AccessibilityStateChangeListener listener = new AccessibilityManager.AccessibilityStateChangeListener() {
244+
public void onAccessibilityStateChanged(boolean b) {
245+
TextView textView = textViewWeakReference.get();
246+
if (textView != null) {
247+
boolean isTalkBackEnabled = TextBlockRenderer.this.isTalkBackEnabled(am);
248+
if (b && isTalkBackEnabled) {
249+
textView.setFocusable(true);
250+
} else {
251+
textView.setFocusable(false);
252+
}
253+
} else {
254+
// TextView is no longer in memory, remove the listener
255+
am.removeAccessibilityStateChangeListener(this);
252256
}
253257
}
258+
};
259+
260+
am.addAccessibilityStateChangeListener(listener);
261+
textView.setFocusable(this.isTalkBackEnabled(am));
262+
263+
textView.addOnAttachStateChangeListener(new View.OnAttachStateChangeListener() {
264+
@Override
265+
public void onViewAttachedToWindow(View v) {
266+
// Nothing to do
267+
}
268+
269+
@Override
270+
public void onViewDetachedFromWindow(View v) {
271+
// When the TextView is detached from the window, remove the listener
272+
am.removeAccessibilityStateChangeListener(listener);
273+
}
254274
});
255-
textView.setFocusable(isTalkBackEnabled(am));
256275
}
257276

258277
@Override

0 commit comments

Comments
 (0)