With Android GCM, can you use a deep JSON 'data' field? - android

That is, can you send
{
"registration_ids": ["whatever", ...],
"data": {
"foo": {
"bar": {
"baz": [42]
}
}
}
}
or is the "data" member of the GCM request restricted to one level of key-value pairs? I ask b/c that limitation is suggested by the wording in Google's doc[1], where it says "data" is:
A JSON object whose fields represents the key-value pairs of the message's payload data. If present, the payload data it will be included in the Intent as application data, with the key being the extra's name. For instance, "data":{"score":"3x1"} would result in an intent extra named score whose value is the string 3x1 There is no limit on the number of key/value pairs, though there is a limit on the total size of the message. Optional.
[1] http://developer.android.com/guide/google/gcm/gcm.html#request

Just did a test myself and confirmed my conjecture.
Send a GCM to myself with this payload:
{
"registration_ids": ["whatever", ...],
"data": {
"message": {
"bar": {
"baz": [42]
}
}
}
}
And my client received it and parse the 'message' intent extra as this:
handleMessage - message={ "bar": { "baz": [42] } }
So the you can indeed do further JSON parsing on the value of a data key.

Although it appears to work (see other answers and comments), without a clear statement from Google, i would not recommend relying on it as their documentation consistently refers to the top-level members of the json as "key-value pairs". The server-side helper jar they provide [1] also reinforces this idea, as it models the user data as a Map<String, String>. Their Message.Builder.addData method doesn't even support non-string values, so even though booleans, numbers, and null are representable in json, i'd be cautious using those, too.
If Google updates their backend code in a way that breaks this (arguably-unsupported) usage, apps that relied on it would need an update to continue to work. In order to be safe, i'm going to be using a single key-value pair whose value is a json-stringified deep object [2]. My data isn't very big, and i can afford the json-inside-json overhead, but ymmv. Also, one of my members is a variable-length list, and flattening those to key-value pairs is always ugly :)
[1] http://developer.android.com/guide/google/gcm/server-javadoc/index.html (The jar itself is only available from within the Android SDK in the gcm-server/dist directory, per http://developer.android.com/guide/google/gcm/gs.html#server-app )
[2] e.g. my whole payload will look something like this:
{
"registration_ids": ["whatever", ...],
"data": {
"player": "{\"score\": 1234, \"new_achievements\": [\"hot foot\", \"nimble\"]}"
}
}

Scuse me if I'm wrong, Map<String, String> denotes key=string and value=string.
If string is a long unreasonable json extract which is UTF-8 formatted and well escaped. It stands to reason that should you call new JSONObject(receivedString); and it works then all other json calls follow.
Do not forget that raw JSON is a string! We do not need google to clarify how to work with strings..this is why your test worked!

Related

Getting channel subscriptions list by Youtube Data Api

