Friday, 30 September 2016

App Engine backend with Firebase Cloud Messaging

Google Cloud Messaging (GCM) is a service that allows you to send push notifications from your server to your users, and also to receive messages from devices on the same connection. The GCM service handles all aspects of queueing of messages and delivery to the target Android application running on the target device. GCM is the same great product from Google but now under a new name: Firebase Cloud Messaging or FCM for short.
This tutorial guides you through how to implement an App engine with FCM.

1. Add Google Cloud Module:
Make a new project to generate a token which will be used for sending and receiving notifications from firebase. You can create a new project from my previous post to get your token or if you are having your own project then just implement the code to your project mentioned in this post to generate the token which will be used further.
To add the backend to your existing or new Android app, open Android Studio and navigate to "File => New Module" or right-click on your project and choose "New => Module".


 In the "New Module" dialog that appears, choose "Google Cloud Module":


Then choose "App Engine Backend with Google Cloud Messaging" from first drop-down list.


Enter the module/package names for your new backend, and choose the "client" module in the project which contains your Android app. You can enter the name of your choice for your new backend. The client module will be set up to call your newly generated backend. The module name which you've entered above (marked with red 1) will be used in your Android Studio project. The package name (marked with red 2) will be used for all classes imported from this template and (reversed) for Endpoints API namespaces. In turn, Endpoints API namespaces will be used to derive the name of the autogenerated Android client libraries. This ensures that the names of generated client libraries will match your package name.


2. Debug the backend locally:
As soon as the backend module is added to your project and Gradle sync finishes, a new run configuration with your backend's module name should be created. Rebuild your project (via "Build => Rebuild Project") and launch this run configuration. It will invoke appengineRun task in Gradle plug-in for App Engine, which in turn will start the local App Engine Java development server. Navigate to http://localhost:8080. You should see the following page:


3. Connect your app with your backend:
To test the application, you need a Google Cloud Messaging API key. Follow the instructions to create a google-services.json configuration file and API key. Open the <backend>/src/main/webapp/WEB-INF/appengine-web.xml file (it should have been opened by default when you generated the backend), and copy the generated API key into appengine-web.xml file, replacing

<property name="gcm.api.key" value="YOUR_KEY_HERE"/>

with

<property name="gcm.api.key" value="AIza..."/>

4. Register your device:
Before any messages can be sent from your backend to the devices, these devices need to be registered with your backend. When you added this backend module to your project, the required permissions, needed by Firebase Cloud Messaging have been added into the Android manifest of your app, and the required build dependencies have been added to your app's build.gradle file.
Furthermore, a RegistrationEndpoint Cloud Endpoints API has been automatically generated for you, so that you could start calling this endpoint from your Android app to register devices with your new backend. Set up your Google Cloud Messaging Client to obtain a registration token, register your android device with your new backend, and set up the listener services to show push notifications from the GCM backend.
To send your newly obtained GCM registration token to the server, use the following code snippet which you should invoke from the RegistrationIntentService you created while setting up the client:

 private void sendRegistrationToServer(String token) throws IOException {
        Registration.Builder builder = new Registration.Builder(AndroidHttp.newCompatibleTransport(),
                new AndroidJsonFactory(), null)
                // Need setRootUrl and setGoogleClientRequestInitializer only for local testing,
                // otherwise they can be skipped
                .setRootUrl("http://<YOUR_LOCAL_IP>:8080/_ah/api/")
                .setGoogleClientRequestInitializer(new GoogleClientRequestInitializer() {
                    @Override
                    public void initialize(AbstractGoogleClientRequest<?> abstractGoogleClientRequest)
                            throws IOException {
                        abstractGoogleClientRequest.setDisableGZipContent(true);
                    }
                });
        Registration regService = builder.build();
        regService.register(token).execute();
    }

5. Test it:
If you have added a RegistrationIntentService invocation to one of your Android app activities and set up the google-services.json configuration file containing your Google Developers Console project number, you are ready to test the device registration with your backend locally. Now launch your backend locally as described in point-2. and ensure that you can access it via http://localhost:8080. If you can access the backend locally, change the run configuration back to your Android app and run the Android emulator.
Testing on a physical device with a local development server requires minor changes to your configuration. You must make your development server accessible to the network by setting it to listen to external connections. You can do this by editing the build.gradle for the backend project and setting the httpAddress.

