Hi I'm using the Google Drive Api to store a database using the AppDataFolder facility. I have a test app running successfully on one device. I am able to upload/update/delete/download the database file and reintegrate it into the program with no problems.
The issue I'm having is when I want to share this database with another device running the same app, then things don't work as expected. Example device A I upload the database, device B - I want to download the database but no file is found (this delay can vary greatly from seconds to hours). Reason for this - when using the Api it decides when it wants to 'sync' data, as it is queued rather than being instantaneously uploaded. So when used on one device this is not a problem because it takes either the 'synced' file from the cloud storage, or file waiting to be synced.
I have tried various things like trying to list all AppDataFolder files or retrieving metadata through a query with searchable filters before making a request to update/delete etc.. However I can't get it to work as desired fundamentally it chooses when to sync.
So my actual question is: How can I force Google Drive to sync my file when I want it to i.e. every time a request is made, so that synchronisation is achieved across multiple devices using the same app. There must be an answer as I would think this is quite a fundamental reason why you would use the AppDataFolder is the first place.
Thanks in advance
EDIT/UPDATE:
I have been able to find an option in the Api to 'sync' the drive content using this code:
// try to sync
Drive.DriveApi.requestSync(mGoogleApiClient).setResultCallback(new ResultCallback<com.google.android.gms.common.api.Status>() {
#Override
public void onResult(com.google.android.gms.common.api.Status status) {
if (!status.getStatus().isSuccess()) {
Log.e("SYNCING", "ERROR" + status.getStatusMessage());
} else {
Log.e("SYNCING", "SUCCESS");
// execute async task to list AppFolderContents
new AppFolderContentsAsyncTask(getActivity()).execute();
}
}
});
This works well for 3/4 attempts in quick succession, however I reach a syncing limit and status message:
ERRORSync request rate limit exceeded.
Is there any way to increase the request rate as this is not really desirable if I have to have a app that prompts the user 'please try again later to sync - not sure how long you'll have to wait until you can though!'
SOLUTION - OF SORTS, AND MY THOUGHTS (for what its worth)
The solution that I am going for (after emailing a app dev whose published a drive app that synchronizes without problems) is to use the Drive REST Api, rather than the newer (and Google preferred) Drive API. I tried limiting the 'requestSync' to only when the user navigated to a fragment with the Drive options (rather than every file transaction). However this would probably solve the requestSync rate limit for the most part, but it still could hit that limit. Also if multiple devices are running the app, and linked to the same Drive account were both syncing/uploading/deleting files at the same time in the app then there is a possibility of losing synchronization - maybe a rare scenario, but still possible. I don't feel that making a user wait to sync files is a viable option in terms of user experience or app design.
Curious though - The actual Drive app lets you refresh (requestSync?) as many times as you like. I created 20 folders on the web interface in quick succession, after each folder was created I refreshed the Drive app on my phone and it synced all 20 times. It seems Google understands the importance of synchronization, but chooses to make this quite difficult ensure this in their new Drive API. As already stated uploading files to the cloud storage happens usually instantly (it is queued, however if you have connectivity it happens almost straight away). I would have thought that this is the costly transaction in terms of moving data/updating drive contents, rather than just querying for synchronization of files. However you can keep adding files to your your drive app one at a time, and it uploads them one at a time almost instantly - where as you request sync more than 4 times in 30 seconds and it then fails and you have to 'cool off' for a while.
I'm very new to programming/Android in general - as soon as I learn something new, I realize how little I actually know, so if their is a better solution out there using the Drive API (rather than REST API) I'd very much welcome it.
DriveApi#requestSync will let you request a "sync down" from the server to the device. This way, on the second device you should be able to see the content uploaded from the first device. However, the calls to request sync are rate limited (per-device) to avoid abuse and guarantee a reasonable amount of data usage by the Drive API. You should ideally call request sync only when you need to. There's no way to increase the rate limit.
Regarding upload completion, after committing an upload, you shouldn't use request sync since that won't help you (it only syncs down but not up). The actual upload will happen as soon as possible (based on the device's connectivity and the preferences specified by your app through DrivePreferencesApi, which by default are unrestricted).
If you want to know when the actual upload happened, you can use CompletionEvents. This way you can test your app with more insights on what's actually going on.
Related
I'm new to app dev...
I read somewhere in the doc: "...In most cases you want to use SharedPreferences as it is automatically backed up and migrated to new devices..."
On first install my app saves a few settings with SharedPreferences. It works great but if I uninstall the app or install it on another device the preference settings are lost.
How can I have these settings saved online within google somehow to be able to retrieve them if the user changes his phone or similar...
Could someone point me in the right direction ?
I read somewhere in the doc: "...In most cases you want to use SharedPreferences as it is automatically backed up and migrated to new devices..."
Your words "backed up and migrated to new devices" is nowhere written nor its true.
We use SharedPreferences in order to minimise the database operations, its like keeping variables handy.
On first install my app saves a few settings with SharedPreferences. It works great but if I uninstall the app or install it on another device the preference settings are lost.
If you wants to store or remember the device dependent settings, use device id / imei_id and store it on your web server mysql database
Even if user uninstalls app from the device and installs again anytime in future, make a call with async task to server by sending deviceid / imei_id and fetch its settings from mysql database and show it.
How can I have these settings saved online within google somehow to be
able to retrieve them if the user changes his phone or similar...
If user changes device, you can do nothing.
One way is, keep public device_id levels keys on server.
If user changes device and uses that key, then show him a response, this key is assigned to another device, but if you are the same, wait for our support
Call him, confirm he is the same old user with new device and delete his old entry from mysql and assign old key to the new device entry
Or use OTP SMS system to identify already existing customers with unique phone numbers
If OTP authentication code is correct then fetch settings for that user from the server, delete old mysql entry, modify new entry with old key and mobile number
This should be the your direction
Edit : 2 ##
I was hoping an easier solution exist but....
There is no short cuts for developers till the date, and it will be never.
Why, no short cuts / easy ways ?
Any device ( mobile, desktop / laptop / any AI device ) which is operated by a system software, is able to perform the tasks as per it is structured.
Ex : android is java based, obviously you can Make javascript based apps, but it is the extensions to the existing system, Android still has the base of Java virtual machine. ( Dalvic / Malvic like )
So, it is always better to use native java
Yes, Kotlin is best option now a days and better than hybrid approach
Every way has its own advantages, disadvantages
If you are developer, should go with native approach
Now your java code never knows, which version it is running on, so you have to, check android versions programming wise, and decide the flow for above Marshmallow & below marshmallow too, and it is explicitly done by developer by coding.
Ex, once user registers, he never shown please register again screen, it is not the magic, nor google, nor, java, nor android does anything, developer has decided, planned, architectured, designed, coded, tested that.
Even developers needs to take care of exceptions, you need to handle it in order to save your app from crashing.
In short developer is god, who creates his own universe, and everything is pre-planned and verified thats it.
You should use allowBackup = "true" in your manifest file. More details can be found here: AutoBackup
In my game I use Google Play Game for Achievements and Leaderboards.
I've just noticed (by logging into the Google API Console), that performing a simple action such as displaying a leaderboard, results in 2 API calls. I would have thought this would be only 1.
I'm simply calling the leaderboard like so:
public void displayLeaderBoard(){
if (getGameHelper().isSignedIn()){
if (leaderboardIntent==null){
leaderboardIntent = Games.Leaderboards.getLeaderboardIntent(getApiClient(), leaderboardID);
}
startActivityForResult(myLeaderboard, 1);
}
}
Note it is still 2 API calls even when pressing the leadeboard button a 2nd time (therefore not creating a new 'leaderboardIntent').
Also, when submitting a high score, it uses 3 API calls (one for submitting, then again it calls displayLeaderboard() to show the player her/his new high score.
The thing here is if I then exit back to the app and submit the score again, it uses another 3 API calls. The documentation states:
Both the Android and iOS client libraries will know not to send a
player's score to the server if your score isn't as good as one you
recently submitted.
I know I could simply store a copy of the high score in sharedPreferences and then not submit it if it's not high enough, but I'm not sure about this - what if the device has multiple accounts set up for example.
I would be grateful if someone with more knowledge/experience of the Play Games API could confirm if the number of API calls I'm seeing is correct and how this relates to quote above, or whether there is something more I should be doing in my code?
The number of calls you are seeing could very well be correct. For many APIs, each request has a "cost" related to it. Which means where a read request to a certain API might cost you 1 call, a write request might cost you 5 (just assuming). Hence, depending on the requests you are making your number of calls are going to differ compared to the number of requests made. For example, try this tool to calculate Youtube API quota cost. Unfortunately I couldn't find any such tool or documentation for Play Games Services API but I hope this makes my point clear.
For optimizing your code to perform it's best, take a look here and try to optimize your code to follow Best Practices as much as you can.
I am currently using Google Games Services trying to update the user score offline. This works fine as there is a cool feature for that:
http://developer.android.com/reference/com/google/android/gms/games/leaderboard/OnScoreSubmittedListener.html#onScoreSubmitted(int,
com.google.android.gms.games.leaderboard.SubmitScoreResult) if the
device is offline or was otherwise unable to post the score to the
server. The score was stored locally and will be posted to the server
the next time the device is online and is able to perform a sync (no
further action is required from the client).
So, imagine that the user has 100 points, The score gan grow to 200,300,etc. and will be updated when going online.
Unfortunately, when querying the score with getRawScore The score returned is not the Offline one, but rather the last value from the server.
Is there any way to fix this? Any workaround?
I think it's way worse than that: according to my tests, getRawScore() (or any other methods like getRank(), ...) return only the up-to-date data if you displayed the corresponding leaderboard with the default intent. If you never did, you won't even get a value.
See my post here: Play games loadLeaderboardMetadata() returns outdated data
[Update] Apparently, you can use the loadCurrentPlayerLeaderboardScore instead of the loadLeaderboardMetadata method. That one doesn't seem to return outdated data. Check it here
I got an application that displays some items loaded from a webservice (e.g. Fruits). These items rarely change. You can also show availability of those items (e.g. for apples, 10kg is available at store A today, 20kg tomorrow, ...)
The user can bookmark some of those items on his phone. I need the user to be able to bookmark some of these items and to have his bookmarks synchronized between devices (I bookmark apples on my phone, I expect to see apples bookmarked in my tablet next time I open the app there).
More or less, I got around 40 items, no more. And each availability data would total to around 200 entries.
Which technique would you use to implement that?
My idea so far:
I build a sqlite database (with contentprovider) of fruits and availabilities
I synchronize this DB every 2/3 days (that is enough, no need to do it more often)
I use a BackupAgent to synchronize the whole DB file
Do you think a database is overkill? The application is expected to always be ran with network connectivity (else we don't allow it).
My other option would have been:
Load items and availability on application start
bookmarks are kept within SharedPreferences
I use a BackupAgent to synchronize only SharedPreferences
This seems less complicated, and more efficient on the sync part. However, I feel that is not really a clean way to do it and less future-proof.
Android's backup API is only useful to initialize a new device based on the backups created by another device. See the backup API docs. It is not the right infrastructure to keep 2 devices in sync.
I suggest you take a look at the Cloud Save features of the Google Play Game Services. It allows you to sync data on two devices. It is typically used by games but can also be used in other scenario's (like yours).
I'm doing an android application much like the gmail app for android. I can see the app is very fast and very responsive.
I'm sure gmail uses local caching for better performance. But I wonder how does gmail does the following use cases.
Lets say i login for first time and the app loads all email and put in sql lite or any other caching.
use case1
every time i delete or add a star it makes an asyncronous server req to server. this is fine.
use case 2.
how does the app get notified in case the user makes changes from another client. (from a browser).
To download the entire mails will be costly. Lets assume a case in which the user adds a star to a already cached email.
How can we implement the api in such a way that to get only updates which made from other clients. Updates like new email, deleted email, star added, etc. I'm considering the scenario when the user doesn't use the background sync.
This is been bothering me for a long time. Request you guys to let me know some tutorials or links to understand the secret behind the gmail app.
Why don't you look at the gmail web app. That will be using the same/similar design principals (gmail web app is also very fast for me). Then you can apply the same principals. With the web app you can look at the web requests using something like firebug with firefox. Under the Net tab it will show the json of what is being sent across the network. It will also show you the way the request was structured. You wont be able to see how they go about optimally returning the data, but that should be fairly trivial.
I would recommend for returning data that you do the following:
1) create a cache for the most recent page of emails.
2) Updates of new emails will be immediately prefetched into the cache.
3) setup a cache for the next page and previous page of emails.
Essentially what I am saying is:
1) You can look at googles web version which is very visible to plain snooping.
2) You can optimize based on statistical usage of how the user would want to see their emails. This can suggest cache improvements.
What you are asking for in terms of links is harder because your question relates to many general concepts and proriatary software.