Is there any way to order the subscription list of Youtube channels by recently subscribed?
youtube
.subscriptions()
.list("snippet")
.setOrder("")// relevance, unread, alphabetical
.setMaxResults((long) 1000) // it is not affecting, the max limit is 50
.setMine(true)
.execute();
According to documents, I can only get max 50 items at a time, and I have only three order type parameters relevance, unread, alphabetical.
But I need to reach the channel I subscribed lastly. I would be really appreciated it if anybody helps me to handle this.
Thanks in advance!
According to the docs, you have the following parameter at your disposal:
myRecentSubscribers (boolean)
This parameter can only be used in a properly authorized request. Set this parameter's value to true to retrieve a feed of the subscribers of the authenticated user in reverse chronological order (newest first).
Note that this parameter only supports retrieval of the most recent 1000 subscribers to the authenticated user's channel. To retrieve a complete list of subscribers, use the mySubscribers parameter. That parameter, which does not return subscribers in a particular order, does not limit the number of subscribers that can be retrieved.
That is: do insert something like .setMyRecentSubscribers(true) in the sequence of setters of your code above. (Also you may remove the setChannelId setter call, since, by requiring from you to be authorized to invoke this endpoint, the API already knows the channel to which your call is referring to.)
Note also that the parameter's maxResults maximum value is 50. To receive only the most recent subscriber have .setMaxResults(1) in the setter sequence above.
If your want to obtain the list of all your subscriptions then there's the following parameter:
mine (boolean)
This parameter can only be used in a properly authorized request. Set this parameter's value to true to retrieve a feed of the authenticated user's subscriptions.
Have .setMine(true) (without .setChannelId) in your setters sequence.
You will have to invoke repeatedly the API's endpoint to get all of your subscriptions, since this endpoint provides paginated result sets. Upon obtaining all those subscriptions, sort them by snippet.publishedAt.
If you're only interested to obtain the most recent channel to which to have subscribed, instead of the sort algorithm, is sufficient to use the max algorithm (O(n) instead of O(n log n)) on the same property.
For an example of how to implement pagination in your code, have a look at some of the sample code provided by Google itself.
As I understand from your question, you want to check if you are following a specific youtube channel with help of Youtube Data API V3.
For that it is mentioned in the document that you can use forChannelId parameter.
Also Youtube Data API has a playground to let you see the results of your query. You can simply put a channelId in forChannelId field and result will return an empty array if you are not subscribed specified channel or result will return the data of that specified channel if you are subscribed to it.
You can do a simple request from your Java app to get results. In this code example I'm checking if authorized youtube API user is subscribed to Firebase Youtube Channel or not.
SubscriptionListResponse response = request.setForChannelId("UC_x5XG1OV2P6uZZ5FSM9Ttw")
.setMine(true)
.execute();
And response will include details of specified channel in the request you will make. I also share response of the request I shared above.
{
"kind": "youtube#SubscriptionListResponse",
"etag": "zCQ7lTwIBgdyVsQmbymEu-fUgjU",
"pageInfo": {
"totalResults": 1,
"resultsPerPage": 5
},
"items": [
{
"kind": "youtube#subscription",
"etag": "A-G_B0BnSqn7XtJi7BgHJEk9L3Q",
"id": "uTEDDg6jpPBwnsim9moHkataEljshwFopudOgIy34nk",
"snippet": {
"publishedAt": "2020-07-08T14:02:43.789000Z",
"title": "Google Developers",
"description": "The Google Developers channel features talks from events, educational series, best practices, tips, and the latest updates across our products and platforms.",
"resourceId": {
"kind": "youtube#channel",
"channelId": "UC_x5XG1OV2P6uZZ5FSM9Ttw"
},
"channelId": "UCC77fYySvfP7p-6QGaa-3lw",
"thumbnails": {
"default": {
"url": "https://yt3.ggpht.com/-Fgp8KFpgQqE/AAAAAAAAAAI/AAAAAAAAAAA/Wyh1vV5Up0I/s88-c-k-no-mo-rj-c0xffffff/photo.jpg"
},
"medium": {
"url": "https://yt3.ggpht.com/-Fgp8KFpgQqE/AAAAAAAAAAI/AAAAAAAAAAA/Wyh1vV5Up0I/s240-c-k-no-mo-rj-c0xffffff/photo.jpg"
},
"high": {
"url": "https://yt3.ggpht.com/-Fgp8KFpgQqE/AAAAAAAAAAI/AAAAAAAAAAA/Wyh1vV5Up0I/s800-c-k-no-mo-rj-c0xffffff/photo.jpg"
}
}
}
}
]
}

Firebase dump json data

I'm no back-end developer. So perspective is always appreciated.
I have written a script which requests from an API and creates this huge JSON file I want to save in firebase, how can I accomplish this? And would it be possible to filter this json with python for example; when I add region=eu in the url this returns the objects which have Europe as region or do I absolutely need to request the entire json file and parse in my code (java android) ?
Since there are a few parts to your question:
You can save JSON to Firebase and the data will be mapped to child locations:
Using PUT, we can write a string, number, boolean, array or any JSON object to our Firebase database...When a JSON object is saved to the database, the object properties are automatically mapped to child locations in a nested fashion.
https://firebase.google.com/docs/database/rest/save-data
And for your next question:
And would it be possible to filter this json with python for example; when I add region=eu in the url this returns the objects which have Europe as region
Looks like you should be able to jimmy something together with Firebase's filters, startAt and endAt:
We can combine startAt and endAt to limit both ends of our query.
https://firebase.google.com/docs/database/rest/retrieve-data#section-rest-filtering
For your example you might do something like this:
curl 'https://yourfirebase.firebaseio.com/yourendpoint.json?orderBy="$REGION_NAME"&startAt="EU"&endAt="EU"&print=pretty'
...or do I absolutely need to request the entire json file and parse in my code (java android) ?
The facts that JSON objects are stored hierarchically in Firebase and that you can filter based on those object values makes me think you do not, in fact, have to request the entire JSON file. However, I don't have personal experience with this particular aspect of Firebase, so give it a shot!
As #ackushiw mentions in the comments, you can also use the equalTo query (https://firebase.google.com/docs/reference/js/firebase.database.Query#equalTo):
curl 'https://yourfirebase.firebaseio.com/yourendpoint.json?orderBy="$REGION_NAME"&equalTo="EU"&print=pretty'
It really depends on how you are structuring your JSON. It's generally recommended to make your JSON tree as shallow as possible since all children are loaded when you have a matching query.
FIREBASE DATA:
{
"-id1": {
"region": "eu" // bear in mind queries are case sensitive
"title": "Foo"
"nested": {
"city": "berlin"
}
},
"-id2": {
"region": "other"
"title": "Bar"
"nested": {
"city": "berlin"
}
},
"-id3": {
"region": "eu"
"title": "Baz"
"nested": {
"city": "paris"
}
}
}
Querying with (using the Android API)
.orderByChild("region").equalTo("eu")
would return "-id1" and "-id3"
with
.orderByChild("nested/city").equalTo("berlin")
would return "-id1" and "-id2"
The REST API Returns Unsorted Results: JSON interpreters do not enforce any ordering on the result set. While orderBy can be used in combination with startAt, endAt, limitToFirst, or limitToLast to return a subset of the data, the returned results will not be sorted. Therefore, it may be necessary to manually sort the results if ordering is important.
If you're using a more complex structure I recommend watching this video
https://www.youtube.com/watch?v=vKqXSZLLnHA
I'd also recommend using the firebase library for Android
https://firebase.google.com/docs/android/setup
And Firebase-UI, It does a lot for you.
https://firebaseopensource.com/projects/firebase/firebaseui-android/

