Tuesday, 9 February 2016

Google Cloud ApiEndPoints and their Initial Denials

Once I thought of :
-> Creating an appengine project
-> Creating backend api for the same project (Part of Google Cloud EndPoints)
-> Integrating Cloud Endpoints with an Android App.

and then one day finally after a long struggle streak I was able to create both.
Well I was not here to make a fuss about it, instead I am here to let you know about a minor issue (Really. Can't say) and few more implementation tips down the road.

Assumptions :
A GAE python project ready to do render some html and ready endpoints to serve.
Reader must have played a little with Google App Engine with Python .


This blog post informs about three things :

1. Issue with Backend api : It would have been little cumbersome if followed conventional process instead of endpoints proto datastore library .
It's implementation alone could be a very big blog post. That's why I will not write about it. Please do it on your own.

2. Create discovery document and client libraries (specifically java lib for Android) to directly interact with app engine backend.

3. Respective android app's build.gradle changes while adding end point lib to an android app.

4. Points to remember before testing with local and live environment


Backend Api Issue

In app.yaml (configuration file which tells what (files) is responsible for whatever appears)
I added entries for both type of handlers
a. wsgi-compliant application : handler that make this project acts as a simple web application
b. endpoints handler : handler that contains the code for api end points

handlers:

# Endpoints handler
- url: /_ah/spi/.*
  script: myModule.endpointApp

# All Request Handler
- url: /.*
  script: myOtherModule.App


Above is the correct order so as to get both handler working simultaneously but if you had the changed the order of declaration, you would have lost endpoints.
Nothing would have appeared there.

Note of Caution : Above thing may or may not be correct for all as I don't see any logic in that or didn't found any post that could tell this thing but yes it did solved my problem.


Create discovery document and client libraries

While generating client libraries, you should be in the root of project to create Google discovery document

1. Generating Google Discovery Document using command :
$ endpointscfg.py get_discovery_doc your_module.YourServiceClass
implies
$ endpointscfg.py get_discovery_doc fileNameOfApiDeclaration.NameOfClassDecoratedWith@endpoints.api
or
$ endpointscfg.py get_discovery_doc --format rpc MyModule.MyApi

example : 
$ endpointscfg.py get_discovery_doc MyModule.MyApi


2. Generate client library bundle using command :
$ endpointscfg.py get_client_lib java -bs desired_client_bundle your_module.YourServiceClass
implies
$ endpointscfg.py get_client_lib java -bs desired_client_bundle fileNameOfApiDeclaration.NameOfClassDecoratedWith@endpoints.api

Following line didn't worked out
$ endpointscfg.py get_client_lib java -bs desired_client_bundle MyModule.MyApi

And then found following in some blog
$ endpointscfg.py get_client_lib java --hostname localhost:8080 MyModule.MyApi
which was modified to following
$ endpointscfg.py get_client_lib java MyModule.MyApi  
     
        // Last one worked out successfully

Note : $ endpointscfg.py means this tool to generate client lib is in your path. So you can run it directly from terminal else you will need to navigate to the directory where it is present.


In Android Side, don't go with the obsolete documentation on how to integrate client library with the project (means don't go adding multiple libraries and then also updating gradle and hence ending up with errors in count of hundreds)

Just get the source file from the extracted source code files from java client lib and add as source in your project

Respective build.gradle changes while adding end point lib to an android app

1. Initially add following repositories :

buildscript {
    repositories {
        mavenCentral()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:1.5.0'
    }
}

apply plugin: 'com.android.application'

repositories {
    mavenCentral()
    mavenLocal()
}


2. Enable multidex

defaultConfig {
.......
        multiDexEnabled true
    }


3. Add the following dependencies :

dependencies {
    compile fileTree(include: ['*.jar'], dir: 'libs')
    testCompile 'junit:junit:4.12'
    compile 'com.android.support:appcompat-v7:23.1.1'
    compile 'com.android.support:design:23.1.1'
    compile 'com.android.support:multidex:1.0.0'
    compile ([group: 'com.google.api-client', name: 'google-api-client-android', version: '1.21.0'])
}