appengine {
  ....
  httpAddress = "0.0.0.0"
  ....
}

You must also change the endpoint root url to point to your computer's ip address when creating the endpoint(In your RegistrationIntentService).

Registration.Builder builder = new Registration.Builder(AndroidHttp.newCompatibleTransport(),
        new AndroidJsonFactory(), null)
        .setRootUrl("http://<YOUR_COMPUTER_ADDRESS>:8080/_ah/api/")
        ....

Now to see notification in your physical device make sure your backend is running locally as shown in point-2. and your app running in your physical device. Then from your backend enter a message and click Send Message>>, then you will be able to see a notification in your device as follows:
6. Deploy your backend:
If your backend is working fine locally, you can now deploy it to Google App Engine.
 - Stop the backend, if it is running locally, by selecting Run => Stop.
 - Run Build => Deploy Module to App Engine.
 - In the Deploy to App Engine dialog, select your module. From the Deploy To: dropdown list, choose your Google Console Project which you have create to get your api_key or if you have not created your one then choose "Click here to create a new Google Developers Console project." This will open Google Developers Console. If you are running this task for the first time, you will be prompted to sign-in with your Google Account. Choose an account and sign in.
 - Create a new project and switch back to the Deploy to App Engine dialog in Android Studio.
Now update your src/main/webapp/WEB-INF/appengine-web.xml file's <application> property and replace myApplicationId with the ID of the project that you just created. This will be important if you try to deploy from the command line.
 - Click the Refresh button in the bottom right corner of the Deploy To: dropdown list and then select the project you just created.
 - Click Deploy. You can monitor the status of your deployment in the Android Studio console.

7. Testing against your deployed backend:
Once you have deployed your backend to App Engine, you can connect your Android app to it by modifying the RegistrationIntentService class explained in point-4. above. and replace particular lines:

Registration.Builder builder = new Registration.Builder(AndroidHttp.newCompatibleTransport(),
        new AndroidJsonFactory(), null)
        // Need setRootUrl and setGoogleClientRequestInitializer only for local testing,
        // otherwise they can be skipped
        .setRootUrl("http://10.0.2.2:8080/_ah/api/")
        .setGoogleClientRequestInitializer(new GoogleClientRequestInitializer() {
            @Override
            public void initialize(AbstractGoogleClientRequest<?> abstractGoogleClientRequest)
                    throws IOException {
                abstractGoogleClientRequest.setDisableGZipContent(true);
            }
        });

with these lines

Registration.Builder builder = new Registration.Builder(AndroidHttp.newCompatibleTransport(),
        new AndroidJsonFactory(), null)
        .setRootUrl("https://android-app-backend.appspot.com/_ah/api/");

where android-app-backend corresponds to your own Project ID created above in 6.

8. At this point you should be all set to run your Android app in an emulator or on the physical device and send messages from your backend which you have created and deployed just now.
You can access your backend at https://android-app-backend.appspot.com , where android-app-backend corresponds to your own Project ID created above in 6 and successfully communicate with your new App Engine backend!!

That's all. Comment if any queries.

Thursday, 22 September 2016

Android transitions: Animations

Animations in android are a good way to make your application more user friendly and interactive. Animations are used to give the UI a rich look and feel. Animations in android apps can be performed through XML or android code. Animation is the process of creating motion and shape change. In this post we will take a look at different types of simple animations in android.
Create following XML files for animation in /anim folder under your res/ directory:

1. anim_fade_in.xml

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
    android:fillAfter="true" >

    <alpha
        android:duration="1000"
        android:fromAlpha="0.0"
        android:interpolator="@android:anim/accelerate_interpolator"
        android:toAlpha="1.0" />
</set>

2. anim_fade_out.xml

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
    android:fillAfter="true" >

    <alpha
        android:duration="1000"
        android:fromAlpha="1.0"
        android:interpolator="@android:anim/accelerate_interpolator"
        android:toAlpha="0.0" />
