Store user data string to Android device local storage

Hello,

I’m trying to store registration phone number value on local storage to make app read this value with loading of home.ts and stay logged in, search of user ID by this data, and make proper retriveing or recording by this ID.

Everything works successfully in Chrome browser, but if I’m trying to test app on Android device, It just does not stores data, and after each registration, it makes new record in mySql database, seems like local storage data just does not exist there and condition does not allows process proper recording or retrieving.

To set and get I use this code:

 setData() {
    this.storage.set('myData', this.persist);
    console.log('Set persistent value to local storage');
  }

  getData() {
    this.storage.get('myData').then((val) => {
      console.log('Get pesistent value data: ', val);
    });
  }

Which plugin are you using for storage? This works OK in my app.

Hello, @distante import { Storage } from ‘@ionic/storage’;

@lado Do you see both the logs Set persistent value to local storage and Get pesistent value data: [value]? The value of value is null/undefined? What is the value of this.persist? Can you log it in setData()? (console.log('Set persistent value to local storage', this.persist);).

Also, I recommend return the promises to avoid async values not returning fast enough:

setData<T>(data: T): Promise<void> {
	return this.storage.set('myData', data).then(
		() => console.log('Set persistent value to local storage', data)
	);
}

getData<T>(): Promise<T> {
	return this.storage.get('myData').then((val: T) => {
		console.log('Get pesistent value data: ', val);
		return val;
	});
}
2 Likes

Hello, @lucasbasquerotto

this.persist is a phone number of user, which I use to find user ID in MySql database and create logged in condition:

 this.persist = this.mob;  
  this.setData();

I see both logs, it works perfectly in browser, but it is lost on Android device.

How do you pass value to setData<T>(data: T) if I want add it from another function?

@lado Do you see both logs in Android? The value of this.persist is correct? What is shown in your log in getData() method (the value is undefined/null)?

About setData<T>(data: T):

// this.persist = this.mob; 
let data = this.mob;  
return this.setData(data); // You don't need a class attribute anymore (to use inside)

@lucasbasquerotto Yes value is correct, it is a number, not undefined or null, but what I found, now question, how to figure out, it works properly with Chrome browser, and Android device on Motorola phone, but not with Asus phone Android, not sure, something wrong in my code or it is some incompatibility with particular OS

This is crucial. People constantly assume storage.set is synchronous and then confuse a race condition with some mysterious feature of device X. This is partially why I keep harping on how storage should only be used to persist data across app restarts. If you discipline yourself to never use it for in-app communication, you can’t get bit by this.

@lado To make things easy to discover the problem you’re having, I think the best way is to make things simple and test with a trivial case to see what happens.

Like @rapropos said, a race condition may be causing that problem. Make sure that storage.ready() is called before you try to set/get the data and chain/return the promises to make sure to avoid problems with race conditions (like shown below).

I also advise to store as JSON objects because I don’t know if the storage that is being used in your device accepts objects (if it’s a phone number (string or number), it shouldn’t be needed tough).

So you could make the following code, call test() and see what it shows in the log:

test() {
	const key = 'myTestData';
	const data = { test: 'value' };

	return this.setData(key, data).then(
		() => console.log('setData() called', data)
	).then(
		() => this.getData(key)
	).then(
		value => console.log('getData() called', value)
	)
}

setData<T>(key: string; data: T): Promise<void> {
	return this.storage.ready().then(
		() => this.storage.set(key, JSON.stringify(data))
	);
}

getData<T>(key: string): Promise<T> {
	return this.storage.ready().then(
		() => this.storage.get(key)
	).then(
		strObj => strObj ? JSON.parse(strObj) : null
	);
}

If you have different results in different devices, I advise to remove your android platform and add it again. Are you using SQLite as storage? If not, you could try installing it and see if the problem persists, otherwise I advise to remove it and test to see if the problem persists.

@lucasbasquerotto Thank you for your feedback, no I’m not using SQLite as storage

Seems like problem with something else here, to explain why, I have to describe what happens

In code below I’m successfully getting recorded local storage value (phone number), and I pass it in provider to use from another page for updated database records by this ID.

with Chrome browser works properly as needed, but with Android device, with both Asus and Motorola, it behaves this way:

With first login by some reason it does not sends value to provider, but after closing of application and login again everything works, with absolutely same processing in both cases, function loads in constructor, gets storage value, then ID from PHP echo, and attaches value to variable in provider.

it looks like that the storage value has no connection with this problem, maybe something wrong this.dataProvider.userID = data.text(); maybe provider can’t timely get this value on device:

  userID() {
    ...
    this.storage.get('myData').then((val) => {

      let postParams = this.param + val; 
     
      this.http.post(this.phpPath + this.phpFile, (postParams), options)
        .subscribe(data => {
        
          this.dataProvider.userID = data.text();

        }, error => {
          console.log(error);
        });
    });
  }

@lado It’s hard for me to tell where the problem is with just this information, try to put some logs to know the values, like:

userID() {
    ...
    return this.storage.get('myData').then((val) => {

      console.log('myData val', val); // what is logged here, val has the correct value?

      let postParams = this.param + val; 

      console.log('postParams', postParams); // postParams has the correct value?
     
      this.http.post(this.phpPath + this.phpFile, (postParams), options)
        .subscribe(data => {
          console.log('post response', data); // the returned data is correct?

          const userID  = data.text();

          console.log('userID ', userID); // userID has the correct value?

          this.dataProvider.userID = userID;

        }, error => {
          console.log(error);
        });
    });
  }

