Skip to content

Commit

Permalink
Fix naXa777#5 Activity has leaked ServiceConnection that was original…
Browse files Browse the repository at this point in the history
…ly bound here
  • Loading branch information
naXa777 committed Sep 9, 2018
1 parent 649592f commit dcd437e
Show file tree
Hide file tree
Showing 3 changed files with 86 additions and 44 deletions.
2 changes: 1 addition & 1 deletion app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,8 @@
</activity>
<activity
android:name=".activities.SettingsActivity"
android:label="@string/action_settings"
android:exported="false"
android:label="@string/action_settings"
android:parentActivityName=".activities.MainActivity">
<meta-data
android:name="android.support.PARENT_ACTIVITY"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import android.content.pm.PackageManager;
import android.graphics.ColorFilter;
import android.graphics.LightingColorFilter;
import android.media.AudioAttributes;
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.os.Build;
Expand Down Expand Up @@ -191,8 +192,6 @@ public void onStopTrackingTouch(SeekBar seekBar) {
}
});

attachHeadsetListener();

mPlayButton = view.findViewById(R.id.fab_play);
mPlayButton.setOnClickListener(new OnSingleClickListener() {
@Override
Expand Down Expand Up @@ -221,18 +220,17 @@ public void onSingleClick(View v) {
/**
* Attach a HeadsetListener to respond to headset events.
*/
private void attachHeadsetListener() {
private void attachHeadsetListener(Context context) {
mHeadsetListener = new HeadsetListener(this);
IntentFilter filter = new IntentFilter();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
filter.addAction(ACTION_HEADSET_PLUG);
}
filter.addAction(ACTION_AUDIO_BECOMING_NOISY);
final Context context = getContext();
if (context != null) {
context.registerReceiver(mHeadsetListener, filter);
} else {
Log.wtf(LOG_TAG, "attachHeadsetListener(): getContext() returned null.");
Log.wtf(LOG_TAG, "attachHeadsetListener(): context is null.");
}
}

Expand All @@ -244,7 +242,7 @@ private void detachHeadsetListener() {
if (context != null) {
context.unregisterReceiver(mHeadsetListener);
} else {
Log.wtf(LOG_TAG, "attachHeadsetListener(): getContext() returned null.");
Log.wtf(LOG_TAG, "detachHeadsetListener(): getContext() returned null.");
}
mHeadsetListener = null;
}
Expand Down Expand Up @@ -282,6 +280,26 @@ public void onDestroy() {
if (mMediaPlayer != null) {
stopPlaying();
}
}

/**
* @param context a reference to the newly created Activity after each configuration change.
*/
@Override
public void onAttach(Context context) {
super.onAttach(context);
if (mHeadsetListener == null) {
attachHeadsetListener(context);
}
}

/**
* Set the MediaPlayer and Headset listener to null so we don't accidentally
* leak the Activity instance.
*/
@Override
public void onDetach() {
super.onDetach();
if (mHeadsetListener != null) {
detachHeadsetListener();
}
Expand Down Expand Up @@ -375,7 +393,15 @@ private void prepareMediaPlayerFromPoint(int progress) {

try {
mMediaPlayer.setDataSource(item.getFilePath());
mMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
final AudioAttributes attributes = new AudioAttributes.Builder()
.setUsage(AudioAttributes.USAGE_MEDIA)
.setContentType(AudioAttributes.CONTENT_TYPE_UNKNOWN)
.build();
mMediaPlayer.setAudioAttributes(attributes);
} else {
mMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
}
mMediaPlayer.prepare();
mSeekBar.setMax(mMediaPlayer.getDuration());
mMediaPlayer.seekTo(progress);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
import java.io.File;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentActivity;
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
Expand Down Expand Up @@ -68,6 +69,8 @@ public class RecordFragment extends Fragment {
private Chronometer mChronometer = null;
long timeWhenPaused = 0; //stores time when user clicks pause button

// Defines callbacks for service binding, passed to bindService()
private ServiceConnection mConnection;
private RecordingService mRecordingService;
private BroadcastReceiver mMessageReceiver = null;

Expand All @@ -88,7 +91,6 @@ public static RecordFragment newInstance() {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
tryBindService();
mMessageReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
Expand All @@ -105,19 +107,58 @@ public void onReceive(Context context, Intent intent) {
};
}

private void tryBindService() {
if (mRecordingService == null) {
final Context context = getContext();
if (context == null)
return;
final Intent intent = new Intent(context, RecordingService.class);
@Override
public void onAttach(Context context) {
super.onAttach(context);
final Intent intent = new Intent(context, RecordingService.class);
tryBindService(context, intent);
}

@Override
public void onDetach() {
super.onDetach();
tryUnbindService(getContext());
}

private void tryBindService(Context context, Intent intent) {
if (mConnection == null) {
mConnection = new ServiceConnection() {

@Override
public void onServiceConnected(ComponentName className, IBinder service) {
// We've bound to LocalService, cast the IBinder and get LocalService instance
RecordingService.LocalBinder binder = (RecordingService.LocalBinder) service;
mRecordingService = binder.getService();
Log.i(LOG_TAG, "RecordFragment ServiceConnection#onServiceConnected");

long chronometerTime = SystemClock.elapsedRealtime() - mRecordingService.getTotalDurationMillis();
updateUI(mRecordingService.getState(), chronometerTime);
}

@Override
public void onServiceDisconnected(ComponentName arg0) {
Log.i(LOG_TAG, "RecordFragment ServiceConnection#onServiceDisconnected");
mRecordingService = null;
}
};

context.bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
}
}

private void tryUnbindService(Context context) {
if (context == null)
Log.w(LOG_TAG, "tryUnbindService: context is null");
if (mConnection != null) {
context.unbindService(mConnection);
mConnection = null;
}
}

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
@Nullable
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
@Nullable Bundle savedInstanceState) {
View recordView = inflater.inflate(R.layout.fragment_record, container, false);

mChronometer = recordView.findViewById(R.id.chronometer);
Expand Down Expand Up @@ -269,29 +310,6 @@ private void updateUI(RecorderState state, long chronometerBaseTime) {
}
}

/**
* Defines callbacks for service binding, passed to bindService()
*/
private ServiceConnection mConnection = new ServiceConnection() {

@Override
public void onServiceConnected(ComponentName className, IBinder service) {
// We've bound to LocalService, cast the IBinder and get LocalService instance
RecordingService.LocalBinder binder = (RecordingService.LocalBinder) service;
mRecordingService = binder.getService();
Log.i(LOG_TAG, "RecordFragment ServiceConnection#onServiceConnected");

long chronometerTime = SystemClock.elapsedRealtime() - mRecordingService.getTotalDurationMillis();
updateUI(mRecordingService.getState(), chronometerTime);
}

@Override
public void onServiceDisconnected(ComponentName arg0) {
Log.i(LOG_TAG, "RecordFragment ServiceConnection#onServiceDisconnected");
mRecordingService = null;
}
};

/**
* Stop recording
*/
Expand All @@ -302,9 +320,7 @@ private void stopRecording() {
return;
}
activity.startService(getStopServiceIntent());
if (mConnection != null) {
activity.unbindService(mConnection);
}
tryUnbindService(activity);

ScreenLock.allowScreenTurnOff(activity);
}
Expand Down Expand Up @@ -339,7 +355,7 @@ private boolean startRecording() {
} else {
componentName = activity.startService(intent);
}
activity.bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
tryBindService(activity, intent);
ScreenLock.keepScreenOn(activity);

if (componentName != null) {
Expand Down

0 comments on commit dcd437e

Please sign in to comment.