</set>

3. anim_slide_down.xml

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
    android:interpolator="@android:anim/overshoot_interpolator">

    <translate
        android:duration="1000"
        android:fromYDelta="-800%"
        android:toYDelta="0%" />
</set>

4. anim_slide_up.xml

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">

    <translate
        android:duration="1000"
        android:fromYDelta="800%"
        android:toYDelta="0" />
</set>

5. anim_slide_out_to_right.xml

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
    android:shareInterpolator="false">
    <translate
        android:duration="400"
        android:fromXDelta="0%"
        android:fromYDelta="0%"
        android:toXDelta="100%"
        android:toYDelta="0%" />
</set>

6. anim_slide_out_to_left.xml

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
    android:shareInterpolator="false">
    <translate
        android:duration="300"
        android:fromXDelta="0%"
        android:toXDelta="-100%" />
</set>

7. anim_slide_in_from_right.xml

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
    android:shareInterpolator="false">
    <translate
        android:duration="400"
        android:fromXDelta="100%"
        android:fromYDelta="0%"
        android:toXDelta="0%"
        android:toYDelta="0%" />
</set>

8. anim_slide_in_from_left.xml

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
    android:shareInterpolator="false">
    <translate
        android:duration="300"
        android:fromXDelta="100%"
        android:toXDelta="0%" />
</set>

9. anim_blink.xml

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
    <alpha android:fromAlpha="0.0"
        android:toAlpha="1.0"
        android:interpolator="@android:anim/accelerate_interpolator"
        android:duration="600"
        android:repeatMode="reverse"
        android:repeatCount="infinite"/>
</set>

10. anim_zoom_in.xml

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
    android:fillAfter="true" >

    <scale
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:duration="1000"
        android:fromXScale="1"
        android:fromYScale="1"
        android:pivotX="50%"
        android:pivotY="50%"
        android:toXScale="3"
        android:toYScale="3" >
    </scale>
</set>

11. anim_zoom_out.xml

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
    android:fillAfter="true" >
    <scale
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:duration="1000"
        android:fromXScale="1.0"
        android:fromYScale="1.0"
        android:pivotX="50%"
        android:pivotY="50%"
        android:toXScale="0.5"
        android:toYScale="0.5" >
    </scale>
</set>

12. anim_rotate.xml

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
    <rotate android:fromDegrees="0"
        android:toDegrees="360"
        android:pivotX="50%"
        android:pivotY="50%"
        android:duration="600"
        android:repeatMode="restart"
        android:repeatCount="infinite"
        android:interpolator="@android:anim/cycle_interpolator"/>
</set>

Now to implement these animation in your app, just in your activity do the following:

      ImageView image = (ImageView)findViewById(R.id.imageView);
      Animation anim = AnimationUtils.loadAnimation(getApplicationContext(),                                         R.anim.your_anim_file);
      image.startAnimation(anim);

That's all. You can change the animation type you want and apply it to the view as shown above.




Friday, 16 September 2016

Firebase Cloud Messaging: Getting Started

Firebase Cloud Messaging (FCM) is a cross-platform messaging solution that lets you reliably deliver messages at no cost. Using FCM, you can notify a client app that a new email or some other data is available to you.

-Key capabilities:
-Send notification messages or data messages
Send notification messages that are displayed to your user or send data messages and determine completely what happens in your application code.
-Versatile message targeting
Distribute messages to your client app in any of three ways — to single devices, to groups of devices, or to devices subscribed to topics.
-Send messages from client apps
Send acknowledgments, chats, and other messages from devices back to your server over FCM’s reliable and battery-efficient connection channel.
(We will implement this third part in the next post)

-How does it work-
An FCM implementation includes an app server that interacts with FCM via HTTP or XMPP protocol, and a client app. You can compose and send messages using the app server or the Notifications console.

Firebase Notifications is built on Firebase Cloud Messaging and shares the same FCM SDK for client development. For testing or for sending marketing or engagement messages with powerful built-in targeting and analytics, you can use Notifications. For deployments with more complex messaging requirements, FCM is the right choice.

-Implementation:

