0

I have found a great service for recording audio in Ionic. But there is at least one thing that I do not understand:

For example, in line 25:

this.MediaPlugin.startRecord();

Question: Why does it call on this.MediaPlugin.startRecord() and not this.mediaPlugin.startRecord() where this.mediaPlugin is an object and MediaPlugin a class?

If the class uses this.MediaPlugin to do the actions why does it return in the get method an object?

complete code:

import { Injectable } from '@angular/core';
import { MediaPlugin } from 'ionic-native';

export enum AudioRecorderState {
    Ready,
    Recording,
    Recorded,
    Playing
}

@Injectable()
export class AudioRecorder {
  mediaPlugin: MediaPlugin = null;
  state: AudioRecorderState = AudioRecorderState.Ready;

  get MediaPlugin(): MediaPlugin {
    if (this.mediaPlugin == null) {
      this.mediaPlugin = new MediaPlugin('../Library/NoCloud/recording.wav');
    }

    return this.mediaPlugin;
  }

  startRecording() {
    this.MediaPlugin.startRecord();
    this.state = AudioRecorderState.Recording;
  }

  stopRecording() {
    this.MediaPlugin.stopRecord();
    this.state = AudioRecorderState.Recorded;
  }

  startPlayback() {
    this.MediaPlugin.play();
    this.state = AudioRecorderState.Playing;
  }

  stopPlayback() {
    this.MediaPlugin.stop();
    this.state = AudioRecorderState.Ready;
  }
}

3 Answers 3

1

this.MediaPlugin is the reference to the get. Using this syntax, it'll construct the MediaPlugin on the first call, but use the constructed on following calls.

(This solutions seems a little weird to me too, since it'd make more sense to just use the constructor in the AudioRecorder class to init this.mediaPlugin, and then use this.mediaPlugin elsewhere)

Sign up to request clarification or add additional context in comments.

Comments

0

First of all following method is a getter and I guess it's an attempt to implement readonly property with lazy initialization.

get MediaPlugin(): MediaPlugin {
    if (this.mediaPlugin == null) {
        this.mediaPlugin = new MediaPlugin('../Library/NoCloud/recording.wav');
    }

    return this.mediaPlugin;
}

So when you try to access this.MediaPlugin for the first time, new instance of MediaPlugin is being created. And when you instantiate AudioRecorder and do not use it (for some reasons) it helps you to save memory not creating instance of MediaPlugin immediately. (see Lazy loading pattern)

Answering you question:

Why does it call on this.MediaPlugin.startRecord() and not this.mediaPlugin.startRecord() where this.mediaPlugin is an object and MediaPlugin a class?

Typescript does not provide any common mechanism of lazy loading and the way to implement it is to create private property with a getter method (as in your AudioRecorder class).

Calling this.MediaPlugin.startRecord() you kind of encapsulating creation and manipulation logic of MediaPlugin instance.

Comments

0

Naming conventions

Someone messed up with regards to naming conventions. The name of the property should be mediaPlugin, not MediaPlugin.

The reason that the property accessor is called MediaPlugin is that there is already a backing field called mediaPlugin.

Some would argue that the backing field should be called _mediaPlugin. Others would argue that this would go against naming conventions. If the latter is the case, you could call it mediaPluginField.

class AudioRecorder {
  mediaPluginField: MediaPlugin = null;

  get mediaPlugin(): MediaPlugin {
    if (this.mediaPluginField === null) {
      this.mediaPluginField = new MediaPlugin('../Library/NoCloud/recording.wav');
    }

    return this.mediaPluginField;
  }
}

Dependency inversion

However, as @Vladyslav Yefremov points out, an arguably better option would be to inject the MediaPlugin dependency through the constructor or pull it from some kind of service locator.

class AudioRecorder {
  constructor(private mediaPlugin: MediaPlugin) { }
}

or

class AudioRecorder {
    private mediaPlugin: MediaPlugin;

    constructor(mediaPlugin: MediaPlugin) {
        this.mediaPlugin = mediaPlugin;
    }
}

Lazy instantiation

I do not immediately see the need to instantiate the media plugin lazily, as the audio recorder needs a media plugin for all actions.

However, it could be because the media plugin has the side effect of loading the media file when instantiated. If this is the case, the media plugin property is instantiated lazily to delay the opening of the resource until it is actually needed, i.e. when the AudioRecorder is needed.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.