Working with Ionic Native - Shake, Rattle, and Roll (Follow Up)

Working with Ionic Native - Shake, Rattle, and Roll (Follow Up)

This post is more than 2 years old.

Last month I wrote a tutorial on using Ionic Native and the Device Motion plugin (Working with Ionic Native - Shake, Rattle, and Roll). In that post I detailed how to use the device's accelerometer to recognize a "shake" gesture and then reload data from a service. A reader (on the Ionic blog version of my article) had a great question:

Thats really useful and it works :-) Can anyone suggest how to implement subscription.unsubscribe(); when the page is navigated away from and then restarted when the user returns to this page?

My demo was a one page app which isn't very practical, but kept things simple for the demo. However, as soon as you add a new page to the app, you may (or may not!) notice something bad about my code - it continues to listen to the accelerometer after you've left the page. That's going to drain the device battery and make the user angry. You wouldn't like the user when they're angry - trust me.

Alt text

I began by modifying my previous demo such that the list of cats actually linked to a detail page. In case you don't remember, this is how the list looked:

So I simply created a new page (don't forget, the Ionic CLI has a cool "generate" feature to make that easy!) and then linked my cats to the detail. So first I added a click event to my list item:


<ion-item *ngFor="let cat of cats" (click)="loadCat(cat)"> {{ cat.name }} </ion-item>

And then added a handler for it:


loadCat(cat) {
    this.navController.push(DetailPage, {cat:cat});
}

Ok, so how do we fix our code so we only listen to the accelerometer when the view is visible? Easy - we use a view event! The Ionic docs do not do a good job of making it easy to find them, but if you look the API docs for NavController, you'll find a list of view-related events you can listen to. For my demo, I just needed ionViewWillEnter and ionViewWillLeave. So I simply moved my "listen for device motion" code out of the constructor and into the enter event. Here's the complete home.ts code:


import {Component} from '@angular/core';
import {NavController,Platform} from 'ionic-angular';
import {CatProvider} from '../../providers/cat-provider/cat-provider';
import {DeviceMotion} from 'ionic-native';
import {DetailPage} from '../detail/detail';

@Component({
  providers: [CatProvider],
  templateUrl: 'build/pages/home/home.html'
})
export class HomePage {

  public cats:Array<Object>;
  private lastX:number;
  private lastY:number;
  private lastZ:number;
  private moveCounter:number = 0;
  private subscription:any;

  constructor(public catProvider:CatProvider, private navController: NavController, public platform:Platform) {
    this.loadCats();
  }

  loadMore() {
    console.log('load more cats');
    this.loadCats();
  }

  loadCats() {
    this.catProvider.load().then(result => {
      this.cats = result;
    });
  }

  loadCat(cat) {
    this.navController.push(DetailPage, {cat:cat});
  }

  ionViewWillEnter() {
    console.log('view will enter');

    this.platform.ready().then(() => {
      this.subscription = DeviceMotion.watchAcceleration({frequency:200}).subscribe(acc => {
        console.log(acc);

        if(!this.lastX) {
          this.lastX = acc.x;
          this.lastY = acc.y;
          this.lastZ = acc.z;
          return;
        }

        let deltaX:number, deltaY:number, deltaZ:number;
        deltaX = Math.abs(acc.x-this.lastX);
        deltaY = Math.abs(acc.y-this.lastY);
        deltaZ = Math.abs(acc.z-this.lastZ);

        if(deltaX + deltaY + deltaZ > 3) {
          this.moveCounter++;
        } else {
          this.moveCounter = Math.max(0, --this.moveCounter);
        }

        if(this.moveCounter > 2) { 
          console.log('SHAKE');
          this.loadCats(); 
          this.moveCounter=0; 
        }

        this.lastX = acc.x;
        this.lastY = acc.y;
        this.lastZ = acc.z;

      });
    });

  }

  ionViewWillLeave() {
    console.log('view will leave');
    this.subscription.unsubscribe();
  }

}

So ionViewWillEnter simply has the code I used before. No real difference there - but do note I'm storing subscription globally to the component. That let's me then use it in ionViewWillLeave to handle unsubscribing from the accelerometer.

I created a new folder for this version in my Cordova Demos repository - you can find it here: https://github.com/cfjedimaster/Cordova-Examples/tree/master/ionicnative_shake_2

Raymond Camden's Picture

About Raymond Camden

Raymond is a senior developer evangelist for Adobe. He focuses on document services, JavaScript, and enterprise cat demos. If you like this article, please consider visiting my Amazon Wishlist or donating via PayPal to show your support. You can even buy me a coffee!

Lafayette, LA https://www.raymondcamden.com

Archived Comments

Comment 1 by sanju posted on 9/7/2016 at 6:06 PM

you are great sir thank you for knowledge for ionic framework

Comment 2 (In reply to #1) by Raymond Camden posted on 9/7/2016 at 6:07 PM

You are most welcome.

Comment 3 by jignesh posted on 5/16/2018 at 11:20 AM

how to only shake front side mobile shake get result

Comment 4 (In reply to #3) by Raymond Camden posted on 5/16/2018 at 12:00 PM

Sorry what?

Comment 5 (In reply to #4) by jignesh posted on 5/18/2018 at 5:21 AM

example: tree motion direction call function not calling function z axis only working motion only tree direction

Comment 6 (In reply to #5) by Raymond Camden posted on 5/18/2018 at 11:04 AM

I honestly cannot tell what you are trying to say here. I'm sorry.

Comment 7 by jignesh posted on 12/7/2018 at 10:51 AM

can we use vibration plugin in background mode in ionc3 android

Comment 8 (In reply to #7) by Raymond Camden posted on 12/8/2018 at 4:11 PM

No idea - did you try? :)