Set up the FCM SDK
Set up Firebase and FCM on your app according the setup instructions for your platform.
Develop your client app
Add message handling, topic subscription logic, or other optional features to your client app. During the development, you can easily send test messages from the Notifications console.
Develop your app server
Decide which server protocol(s) you want to use to interact with FCM, and add logic to authenticate, build send requests, handle response, and so on. Note that if you want to use upstream messaging from your client applications, you must use XMPP.

1. Go to FireBase Console and create a new project by following the steps.
2. After syncing your project, create a class named MyFirebaseInstanceIDService.java and write the following code:

//Class extending FirebaseInstanceIdService
public class MyFirebaseInstanceIDService extends FirebaseInstanceIdService {

    private static final String TAG = "MyFirebaseIIDService";

    @Override
    public void onTokenRefresh() {
        
        //Getting registration token
        String refreshedToken = FirebaseInstanceId.getInstance().getToken();
        //Displaying token on logcat 
        Log.d(TAG, "Refreshed token: " + refreshedToken);
        
    }
}

3. Now create MyFirebaseMessagingService.java and write the following code:

public class MyFirebaseMessagingService extends FirebaseMessagingService {

    private static final String TAG = "MyFirebaseMsgService";

    @Override
    public void onMessageReceived(RemoteMessage remoteMessage) {
        //Displaying data in log
        //It is optional 
        Log.d(TAG, "From: " + remoteMessage.getFrom());
        Log.d(TAG, "Notification Message Body: " + remoteMessage.getNotification().getBody());
        
        //Calling method to generate notification
        sendNotification(remoteMessage.getNotification().getBody());
    }

    //This method is only generating push notification
    private void sendNotification(String messageBody) {
        Intent intent = new Intent(this, MainActivity.class);
        intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
        PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent,
                PendingIntent.FLAG_ONE_SHOT);

        Uri defaultSoundUri= RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
        NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this)
                .setSmallIcon(R.mipmap.ic_launcher)
                .setContentTitle("Firebase Notification")
                .setContentText(messageBody)
                .setAutoCancel(true)
                .setSound(defaultSoundUri)
                .setContentIntent(pendingIntent);

        NotificationManager notificationManager =
                (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);

        notificationManager.notify(0, notificationBuilder.build());
    }
}

4. Now define the above services in your AndroidManifest.xml file as follows:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="<your_package_name>">

    <!-- Adding Internet Permission -->
    <uses-permission android:name="android.permission.INTERNET"/>

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

        <!-- Defining Services -->
        <service
            android:name=".MyFirebaseMessagingService">
            <intent-filter>
                <action android:name="com.google.firebase.MESSAGING_EVENT"/>
            </intent-filter>
        </service>

        <service
            android:name=".MyFirebaseInstanceIDService">
            <intent-filter>
                <action android:name="com.google.firebase.INSTANCE_ID_EVENT"/>
            </intent-filter>
        </service>
    </application>
</manifest>


5. Thats all. Now run your app (Make sure your device is having google play service or else it won’t work). After running the app you will be able to see a token in the logcat. Copy the token.

-Now steps for sending Push Notification using Firebase Console:
-Go to Firebase console and select the app you created.
-From the left menu select notification.
-Click on new message.
-Enter message, select single device and paste the token you copied and click on send.

That's all.. you can see a notification in the tray of your device.

Reference: https://firebase.google.com/docs/notifications/android/console-device

Friday, 9 September 2016

Firebase in Android - Storage

With reference from my last blog here, now we go forward towards the next step i.e learning the concept of Storage in Firebase.
Firebase Storage lets you upload and share user generated content, such as images and video, which allows you to build rich media content into your apps. Firebase Storage stores this data in a Google Cloud Storage bucket. Firebase Storage lets you securely upload these files directly from mobile devices and web browsers, handling spotty networks with ease.

-Prerequisites:
Install the Firebase SDK.
Add your app to your Firebase project in the Firebase console.

-Add Firebase Storage to your app:
 Add the dependencies for Firebase Storage to your build.gradle file:

compile 'com.google.firebase:firebase-storage:9.4.0'
compile 'com.google.firebase:firebase-auth:9.4.0'