Json_ The value of the key depend on the value of other key

I get a server response like this:
{
"action":"add",
"domain":"dm1",
"params":{
"add1":"v1",
"add2":"v2",
"add3":"v3"
}
}
And i have many domain (15) and each domain have multi action, and key in value of "params" key ("add1", "add2",...) that are depended on value of action value ("add", "remove", ...). So, i want to ask that, how can i get param value from server then push in a Model using Gson. I'm Android.
Thanks in advance!
You can parse your params key as a JSONObject and iterate through all its keys to get the values of those dynamic keys. Use JSONObject.keys to get an Iterator for keys. This answer should further help you - How to parse a dynamic JSON key in a Nested JSON result?
I am not pretty sure. What your goal is.
But You can do as below
{
"action":"add",
"domain":"dm1",
"params":[
{ "add":"v1" },
{ "add":"v2" },
{ "add":"v3" }
]
}

Android, Json modifying element

I have a json file on server:
{"images":[
{"url":"...", "likes":"123"},
{"url":"...", "likes":"234"},
{"url":"...", "likes":"345"}
]}
I get the json file on android read it, but if someone likes a picture i want to change the value of the first picture from 123 to 124, is this possible and how can i do this?
The whole point is to change a json value on server,from client side.
Also if this isn't possible how can i make this happen?
Also if i want to get the Top50 rated pictures,how can i sort them and get only the 50 picture,without getting all pictures and sorting them on android ?
Which one is better,initializing the Top50 images,when the user starts the app,or when the user click on the button Top50.I assume that if its when he click the button,there might be some performance issues server side?
My other idea is to have a function server side,which every 10 min,executes automatically and gets the Top50 rated and makes something like json file.So it all happens server side automatically.
To make this happen, client should expose some interface, i.e. function that will allow to modify file on server side. The interface and implementation of this function greatly depends on server itself, i.e. which protocols it handles, what built-in or external modules it supports, which languages are supported, etc... For example, the classic scenario is using apache as HTTP server, CGI enabled, and write CGI function in perl. So, in this case interface would look like http://server.name/like.cgi?image=image123.
How to modify the values on the server ?
For this every like of a photo should be a post request of this sort.
{
"data": [
{
"image_id": 3133456,
"likes": 343
},
{
"image_id": 3133456,
"likes": 343
}
]
}
On parsing this request server updates the corresponding image's like on the server.
How to get the top 50 rated/liked images from the server ?
Again you send a get request to such a url
http://server.getsomething.com/getTop50Images
On server side
On receiving such a request you make a query on the table in your database something like this
select image_id , image_url, likes from image_table limit 50 ORDER BY likes ASC
Now getting those query results and returning them as a json would not be a performance hit until you have huge bulk of data. like some million rows may be in your database.
Response can be something like this
{
"result": [
{
"image_id": 3133456,
"likes": 34400,
"url": "http://flickr.com/someimage"
},
{
"image_id": 3133456,
"likes": 34380,
"url": "http://flickr.com/someimage"
}
]
}
You still avoid using a database yourself but can lease it from clouds services like parse.
However if you won't be using those services then you can take a look at ftp packages for js. Like the neo JavaScript library by apache.
But still a good choice will be to go with the database approach (is quiet simpler).

android - simple way to extract a key-value pair from a json string?

Suppose I have a json string like this:
{ ... "key1":"value1"; ... }
with a key1-value1 pair somewhere deep down the json structure (which includes other things such as array, dictionary, etc...). I don't know exactly (and don't care) how the exact structure of the json is.
Is there a simple way to extract the "value1" ? (if there are 2 "key1" in the json string then I just need the first one).
As far as I know, you have no chance of doing it manually.
If you really don't know what's the structure of the JSON string you're expecting, you can try a graph search approach, such as DFS (http://en.wikipedia.org/wiki/Depth-first_search).
For every key, check if it is an array.
If so, go inside and repeat the procedure. If nothing was found in a given array, backtrack.
Interrupt your process once you have found your key.

Categories

Resources