I’ve made the challenge in this way.
Firstly created a new ViewModel class.
FragmentViewModel.java:
public class FragmentViewModel extends BaseObservable {
public ObservableField<String> mPlaybackSpeedRateLabel = new ObservableField<>();
public ObservableInt mPlaybackSpeedRate = new ObservableInt();
private BeatBox mBeatBox;
public FragmentViewModel(BeatBox beatBox) {
if (beatBox != null) {
mBeatBox = beatBox;
mPlaybackSpeedRateLabel.set(MessageFormat.format(
mBeatBox.getPlaybackSpeedLabel(),
(int) (mBeatBox.getPlaybackSpeedRate() * 100)));
mPlaybackSpeedRate.set((int) (mBeatBox.getPlaybackSpeedRate() * 100 - 20));
}
}
public void onPlaybackSpeedRateChanged(SeekBar seekBar, int progress, boolean fromUser) {
mPlaybackSpeedRateLabel.set(MessageFormat.format(mBeatBox.getPlaybackSpeedLabel(), progress + 20));
mPlaybackSpeedRate.set(progress);
mBeatBox.setPlaybackSpeedRate((progress + 20.0f) / 100);
}
}
Then modified the BeatBox class.
BeatBox.java:
public class BeatBox {
private static final String TAG = "BeatBox";
private static final String SOUND_FOLDER = "sample_sounds";
private static final int MAX_SOUNDS = 5;
private AssetManager mAssets;
private List<Sound> mSounds = new ArrayList<>();
private SoundPool mSoundPool;
private float mPlaybackSpeedRate;
private String mPlaybackSpeedLabel;
public BeatBox(Context context) {
mAssets = context.getAssets();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
AudioAttributes attributes = new AudioAttributes.Builder()
.setUsage(AudioAttributes.USAGE_MEDIA)
.setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
.build();
mSoundPool = new SoundPool.Builder()
.setAudioAttributes(attributes)
.setMaxStreams(MAX_SOUNDS)
.build();
} else {
//noinspection deprecation
mSoundPool = new SoundPool(MAX_SOUNDS, AudioManager.STREAM_MUSIC, 0);
}
setPlaybackSpeedRate(1.0f);
setPlaybackSpeedLabel(context.getString(R.string.playback_label));
loadSounds();
}
public void play(Sound sound) {
play(sound, mPlaybackSpeedRate);
}
public void play(Sound sound, float rate) {
Integer soundId = sound.getSoundId();
if (soundId == null) {
return;
}
mSoundPool.play(soundId, 1.0f, 1.0f, 1, 0, rate);
}
public void release() {
mSoundPool.release();
}
private void loadSounds() {
String[] soundNames;
try {
soundNames = mAssets.list(SOUND_FOLDER);
Log.i(TAG, "Found " + soundNames.length + " sounds");
} catch (IOException ioe) {
Log.e(TAG, "Could not list assets", ioe);
return;
}
for (String filename : soundNames) {
try {
String assetPath = SOUND_FOLDER + "/" + filename;
Sound sound = new Sound(assetPath);
load(sound);
mSounds.add(sound);
} catch (IOException ioe) {
Log.e(TAG, "Could not load sound " + filename, ioe);
}
}
}
private void load(Sound sound) throws IOException {
AssetFileDescriptor afd = mAssets.openFd(sound.getAssetPath());
int soundId = mSoundPool.load(afd, 1);
sound.setSoundId(soundId);
}
public List<Sound> getSounds() {
return mSounds;
}
public void setPlaybackSpeedRate(float rate) {
mPlaybackSpeedRate = rate;
}
public float getPlaybackSpeedRate() {
return mPlaybackSpeedRate;
}
public String getPlaybackSpeedLabel() {
return mPlaybackSpeedLabel;
}
public void setPlaybackSpeedLabel(String playbackSpeedLabel) {
mPlaybackSpeedLabel = playbackSpeedLabel;
}
}
Changed the fragment layout file.
fragment_beat_box.xml:
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">
<data>
<variable
name="viewModel"
type="ru.coffeeplanter.beatbox.FragmentViewModel"/>
</data>
<android.support.constraint.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v7.widget.RecyclerView
android:id="@+id/recycler_view"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginBottom="12dp"
android:layout_marginEnd="8dp"
android:layout_marginLeft="8dp"
android:layout_marginRight="8dp"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
app:layout_constraintBottom_toTopOf="@+id/speed_rate_label"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"/>
<TextView
android:id="@+id/speed_rate_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="8dp"
android:layout_marginRight="8dp"
android:text="@{viewModel.mPlaybackSpeedRateLabel}"
app:layout_constraintBottom_toTopOf="@+id/seek_bar"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
tools:text="Playback Speed: 100 %"/>
<SeekBar
android:id="@+id/seek_bar"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:layout_marginEnd="8dp"
android:layout_marginLeft="8dp"
android:layout_marginRight="8dp"
android:layout_marginStart="8dp"
android:max="160"
android:progress="@{viewModel.mPlaybackSpeedRate}"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
android:onProgressChanged="@{viewModel::onPlaybackSpeedRateChanged}"/>
</android.support.constraint.ConstraintLayout>
</layout>
And finally added to the onCreateView() method of BeatBoxFragment.java:
binding.setViewModel(new FragmentViewModel(mBeatBox));
All is working nice. )