-Set up Firebase Storage:
The first step in accessing your storage bucket is to create an instance of FirebaseStorage:

FirebaseStorage storage = FirebaseStorage.getInstance();

-Create a Reference:
Create a reference to upload, download, or delete a file, or to get or update its metadata. A reference can be thought of as as pointer to a file in the cloud. References are lightweight, so you can create as many as you need. They are also reusable for multiple operations. You can create a reference as follows:

// Create a storage reference from our app
StorageReference storageRef = storage.getReferenceFromUrl("gs://<your-bucket-name>");

gs://<your-firebase-storage-bucket> You can find this URL the Storage section of the Firebase console.
You can create a reference to a location lower in the tree, say 'images/space.jpg' by using the getChild() method on an existing reference.

// Create a child reference
// imagesRef now points to "images"
StorageReference imagesRef = storageRef.child("images");

// Child references can also take paths
// spaceRef now points to "users/me/profile.png
// imagesRef still points to "images"
StorageReference spaceRef = storageRef.child("images/space.jpg");

-Limitations on References:
Reference paths and names can contain any sequence of valid Unicode characters, but certain restrictions are imposed including:
  • Total length of reference.fullPath must be between 1 and 1024 bytes when UTF-8 encoded.
  • No Carriage Return or Line Feed characters.
  • Avoid using #, [, ], *, or ?, as these do not work well with other tools such as the Firebase Realtime Database or gsutil.
-Upload Files:
To upload a file to Firebase Storage, you first create a reference to the full path of the file, including the file name.

// Create a storage reference from our app
StorageReference storageRef = storage.getReferenceFromUrl("gs://<your-bucket-name>");
// Create a reference to 'images/mountains.jpg'
StorageReference mountainImagesRef = storageRef.child("images/mountains.jpg");

-Upload from data in memory:
The putData() method is the simplest way to upload a file to Firebase Storage. putData() takes a byte[] and returns an UploadTask that you can use to manage and monitor the status of the upload.

// Get the data from an ImageView as bytes
imageView.setDrawingCacheEnabled(true);
imageView.buildDrawingCache();
Bitmap bitmap = imageView.getDrawingCache();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, baos);
byte[] data = baos.toByteArray();

UploadTask uploadTask = mountainsRef.putBytes(data);
uploadTask.addOnFailureListener(new OnFailureListener() {
    @Override
    public void onFailure(@NonNull Exception exception) {
        // Handle unsuccessful uploads
    }
}).addOnSuccessListener(new OnSuccessListener<UploadTask.TaskSnapshot>() {
    @Override
    public void onSuccess(UploadTask.TaskSnapshot taskSnapshot) {
        // taskSnapshot.getMetadata() contains file metadata such as size, content-type, and download URL.
        Uri downloadUrl = taskSnapshot.getDownloadUrl();
    }
});

-Upload from a local file:
You can upload local files on the device, such as photos and videos from the camera, with the putFile() method. putFile() takes a File and returns an UploadTask which you can use to manage and monitor the status of the upload.

Uri file = Uri.fromFile(new File("path/to/images/rivers.jpg"));
StorageReference riversRef = storageRef.child("images/"+file.getLastPathSegment());
uploadTask = riversRef.putFile(file);

// Register observers to listen for when the download is done or if it fails
uploadTask.addOnFailureListener(new OnFailureListener() {
    @Override
    public void onFailure(@NonNull Exception exception) {
        // Handle unsuccessful uploads
    }
}).addOnSuccessListener(new OnSuccessListener<UploadTask.TaskSnapshot>() {
    @Override
    public void onSuccess(UploadTask.TaskSnapshot taskSnapshot) {
        Uri downloadUrl = taskSnapshot.getDownloadUrl();
    }
});

-Download files:
Download to a local file
The getFile() method downloads a file directly to a local device. Use this if your users want to have access to the file while offline or to share the file in a different app. getFile() returns a DownloadTask which you can use to manage your download and monitor the status of the download.

// Create a storage reference from our app to the image
StorageReference islandRef = storageRef.child("images/island.jpg");