You can use localStorage.setItem(‘value’, 'key):
localStorage.getItem(‘value’, 'key)

@lucasbasquerotto I have added logs with console, it is correct, below the green line, I have also added result of StudioSettingPage.ts, which gets storage value, created in home.ts, from StudioSettingsPage.ts load of function in constructor, without getting of 2382503 value from provider variable, as it is done above the green line, where it gets value with loading of home.ts and passing of storage value to StudioSettingsPage.ts with provider variable.

Both shows proper storage value, ID, ID attaching to provider variable, recording to MySql database, all works fine with Chrome browses, but result on Android device is proper only after closing of application after registration and with second login, what seems equivalent of refreshing this.navCtrl.setRoot(this.navCtrl.getActive().component);, but I’m not sure, if it is solution in this case.

Registration process makes record into database and calls discussed function again, the only thing there is loading of his.navCtrl.setRoot(StudioSettingsPage); after registration with following checking of database and loading from constructor if particular user registration already exist, StudioSettingPage.ts instead home.ts.

@lado it’s really hard to me to know what is happening with the logs you provided. Can you change your method to use the logs I showed in my previous post? (the logs alone don’t mean too much to me, I need to know what is logging and what is done before, as well as what is expected to log).

In android, the logs from my previous post are right? If not, which log is wrong? The one that shows the value from storage? Or the one returned from the http call? Without it I can’t say much.

If you want to know if your storage is working I recommend again to execute the following test function:

ngOnInit() {
	// This works? 
	// The data of setData() is equal to the value from getData()?
	// Look at the console logs
	// Show both logs in the browser (chrome) and in android to me
	this.test(); 
}

test() {
	const key = 'myTestData';
	const data = { test: 'value' };

	return this.setData(key, data).then(
		() => console.log('setData() called', data)
	).then(
		() => this.getData(key)
	).then(
		value => console.log('getData() called', value)
	)
}

setData<T>(key: string; data: T): Promise<void> {
	return this.storage.ready().then(
		() => this.storage.set(key, JSON.stringify(data))
	);
}

getData<T>(key: string): Promise<T> {
	return this.storage.ready().then(
		() => this.storage.get(key)
	).then(
		strObj => strObj ? JSON.parse(strObj) : null
	);
}

Try the code above to see if the problem is in the storage. If it works, then the problem is not the storage (by itself, although could be some race condition).

this.test(); and userID(); logs, value from storage is a number 382503, returned from the http call is a number 1 from database ID, post response text isdata.text(); which is also this.dataProvider.ID = data.text(); passed in Chrome to another page this.dataProvider.ID successfully, but on device only after second login to app. Works on device only if I got userID(); in this second page too.

Seems like something with provider value. Also I found equivalent result with event from home.ts

this.events.publish('id:added', data);

in app.components.ts :

 userID() {
    this.events.subscribe('userid:added', (data) => {
      this.ID = data.text();
    });
  }

@lado

  1. The logs you posted are from chrome or Android? (you can see the Android logs using chrome://inspect)
  2. If I understood correctly in Android it only works after the 2nd login. In the logs you showed is something different in chrome compared to Android?
  3. Whenever you use Android the logs are the same or something change? Is some log incorrect in your 1st login? If there is, what is?
    3.1) setData() called?
    3.2) getData() called?
    3.3) post response?
    3.4) myData val?
    3.5) postParams?
    3.6) userID
    3.7) Or every log is right but you just don’t receive the event with the userID?
  4. I see that you have the logs of post response before myData val and postParams, you changed the method?
userID() {
    ...
    return this.storage.get('myData').then((val) => {

      console.log('myData val', val); // what is logged here, val has the correct value?

      let postParams = this.param + val; 

      console.log('postParams', postParams); // postParams has the correct value?
     
      this.http.post(this.phpPath + this.phpFile, (postParams), options)
        .subscribe(data => {
          console.log('post response', data); // the returned data is correct?

          const userID  = data.text();

          console.log('userID ', userID); // userID has the correct value?

          this.dataProvider.userID = userID;

        }, error => {
          console.log(error);
        });
    });
  }

@lucasbasquerotto Yes in Android works after the 2nd login. it is Chrome log, but it is same with 1st login userID: 1 from android debug, nothing changes, every log is correct, but I just don’t receive provider value to another page.ts, or event to app.components.ts with the userID with 1st login. I did not changed method, it is cut from print screen over another layer by mistake in photoshop, sorry for that. It is after myData val and postParams.

@lado So it seems the problem is not the storage, otherwise the logs would be different. It’s probably some race condition, I presume (because it works in some devices and in others only after the 2nd login).

If you want to receive the event in app component I advise you to send the event inside the method, not in home.ts, to make sure it is published after you have the response data, and every time the value change:

subscribe(data => {
  console.log('post response', data);

  const userID  = data.text();

  console.log('userID ', userID);

  this.dataProvider.userID = userID;
  
  // include this
  this.events.publish('userid:added', data);
}

Then you can subscribe to it in app.components.ts:

userID() {
  this.events.subscribe('userid:added', (data) => {
    this.ID = data.text();
    // include this log and see if you receive the event
    console.log('received event userid:added', this.ID);
  });
}

@lucasbasquerotto The unique solution I found in my particular case is this.navCtrl.setRoot(this.navCtrl.getActive().component); with login once, and I don’t know, what can be reason of race condition in this app, and how to find it. This happens with both provider and event value, same way