Testing from simulator/phone :

Url's to access api endpoint explorer on machine's localhost

1. Android Emulator : http://10.0.2.2:8080/_ah/api/
2. Genymotion : http://10.0.3.2:8080/_ah/api/
3. Physical Device : http://<your_machine_ip>:8080/_ah/api/

Note : Localhost or 127.0.0.1 refers to the emulated device itself, not the host the emulator is running on.

Once you are done uploading api endpoints code to Google api console, you can update url to

4. http://<project_id>.appspot.com/_ah/api/  (Project Id : post registration of your project on api console)


References : Cloud Api End Points

I know you have issues, please write down in the comments.

Thursday, 24 December 2015

Curious Case of RecyclerView


Sorry for the title as I was supposed to write Serious instead of Curious but no problem that will work too.

Assumptions :
1. Done with the most simplest implementation of the RecyclerView.
2. Provided options to each list item for deleting it.

So in this post we will not discuss about the RecyclerView implementation and adding options to add/delete item from it. 

We will be discussing about an issue that will occur for sure if implementation is not done with some care.

While implementation RecyclerView, there appears an inconsistency while adding and deleting items leading to an issue with addition and deletion of items from the list due to list not getting reset causing unchanged item indexes in the list.

A very frequent example of crash :
Delete second last item and then try deleting last item you will get crash due to IndexOutOfBoundsException.


Usually we add following line to remove an item from the RecylcerView. 

.....
mDataList.remove(position);
notifyItemRemoved(position);
.....


Possible Resolution : 
1. We can avoid this by simple calling notifyDataSetChanged() which resets the complete list but using this the added animation with item placement in event of addition or deletion. Also it is an expensive call in comparsion to notifyItemRemoved() or notifyItemInserted().

2. But to resolve this issue along with animation up, we need to add one more method call just below the above two method calls

.....
mDataList.remove(position);
notifyItemRemoved(position);
notifyItemRangeChanged(position, mDataList.size());
.....

It just resets the RecylerView and hence index of list items get updated.


More : 
1. Similar issue can also be seen when you add a new item to the RecyclerView at any position.
2. And in that case notifyItemInserted() is called and should be followed by notifyItemRangeChanged() .


Please comment in case of any clarifications.


Monday, 14 September 2015

Always Visible Multiple InfoWindows on Google Map



This post is about resolution of an issue that I faced when I started working on a requirement in which multiple info windows were supposed to be shown and that too simultaneously.

Conventionally there is no such method/class in Google maps api that could allow developers to implement this functionality. Though we can add multiple markers default or customized with an attached infowindow but cannot show all the infowindow simultaneously.


Prerequisite : 
Get google map key for your map to be launched correctly. Please following link to create one
https://developers.google.com/maps/documentation/android-api/signup


Alternative:
Whatever. Above feature is highly needed along with autoupdating the content on the info window.
Never knew Markers were enough to replicate it into an infowindow too.



Conception: 
We will be going to create custom Markers in which we will draw all the information as bitmap and then set it to the markers icon property using

customMarkerOption.icon(BitmapDescriptorFactory.fromBitmap(createMarkerBitmap("76.3, 23.4 75%"))));


where customMarkerOption is an instance of MarkerOptions and createMarkerBitmap() is the method that creates bitmap using the content to be shown on map.



private Bitmap createMarkerBitmap(String iMarkerText) {
         Bitmap.Config conf = Bitmap.Config.ARGB_8888;
         Bitmap bmp = Bitmap.createBitmap(200, 100, conf);
         Canvas canvas = new Canvas(bmp);
 
         canvas.drawRect(0,75,200,175, mMarkerContainerPaint);
         canvas.drawBitmap(BitmapFactory.decodeResource(getResources(),R.drawable.purple_marker),100,25,mMarkerTextPaint);
         canvas.drawText(iMarkerText, 50, 100, mMarkerTextPaint);
 
         return bmp;
     }


You can set up the map and use MarkerOptions instances above to create markers on map. And the content will also update automatically.

You can get the complete source for the demo app here.
MapDemos


Please check and let me know in case of issues.