File localFile = File.createTempFile("images", "jpg");

islandRef.getFile(localFile).addOnSuccessListener(new OnSuccessListener<FileDownloadTask.TaskSnapshot>() {
    @Override
    public void onSuccess(FileDownloadTask.TaskSnapshot taskSnapshot) {
        // Local temp file has been created
    }
}).addOnFailureListener(new OnFailureListener() {
    @Override
    public void onFailure(@NonNull Exception exception) {
        // Handle any errors
    }
});

That's all of this tutorial. Try this and wait for the next one to proceed further.

Friday, 2 September 2016

Firebase in Android - Adding Realtime Database

With reference from my last blog here, now we go forward towards the next step for adding Realtime database to your android app.

-Prerequisites:
- Install the Firebase in Android - Getting started.
- In the Firebase console, add your app to your Firebase project.

- Add the dependency for Firebase Realtime Database to your app-level build.gradle file:

                      compile 'com.google.firebase:firebase-database:9.4.0'

- Configure databse rules:
The Realtime database provides a declarative rules language that allows you to define how your data should be structured, how it should be indexed, and when your data can be read from and written to.By default, read and write access to your database is restricted so that only authenticated users can read or write data.You can change your permissions to your database by defining your rules.Changing your rule set from default  will make your database open to anyone, even people not using your app, so be sure to restrict your database again when you set up authentication.

- Write to your database
Create an instance of your database using getInstance() and reference the location (node) in your database where you want to write your data.

// Write a message to the database
FirebaseDatabase database = FirebaseDatabase.getInstance();
DatabaseReference myRef = database.getReference("message");
myRef.setValue("Hello, World!");

You can save a range of data types to the database this way,including Java objects.When you save an object the responses from any getters will be saved as children of this location.

- Read from your database
To make your app data update in realtime i.e data from database in constant sync with your app,you should add a ValueEventListener to the reference you just created.
The onDataChange() method in this class is triggered once when the listener is attached and again every time the data changes,including the children.

// Read from the database with reference you created above
myRef.addValueEventListener(new ValueEventListener() {
    @Override
    public void onDataChange(DataSnapshot dataSnapshot) {
        // This method is called once with the initial value and again
        // whenever data at this location is updated.
        String value = dataSnapshot.getValue(String.class);
        Log.d(TAG, "Value is: " + value);
    }

    @Override
    public void onCancelled(DatabaseError error) {
        // Failed to read value
        Log.w(TAG, "Failed to read value.", error.toException());
    }

});

- Structure Your Database
Building a properly structured database requires quite a bit of forethought. Most importantly, you need to plan for how data is going to be saved and later retrieved to make that process as easy as possible.

How data is structured: it's a JSON tree
All Firebase Realtime database data is stored as JSON objects. You can think of the database as a cloud-hosted JSON tree. Unlike a SQL database, there are no tables or records. When you add data to the JSON tree, it becomes a node in the existing JSON structure with an associated key. You can provide your own keys, such as user IDs or semantic names, or they can be provided for you using push().
For example, data in your database may look like as follows when you are storing some user details:


     "users": {
          "userid_node_for_creating_user": {
                                       "userEmailAddress":"xx@yyy.zz", 
                                       "userFirstName":"First Name",
                                       "userGender":"Male",
                                       "userLastName":"Last Name",
                                       "userMobileNumber":"0099990099",
                                       "userName":"User_1"
                          }
               }
  }

Although the database uses a JSON tree, data stored in the database can be represented as certain native types that correspond to available JSON types to help you write more maintainable code.

- Best practices for data structure

- Avoid nesting data:
Although the Firebase Realtime database allows nesting of data up to 32 levels deep, you might think that this should be the default structure. However, when you fetch data at a location in your database, you also retrieve all of its child nodes. Also, when you grant someone read or write access at a node in your database, you also grant them access to all data under that node. Therefore, in practice, it's best to keep your data structure as flat as possible.
- Use Flatten data structures:
If the data is instead split into separate paths, it can be efficiently downloaded in separate calls, as it is needed.

That's all for now. We will proceed further in next page. Till then try this much first.