Firebase Remote Config Android Example

Suppose its Christmas and you want to display your app in a new Christmas theme for all the users. You might simply think of sending an app update with the new theme but its not certain that all your users will download the update. Also sending an update for a theme change would be an unnecessary effort, considering that you have to do it for all the festivals. It is for scenarios like these that Firebase Remote Config was built.

Firebase Remote Config is a cloud service that lets you change the behavior and appearance of your app without requiring users to download an app update. Remote config basically allows you to maintain parameters on cloud which can be fetched from your application. These parameters are then used to define the changes you want to see in your application. Like in the above Christmas theme scenario, we can define a parameters with the text, color, images for the new theme which can again be fetched using Remote Config library from your app.

How Firebase Remote Config works ?

Remote Config library helps your app to fetch parameters from the firebase remote config server. It will be responsible for fetching the values and caching them in your app. To handle situations in which the server is not accessible or the parameters are not found we have to define default parameter values in the app. Once fetched from server these values are stored in cache for the next 12 hours.Which means any request in this period will return the cached values.

Remote Config implementation will just take very few lines of code because it handles all the complicated logic of fetching and caching on its own.This is mainly done by have three different configs as explained below

  • Default Config – This config contains default values defined in your app. If no matching keys are found on remote config server these default parameters are copied to the active config and returned to the client
  • Fetched Config – This contains most recently fetched  parameters from the remote config server. But this config cant be directly accessed from your app. You need to activate these config parameters which will copy parameter values from this config to the active config from where they can be directly accessed.
  • Active Config – This is the only config directly accessible from your app and it contains values from either Default or Fetched config.

Caching in Firebase Remote Config

Remote Config library implements parameter caching on its own. After the first fetch the parameters are saved into local cache. By default the cache expires in 12 hours but you can set a custom expiry for the cache using the fetch(time) method. For every fetch request it checks if the cached values are older than the specified expiry time. If yes it fetches for the new parameters. If not the cached values are only returned. Though you can change the cache expiry time for parameter values you are not allowed to call fetch API more than 5 times in an hour.

Don’t panic if you are still not clear how Remote config library works. Its implementation is very simple and the  following example will clear all your confusion

In this Firebase Remote Config example we will display a welcome message in our app using three parameters from the remote config- Welcome string, text size , text color.

Adding Firebase to your App

To start this integration first you need to register your app with Firebase. Go to Firebase Console  and follow the steps mentioned. Once the project is registered download the google-service.json file and add it to your Android project as shown in the screenshot below

Adding Gradle Dependencies

After registering your app with firebase you are provided with a set of dependencies which you need to add in your Android application. Apart from these you also need to add dependency for Remote Config library given below

implementation 'com.google.firebase:firebase-config:16.1.0'

In the end your app’s build.gradle should have the following

dependencies {
    implementation 'com.google.firebase:firebase-config:16.1.0' // Remote Config gradle dependency
    implementation 'com.google.firebase:firebase-core:16.0.4'   // Firebase gradle dependency
}
apply plugin: 'com.google.gms.google-services'   // Google Services plugin

Similarly your project’s build.gradle should have the following

buildscript {
    
    repositories {
        google()
        jcenter()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:3.2.1'
        classpath 'com.google.gms:google-services:4.0.1'  // Project Level Google Services dependency
       
    }
}

Note that you should always use the latest version of the gradle dependencies. Versions used in this example are latest at the time of publishing this post but it might not be the case always. You can find all the latest versions here.

Designing the Layout

  • In order to show the welcome message we need to define a layout and initialize it in an activity. For this we will have a simple layout with TextView– to display the welcome message and Button to fetch the latest parameters.
    <?xml version="1.0" encoding="utf-8"?>
    <RelativeLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".MainActivity">
    
        <TextView
            android:layout_width="wrap_content"
            tools:text="Welcome to the app"
            android:id="@+id/text"
            android:layout_marginTop="32dp"
            android:layout_centerHorizontal="true"
            android:layout_height="wrap_content" />
    
        <Button
            android:layout_width="wrap_content"
            android:text="FETCH"
            android:id="@+id/fetch"
            android:layout_centerInParent="true"
            android:layout_height="wrap_content" />
    
    </RelativeLayout>

Initializing FirebaseRemoteConfig

  • We just need one object to work with Remote Config library i.e. FirebaseRemoteConfig. The same object is used to set defaults parameters, fetch new parameters or activate the fetched parameters. It is a singleton object and can be obtained using FirebaseRemoteConfig.getInstance() API as shown below
    public class MainActivity extends AppCompatActivity {
    
        private FirebaseRemoteConfig firebaseRemoteConfig;
    
        private Button button;
    
        private TextView textView;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            button = findViewById(R.id.fetch);
            textView= findViewById(R.id.text);
         
            // Fetch singleton FirebaseRemoteConfig object
            firebaseRemoteConfig = FirebaseRemoteConfig.getInstance();
  • Once initialized you can use the setConfigSettings() API to enable developer mode for remote config. Developer mode allows us to refresh the parameter cache any number of times. By default Firebase doesn’t allow us to fetch new parameters for more than 5 times in an hour as explained in the last section. For this example we enable developer mode as shown below
    firebaseRemoteConfig.setConfigSettings(new FirebaseRemoteConfigSettings.Builder()
                   .setDeveloperModeEnabled(true)
                   .build());

Defining Default Values

  • As already mentioned, in this example we will have a welcome message in our app based on three parameters from remote config. Each parameter needs to have unique key and value and it is mandatory for us to define default values for all the parameters locally in our application. This can be achieved  by having a resource XML file or defining a map as shown below
    <?xml version="1.0" encoding="utf-8"?>
    <defaultsMap>
        <entry> 
            <key>text_str</key>
            <value>Welcome to the app</value>
        </entry>
        <entry>
            <key>text_str</key>
            <value>14</value>
        </entry>
        <entry>
            <key>text_color</key>
            <value>#FF0000</value>
        </entry>
    </defaultsMap>

    Instead of a XML resource file you can instead define default values in a map as shown below. Either of them will work fine

    Map<String,Object> map =new HashMap<>();
    map.put("text_str","Welcome to the app");
    map.put("text_size",14);
    
    map.put("text_color","#FF0000");

    Keep note of the parameter keys used in your default map. You will have to use the same when defining parameters on Firebase Console

  • Now we set the default parameters for remote config using the setDefaults() API. We set the map from our XML file as default. This will ensure that if any parameter key is not found on cloud its value will be fetched from this map
    firebaseRemoteConfig.setDefaults(R.xml.default_map)
    

    Getting Parameter Values

  • firebaseRemoteConfig.get<>() is used to get parameter values from the config. As already explained this can be either be from your default config or can be from the remote server. This call doesn’t actually send request for the parameter values from server but instead gets the values stored in the active config. If we have not fetched the parameters from server it returns the default in-app parameter values instead
  • In the example we try to get three parameter values using the corresponding get APIs and the parameter keys. We use the three parameter values to define the string, text size and text color of our TextView.
public class MainActivity extends AppCompatActivity {

    private FirebaseRemoteConfig firebaseRemoteConfig;

    private Button button;

    private TextView textView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
       
        button = findViewById(R.id.fetch);
        textView= findViewById(R.id.text);
        firebaseRemoteConfig = FirebaseRemoteConfig.getInstance();
        firebaseRemoteConfig.setConfigSettings(new FirebaseRemoteConfigSettings.Builder()
                .setDeveloperModeEnabled(true)
                .build());
        firebaseRemoteConfig.setDefaults(R.xml.default_map);
        firebaseRemoteConfig.setDefaults(map);
    
        textView.setTextColor(Color.parseColor(firebaseRemoteConfig.getString("text_color")));
        textView.setTextSize((float) firebaseRemoteConfig.getValue("text_size").asDouble());
        textView.setText(firebaseRemoteConfig.getString("text_str"));
    }
  • As seen in the above code snippet as soon as the activity is created (onCreate) we try to get the parameter values using the corresponding get<>() APIs and display the welcome text.

Fetching Latest Parameters

  • firebaseRemoteConfig.fetch() call initiates request to remote config server for the latest parameters and once fetched these are stored in local cache. By default these parameters expire in 12 hours but we can set custom expiry time using the fetch(long) method (the long argument denoting time in seconds). Within the expiry time, 12 hour by default, if we try calling fetch() again no request to server is sent instead the values stored in cache are returned. When requesting using fetch(long) the remote config client checks if the cached values are older than the seconds specified in method argument. If yes new parameters are requested else the cached value is returned.
  • In this example we initiate the fetch request on button click using the fetch(long) method. We set the custom expiry time as 0 so that every time our app gets the latest values from the config.
    button.setOnClickListener(new View.OnClickListener() {
               @Override
               public void onClick(View v) {
                   /*
                    This will initiate fetching of parameters. We have set the expiry time as 0
                    which will ensure we get fresh parameters every time
                    */
                   firebaseRemoteConfig.fetch(0).addOnCompleteListener(new OnCompleteListener<Void>() {
                       @Override
                       public void onComplete(@NonNull Task<Void> task) {
                           if (task.isSuccessful()){
                               Toast.makeText(MainActivity.this, "Activated", Toast.LENGTH_SHORT).show();
                           }else {
                               Toast.makeText(MainActivity.this, "Not Activated", Toast.LENGTH_SHORT).show();
                           }
                       }
                   });
               }
           });

Activating Fetched Parameters

  • Even after a successful fetch request when you try to get the values using get<>() APIs old values are returned. Remember how they are three configs (Active, Fetched and Default) and only active config is accessible from your app. Therefore in order for the fetched config parameters to be available you need to activate them using firebaseRemoteConfig.activateFetched(). This will move all the parameters from the fetched config to active config thereby making them accessible from the app.
  • This concept of parameter activation is to improve user experience and avoid any abrupt changes in behavior or design of the app when you are still navigating the app.
  • In the following example we activate the fetched parameters in the OnClick listener as shown below. After activation if you try to retrieve values using get() APIs the new parameter values will be returned. In this example we just activate the new values but don’t “get” them immediately in OnClick listener
    button.setOnClickListener(new View.OnClickListener() {
               @Override
               public void onClick(View v) {
                   /*
                    This will initiate fetching of parameters. We have set the expiry time as 0
                    which will ensure we get fresh parameters every time
                    */
                   firebaseRemoteConfig.fetch(60*5).addOnCompleteListener(new OnCompleteListener<Void>() {
                       @Override
                       public void onComplete(@NonNull Task<Void> task) {
                           if (task.isSuccessful()){
                               Toast.makeText(MainActivity.this, "Activated", Toast.LENGTH_SHORT).show();
                               /*
                               Activiting fetched parameters. The new parameters will now be available to your app
                                */
                               firebaseRemoteConfig.activateFetched();
                           }else {
                               Toast.makeText(MainActivity.this, "Not Activated", Toast.LENGTH_SHORT).show();
                           }
                       }
                   });
               }
           });

Just be reminded that so far we have not created any parameters on the Firebase Console. Since we only have default in app parameters defined these will only be returned even if we try to calling fetch() or get()

Complete Activity

This finishes our client side implementation for Firebase remote config. Our complete activity will now look as the code snippet below. 

public class MainActivity extends AppCompatActivity {

    private FirebaseRemoteConfig firebaseRemoteConfig;

    private Button button;

    private TextView textView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
       
        button = findViewById(R.id.fetch);
        textView= findViewById(R.id.text);
        firebaseRemoteConfig = FirebaseRemoteConfig.getInstance();
        firebaseRemoteConfig.setConfigSettings(new FirebaseRemoteConfigSettings.Builder()
                .setDeveloperModeEnabled(true)
                .build());
        firebaseRemoteConfig.setDefaults(R.xml.default_map);

        /*
        Setting color, size and string for TextView using parameters returned from
        remote config server
         */
        textView.setTextColor(Color.parseColor(firebaseRemoteConfig.getString("text_color")));
        textView.setTextSize((float) firebaseRemoteConfig.getValue("text_size").asDouble());
        textView.setText(firebaseRemoteConfig.getString("text_str"));

        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                /*
                 This will initiate fetching of parameters. We have set the expiry time as 0
                 which will ensure we get fresh parameters every time
                 */
                firebaseRemoteConfig.fetch(60*5).addOnCompleteListener(new OnCompleteListener<Void>() {
                    @Override
                    public void onComplete(@NonNull Task<Void> task) {
                        if (task.isSuccessful()){
                            Toast.makeText(MainActivity.this, "Activated", Toast.LENGTH_SHORT).show();
                            /*
                            Activiting fetched parameters. The new parameters will now be available to your app
                             */
                            firebaseRemoteConfig.activateFetched();
                        }else {
                            Toast.makeText(MainActivity.this, "Not Activated", Toast.LENGTH_SHORT).show();
                        }
                    }
                });
            }
        });

    }
}
  • Note that we initiate fetching latest params from server only on click of button. Getting parameters before that will return values from the default map. Therefore in first launch of app we see the default in app values displayed (Screenshot below)
  • Also note that we have not defined any parameters for this app on remote config server yet. So even clicking the button and requesting using fetch() would return the default in-app values only.

Adding Parameters to Console

In this section we will add the parameters to the remote config server. So far we had only defined the parameters in app

  • Go to Firebase Console and select the project your created in step 1.
  • Once the project is selected click Grow > Remote Config in the left pane. Look at screenshot for reference.
  • Now click the “Add your first parameter” button and then add a string as shown in the screenshot below. Keep the parameter key same as the default one defined in your app map. I created a parameter with string value “Hello Android Clarified! Its working”.
  • Similarly add parameters to define your text size and and text colour. Again the parameter key should be same as the one defined in your app
  • After adding you need to publish this parameters to make them accessible from your app. Just click the Publish Changes button on the upper right corner of your console. Look at the screenshot above reference

Fetching from Server

  • Now clicking “Fetch” button in your app will request the parameters values from server. But notice that even after clicking fetch the text immediately doesn’t change. This is because after the request is successful we just activate the latest parameters but don’t retrieve them to update the text. So in order for the changes to reflect you need to restart the app. This will ensure on onCreate() is called again and latest parameters are retrieved from active config using get<>() APIs.

Conclusion

This finishes our Firebase Remote Config example. If properly implemented Firebase remote config can give developers complete control over app behaviour across all the versions. I hope this tutorials helps you in understanding Firebase. Feel free to comment any questions.

If you liked this tutorial you can find more at Android Examples 

OkHttp Interceptor for Retrofit2 | With Example

This tutorial only focuses on OkHttp Interceptor. If you want to learn how to send a network request with Retrofit from basics read this

In our last post we have learnt how to send a network request with Retrofit on Android. While Retrofit makes sending HTTP requests quite simple it also allows a unique mechanism to monitor and rewrite these requests. This is implemented with the help of OkHttp Interceptor. Intercept – the word means “to obstruct something from reaching its destinations”, similarly Interceptors obstruct a request, rewrite it and then send it to the destinations(server). For example suppose you need all the HTTP requests sent from your app to have authorization token as header. Instead of dynamically adding the same header to all the endpoints as shown here you can simply add a interceptor which will be invoked every time you send a request.

The official explanation for Interceptors is

Interceptors are to observe, modify and potentially short-circuits requests going out and the corresponding responses coming back in. Typically interceptors add, remove, or transform headers on the request  or response.

Interceptors are basically of two types

  • Application Interceptors
    These are high level interceptors which are used to intercept request and response. They are usually used to rewrite headers/query of both request and response. These are definitly invoked once even if the response is fetched from cache.
  • Network Interceptors
    These are low level interceptors used to monitor requested just as it is transmitted over the network. Are very useful to follow redirects and retries and give access to various low level details of the request. These are not invoked if the response is cached.

The diagram below explains the difference between Network and Application Interceptors

interceptors.png

Creating Interceptors

Creating or defining a Interceptor is very simple. You just need to implement the Interceptor interface and override the intercept() method as shown below.  The same interface implementation works for both  NetworkInterceptor and ApplicationInterceptor

private static class CustomInterceptor implements Interceptor {

    @Override
    public Response intercept(Chain chain) throws IOException {
        /*
        chain.request() returns original request that you can work with(modify, rewrite)
        */
        Request request = chain.request();

        // Here you can rewrite the request

        /*
        chain.proceed(request) is the call which will initiate the HTTP work. This call invokes the
        request and returns the response as per the request.
        */
        Response response = chain.proceed(request);

        //Here you can rewrite/modify the response

        return response;
    }
}

 

A call to chain.proceed(request) is a critical part of each interceptor’s implementation. This simple-looking method is where all the HTTP work happens, this is where the request is initiated and a response is fetched to satisfy the request.

Once you have defined your interface you can register it with the OkHttp client as shown below. Now you should register this client with Retrofit.Builder thereby for all your requests OkHttp client will be used and your interceptor will be invoked

OkHttpClient okHttpClient = new OkHttpClient.Builder()
    .addInterceptor(new CustomInterceptor()) // This is used to add ApplicationInterceptor.
    .addNetworkInterceptor(new CustomInterceptor()) //This is used to add NetworkInterceptor.
    .build();

//Defining the Retrofit using Builder
Retrofit retrofit = new Retrofit.Builder()
    .baseUrl(BASE_URL) //This is the onlt mandatory call on Builder object.
    .client(okHttpClient) //The Htttp client to be used for requests
    .addConverterFactory(GsonConverterFactory.create()) // Convertor library used to convert response into POJO
    .build();

 

 

Logging Request and Response

As developers it is very important that we log the requests/responses which are sent and received  from the app. These logs give us details about the headers, response body, request body and various other details which are crucial for debugging any error. Thanks to Interceptors logging all the HTTP operations on Android is very simple.

Retrofit provides us with a Custom Interceptor – HttpLoggingInterceptor which can be registered with OkHttpClient. With this you will be able to print all the logs for the HTTP operations through this client.

HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);

OkHttpClient client = new OkHttpClient.Builder().addInterceptor(interceptor).build();

Retrofit retrofit = new Retrofit.Builder()
        .baseUrl("https://backend.example.com")
        .client(client)
        .addConverterFactory(GsonConverterFactory.create())
        .build();

 

Rewriting Requests- Adding/Removing Headers

We have already seen how to define a Custom Interceptor. Now in this section we will define a Custom Interceptor to modify the headers sent with a network request.

private static class RequestInterceptor implements Interceptor {

    @Override
    public Response intercept(Chain chain) throws IOException {
        /*
        chain.request() returns original request that you can work with(modify, rewrite)
        */
        Request originalRequest = chain.request();

        Headers headers = new Headers.Builder()
            .add("Authorization", "auth-value")
            .add("User-Agent", "you-app-name")
            .build();

        Request newRequest = originalRequest.newBuilder()
            .addHeader("Authorization", "auth-value") //Adds a header with name and value.
            .addHeader("User-Agent", "you-app-name")
            .cacheControl(CacheControl.FORCE_CACHE) // Sets this request's Cache-Control header, replacing any cache control headers already present.
            .headers(headers) //Removes all headers on this builder and adds headers.
            .method(originalRequest.method(), null) // Adds request method and request body
            .removeHeader("Authorization") // Removes all the headers with this name
            .build();

        /*
        chain.proceed(request) is the call which will initiate the HTTP work. This call invokes the
        request and returns the response as per the request.
        */
        Response response = chain.proceed(newRequest);

        return response;
    }

}

 

Rewriting Response with OKHttp Interceptor

Similarly, OkHttp Interceptor can be used to rewrite/ modify response from the server. With this you can not only rewrite response headers but also can make changes to the response body.

In the example below we read the response code and build a new response body based on the response code.

private static class ResponseInterceptor implements Interceptor {

    @Override
    public Response intercept(Chain chain) throws IOException {
        // We obtain the response using chain.proceed() API. This invokes the request and return the response
        Response response = chain.proceed(chain.request());
        try {

            JSONObject jsonObject = new JSONObject();

            if (response.code() == 200) {
                jsonObject.put("code", 200);
                jsonObject.put("status", "OK");
                jsonObject.put("message", new JSONObject(response.body().string()));
            } else {
                jsonObject.put("code", 404);
                jsonObject.put("status", "ERROR");
                jsonObject.put("message", new JSONObject(response.body().string()));
            }
            MediaType contentType = response.body().contentType();
            ResponseBody body = ResponseBody.create(contentType, jsonObject.toString());
            return response.newBuilder().body(body).build();
        } catch (JSONException e) {
            e.printStackTrace();
        }

        return response;
    }
}

Android Image Upload Example | Multipart Retrofit2

This tutorial only discusses Android image upload using multipart with Retrofit2. If you want to learn about sending HTTP requests using Retrofit2 from basics read this.

Why use Multipart to Upload Image ?

Before diving deep into Android Image upload, its important to understand some basics of HTTP requests. Most importantly how are different types of data sent to server. POST requests are used to send data to server, this data can either be simple readable text fields or sometimes even non alphanumeric binary data(like image files).  In our last tutorial6 we saw how to send a simple POST request with retrofit. To facilitate sending different types of data we have different methods given below

With application/x-www-form-urlencoded, the body of the HTTP message sent to the server is essentially one giant query string — name/value pairs are separated by the ampersand (&), and names are separated from values by the equals symbol (=). But for each non-alphanumeric byte that exists in one of our values, it’s going to take three bytes to represent it. This is very inefficient for sending large files hence this method cannot be used for sending image files

That’s where  multipart/form-data  comes in. Multipart sends a single object(file) in various parts, each part is separated by a boundary and has some portion of object’s data. Each part also has its own headers like Content-Type, Content-Deposition. Below is a sample representation of multipart request to upload two file a.txt and a.html

POST / HTTP/1.1
[[ Less interesting headers ... ]]
Content-Type: multipart/form-data; boundary=---------------------------735323031399963166993862150
Content-Length: 834

-----------------------------735323031399963166993862150
Content-Disposition: form-data; name="text1"

text default
-----------------------------735323031399963166993862150
Content-Disposition: form-data; name="text2"

aωb
-----------------------------735323031399963166993862150
Content-Disposition: form-data; name="file1"; filename="a.txt"
Content-Type: text/plain

Content of a.txt.

-----------------------------735323031399963166993862150
Content-Disposition: form-data; name="file2"; filename="a.html"
Content-Type: text/html

<!DOCTYPE html><title>Content of a.html.</title>

-----------------------------735323031399963166993862150
Content-Disposition: form-data; name="file3"; filename="binary"
Content-Type: application/octet-stream

aωb
-----------------------------735323031399963166993862150--

 

This efficiency of sending single file in multiple parts is the reason most of the browsers use Multipart to upload files. Retrofit is one of the few network libraries which has built in support for Multipart. This enables you  to upload any files from your app without worrying of any of the internal details of Multipart.

Android Image Upload

In the following example we will be uploading a Image file to Server using Multipart with Retrofit2. As per the scope of this example we will only cover how to upload a image/file on server but if you want to first learn how to pick image from gallery/camera please read this example

Step 1 : Add Gradle dependencies

implementation 'com.squareup.retrofit2:retrofit:2.3.0'
implementation 'com.squareup.retrofit2:converter-gson:2.3.0'

Step 2 : Create Retrofit Instance

Create a class NetworkClient.java  to retrieve the Retrofit object anywhere in your application. This instance will be used to send the HTTP request from your app.

public class NetworkClient {

    private static final String BASE_URL = "";
    private static Retrofit retrofit;

    public static Retrofit getRetrofitClient(Context context) {

        if (retrofit == null) {
            OkHttpClient okHttpClient = new OkHttpClient.Builder()
                    .build();
            retrofit = new Retrofit.Builder()
                    .baseUrl(BASE_URL)
                    .client(okHttpClient)
                    .addConverterFactory(GsonConverterFactory.create())
                    .build();

        }

        return retrofit;
    }
    
}

Step 3 : Define the Upload API

We know that with Retrofit2, interface methods are used to  define the APIs with which the app will be interacting. Therefore for uploading an image we define the following API. Note the use of @Multipart and @Part

ublic interface UploadAPIs {
    @Multipart
    @POST("/upload")
    Call<ResponseBody> uploadImage(@Part MultipartBody.Part file, @Part("name") RequestBody requestBody);
}

 

@Multipart 
Denotes that the request body is multi-part. Parts should be declared as parameters and annotated with @Part.

@Part
This denotes a single part of Multipart request. The parameter on which this type exists will be processed in three ways

  • If the parameter type is MultipartBody.Part the contents will be used directly. Part name is not required with the annotation (i.e., @Part MultipartBody.Part part).
  • If the parameter  type is RequestBody the value will be used directly with its content type. Supply the part name in the annotation (e.g., @Part("foo") RequestBody foo).
  • Other object types will be converted to an appropriate representation by using a converter. Supply the part name in the annotation (e.g., @Part("foo") Image photo).

 

Step 4 : Uploading an Image

Now comes most important part- Uploading a File. Input parameter to this method is a simple image file path. As already mentioned if you want to learn how to get file path of the images from gallery/camera read this tutorial

  • Using the file path we create a file object and then create a request body with that image file. Now with the request body we create a MultipartBody.Part by passing file name and part name as shown in the snippet below. This MultipartBody.Part is sent to Retrofit to initiate image upload
  • We can even send some text fields along with the image. Make sure server is able to handle all tha parts that you are sending. Since this is a demo example I am just sending a sample description text request body along with the image.
  • Both  the text and image are sent as parts along with the mutipart requests

 

private void uploadToServer(String filePath) {
     Retrofit retrofit = NetworkClient.getRetrofitClient(this);

     UploadAPIs uploadAPIs = retrofit.create(UploadAPIs.class);

     //Create a file object using file path
     File file = new File(filePath);

     // Create a request body with file and image media type
     RequestBody fileReqBody = RequestBody.create(MediaType.parse("image/*"), file);

     // Create MultipartBody.Part using file request-body,file name and part name 
     MultipartBody.Part part = MultipartBody.Part.createFormData("upload", file.getName(), fileReqBody);

     //Create request body with text description and text media type
     RequestBody description = RequestBody.create(MediaType.parse("text/plain"), "image-type");

     // 
     Call call = uploadAPIs.uploadImage(part, description);

     call.enqueue(new Callback() {
         @Override
         public void onResponse(Call call, Response response) {

         }

         @Override
         public void onFailure(Call call, Throwable t) {

         }
     });

 }

Conclusion

This finishes our fully functional Android Image Upload Example, but in software development just getting something working is not enough. One of the major characteristic of a good programmer is that he writes clean code. And the best tips and guidelines for clean code are mentioned in this book by noted software expert Robert C. Martin. It is a must read for every software engineer.


If you are new to Android you should definitely go through the list of Android examples here. It is a must read for every Android Developer
sexy Indian girls

Android DownloadManager Example [Complete Tutorial]

We have a separate tutorial section on this website for HTTP operations. Over there we have already covered all the different network operations like sending a GET/POST request, uploading images, logging request, adding headers etc. We have used two of the most popular Libraries- Volley and Retrofit which provide complete support for all these network operations. But when it comes to downloading large files you cant use Retrofit or Volley, both of these recommend using DownloadManager. And that is what today’s tutorial is all about – DownloadManager Example

The DownloadManager is a system service that handles long-running HTTP downloads. Clients may request that a URI be downloaded to a particular destination file.

Here are some advantages of using DownloadManager

  • It performs all the HTTP interaction on background thread by default. You dont need to create any thread.
  • It gracefully handles connectivity issues if the network changes or device reboots by automatically retrying download after failure due to any reason.
  • It provides features like pause/ resume download thereby improving user experience.
  • Has a in built mechanism  to inform the user of download progress using notification.

Downloading a File

In this section of DownloadManager Example we will prepare our download request and initiate the File Download  

Add Permissions

First step in this DownloadManager Example is to add INTERNET permission to the AndroidManifest.xml

<uses-permission android:name="android.permission.INTERNET"/>

Create Activity

We need to create only one Activity in this DownloadManager Example which will have a button to initiate the download of file. Following is the layout file for this activity

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.example.irshadkumail.downloadexample.MainActivity">

    <Button
        android:layout_width="wrap_content"
        android:id="@+id/download"
        android:text="DOWNLOAD"
        android:layout_centerInParent="true"
        android:layout_height="wrap_content" />


</RelativeLayout>

Now in our Java file of the Activity we initialize the button and set up a click listener as shown below

public class MainActivity extends AppCompatActivity {

    private Button button;

    private long downloadID;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        button=findViewById(R.id.download);

        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
            }
        });
    }
}
  • Note that we have also created a global long variable which will be used to store download identifier id. More about this in next section

Prepare the DownloadManager.Request

Before starting the download we need to create a  DownloadManager.Request object with all the details of the download and conditions to start it. DownloadManager.Request has provided us with multiple APIs to set information necessary to begin the download. The only mandatory information to start a download is network URI. Even if you have not specified any destination, Android stores the downloaded file in a shared storage . Below code snippet shows how we prepare our DownloadManager.Request with all the details.

       File file=new File(getExternalFilesDir(null),"Dummy");
       /*
       Create a DownloadManager.Request with all the information necessary to start the download
        */

       DownloadManager.Request request=new DownloadManager.Request(Uri.parse("http://speedtest.ftp.otenet.gr/files/test10Mb.db"))
               .setTitle("Dummy File")// Title of the Download Notification
               .setDescription("Downloading")// Description of the Download Notification
               .setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE)// Visibility of the download Notification
               .setDestinationUri(Uri.fromFile(file))// Uri of the destination file
               .setRequiresCharging(false)// Set if charging is required to begin the download
               .setAllowedOverMetered(true)// Set if download is allowed on Mobile network
               .setAllowedOverRoaming(true);// Set if download is allowed on roaming network

     
   

Following are some important APIs used to set information of the download

  • setNotificationVisibility(int)
    This API is to control whether a system notification is shown while this download is running or when it is completed.
    It can takes any of the following predefined values: 
    #VISIBILITY_HIDDEN
    #VISIBILITY_VISIBLE 
    #VISIBILITY_VISIBLE_NOTIFY_COMPLETED
    If set to VISIBILITY_HIDDEN, this requires the permission android.permission.DOWNLOAD_WITHOUT_NOTIFICATION.
  •  setDescription(String), setTitle(String)
    These APIs are used to set the description and title of the download notification (if displayed).
  • setDestinationInExternalFilesDir(Context ,String,String) , setDestinationUri(Uri), setDestinationInExternalPublicDir(String,String)
    These APIs are used to set the destination file path of the downloaded file. You can start a download even without specifying the destination, in which case file is temporarily stored in shared storage. Also if you are storing the file in external storage you need to add STORAGE permissions in the Manifest.
  • addRequestHeader(String,String)
    This API is used to add a request header to the HTTP request used to download the file

Apart from these they are a lot of other APIs like setAllowedOverRoaming(), setRequiresCharging(), setAllowedOverMetered()  etc which define the conditions for the download to start. We have not used all the APIs in this DownloadManager Example but you can read more about them here.

Initiate the download

Once the DownloadManager.Request is ready with all the information you can start the download as shown in snippet below

DownloadManager downloadManager= (DownloadManager) getSystemService(DOWNLOAD_SERVICE);
downloadID = downloadManager.enqueue(request);// enqueue puts the download request in the queue.
  • enqueue(request) returns  a unique long ID which acts as an identifier for the download. Note that calling enqueue() doesnt necessarily start the download immediately. It rather schedules the download request in a queue. Once the DownloadManager is free is starts the download.
  • Important thing to note is how we initialize global variable downloadID . enqueue() returns an ID for the download, unique across the system. Global variable downloadID is used to store this ID. It is used to reference this download in future.

Listen to Download Complete

So far in this DownloadManager Example we saw to initiate downloading a file in Android. This section covers how to be notified when your download is completed.

One thing to note is that DownloadManager  is a separate system service which downloads files requested by client. Here your app is the client and once you call enqueue() from your app it is now the responsibility of DownloadManager to schedule that download and save the file at destination. Therefore it is important that the client is informed when the download is completed. Android DownloadManager sends a ACTION_DOWNLOAD_COMPLETE broadcast intent when any download is completed. You can listen for this broadcast using a BroadcastReceiver and identify if your download is completed using the unique long ID returned by enqueue().

Not sure what Broadcast is and How does BroadcastReceiver work?  Read this simple tutorial

You can be notified when your download is complete by following three steps

  • Create a BroadcastReceiver as shown in snippet below.Inside the receiver we just check if the received broadcast is for our download by matching the received download id with our enqueued download.
    private BroadcastReceiver onDownloadComplete = new BroadcastReceiver() {
           @Override
           public void onReceive(Context context, Intent intent) {
    
               //Fetching the download id received with the broadcast
               long id = intent.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID, -1);
    
               //Checking if the received broadcast is for our enqueued download by matching download id
               if (downloadID == id) {
                   Toast.makeText(MainActivity.this, "Download Completed", Toast.LENGTH_SHORT).show();
               }
    
           }
       };
  • Once the BroadcastReceiver is created you can register for ACTION_DOWNLOAD_COMPLETE in the onCreate method of your activity. This ACTION_DOWNLOAD_COMPLETE broadcast is fired everytime any file download is completed by DownloadManager.
    @Override
       protected void onCreate(Bundle savedInstanceState) {
           super.onCreate(savedInstanceState);
           setContentView(R.layout.activity_main);
    
           button=findViewById(R.id.download);
           registerReceiver(onDownloadComplete,new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE));
           button.setOnClickListener(new View.OnClickListener() {
               @Override
               public void onClick(View view) {
                   beginDownload();
               }
           });
       }
  • It is also important that you unregister the BroadcastReceiver in onDestroy. This ensures you only listen for this broadcast as long as the activity is active
    @Override
      public void onDestroy() {
          super.onDestroy();
          unregisterReceiver(onDownloadComplete);
      }
    

     

DownloadManager Example: Complete Code

This completes DownloadManager Example. Below is the complete code of your Activity

public class MainActivity extends AppCompatActivity {

    private Button button;

    private long downloadID;

    private BroadcastReceiver onDownloadComplete = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {

            //Fetching the download id received with the broadcast
            long id = intent.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID, -1);

            //Checking if the received broadcast is for our enqueued download by matching download id
            if (downloadID == id) {
                Toast.makeText(MainActivity.this, "Download Completed", Toast.LENGTH_SHORT).show();
            }

        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        button=findViewById(R.id.download);
        registerReceiver(onDownloadComplete,new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE));
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                beginDownload();
            }
        });
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        unregisterReceiver(onDownloadComplete);
    }

    private void beginDownload(){

        File file=new File(getExternalFilesDir(null),"Dummy");
        /*
        Create a DownloadManager.Request with all the information necessary to start the download
         */

        DownloadManager.Request request=new DownloadManager.Request(Uri.parse("http://speedtest.ftp.otenet.gr/files/test10Mb.db"))
                .setTitle("Dummy File")// Title of the Download Notification
                .setDescription("Downloading")// Description of the Download Notification
                .setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE)// Visibility of the download Notification
                .setDestinationUri(Uri.fromFile(file))// Uri of the destination file
                .setRequiresCharging(false)// Set if charging is required to begin the download
                .setAllowedOverMetered(true)// Set if download is allowed on Mobile network
                .setAllowedOverRoaming(true);// Set if download is allowed on roaming network

        DownloadManager downloadManager= (DownloadManager) getSystemService(DOWNLOAD_SERVICE);
        downloadID = downloadManager.enqueue(request);// enqueue puts the download request in the queue.
    }


}

 

We hope you are now clear on how to download files on Android. You can even learn how to upload files on Android by reading this simple tutorial

FusedLocationProviderClient | Get Current Location Android Example

So far we had used FusedLocationProviderApi to fetch user’s location. But as of Google Play Services version 11.6.0, it has been depreciated and now Google recommends us to use FusedLocationProviderClient. In this tutorial we will be explaining why FusedLocationProviderClient is better and how should we implement it.

FusedLocationProviderClient is the main entry point to Google’s LocationServices. With this your app no longer needs to manually manage connections to Google Play Services through GoogleApiClient.

 

If you want to check how current location was fetched with now depreciated FusedLocationProviderAPI read this

Why FusedLocationProviderClient ?

Google’s LocationServices API is the one which is actually used to access device location. To access these services your app needs to connect to Google Play Services. With FusedLocationProviderApi it was our responsibility to initiate and manage the connection. Below code snippet might remind you of how complicated it was to connect to Google Play Services

public class MapsActivity extends FragmentActivity implements GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener {

        private GoogleApiClient googleApiClient;

        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_maps);

            //Instantiating the GoogleApiClient
            googleApiClient = new GoogleApiClient.Builder(this)
                .addApi(LocationServices.API)
                .addConnectionCallbacks(this)
                .addOnConnectionFailedListener(this)
                .build();

        }

        public void onStart() {
            super.onStart();
            // Initiating the connection
            googleApiClient.connect();
        }

        public void onStop() {
            super.onStop();
            // Disconnecting the connection
            googleApiClient.disconnect();

        }

        //Callback invoked once the GoogleApiClient is connected successfully
        @Override
        public void onConnected(Bundle bundle) {
            //Fetching the last known location using the FusedLocationProviderApi
        }

        @Override
        public void onConnectionSuspended(int i) {

        }

        //Callback invoked if the GoogleApiClient connection fails
        @Override
        public void onConnectionFailed(ConnectionResult connectionResult) {

        }
}

 

As you can see, before we could fetch location we first had to initiate the connection to GooglePlayServices and only after the connection was successful we could fetch location. And if we tried to fetch the location before the connection is complete it would lead to a FATAL IllegalStateException. This approach has a lot of issues like

  • The scenario in which connection to GooglePlayServices fails or is cancelled is not handled.
  •  It would be difficult to share the location between multiple activities without repeating the connection logic again
  • For a app which just wants to fetch location understanding and managing this connection logic every time would be an unnecessary and extra effort

Advantages with FusedLocationProviderClient

  • It takes the complete connection logic under the hood. User no longer needs to initialize GoogleApiClient nor does he need to manage the connection logic.
  • It returns the result as a Task object which is easy to a manage and share.
  • User need not wait until the connection is established to request for a Location. When requesting for the current location the API call automatically waits until the connection is estabilished thereby minimising the chances of an IllegalStateException

It’s recommended to use Google Play services version 11.6.0 or higher, which includes bug fixes for this class.

Example: Fetching Current Location

In this example we have a button in an Activity which when clicked would fetch the current location of the user using FusedLocationProviderClient.

  • App permissions need to be defined in the Manifest file. Thereby the first step would be to add the Location permissions in the AndroidManifest.xml
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
  • Fused Location provider is a part of Google Play Services therefore we need to include the google play services as dependency in build.gradle.
    implementation 'com.google.android.gms:play-services:11.6.0'
  • Add a button to the layout file of the Launcher Activity
    <?xml version="1.0" encoding="utf-8"?>
    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
        
        <Button
            android:layout_width="wrap_content"
            android:id="@+id/button"
            android:text="FETCH Location"
            android:layout_centerInParent="true"
            android:layout_height="wrap_content" />
    
    </RelativeLayout>
    
  • Now initialize that button and implement the OnClickListener in your MainActivity.java file.
    public class MainActivity extends AppCompatActivity implements View.OnClickListener {
        Button button;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            button = findViewById(R.id.button);
            button.setOnClickListener(this);
    
        }
    
        @Override
        public void onClick(View view) {
            switch (view.getId()) {
                case R.id.button:
                    break;
            }
        }
    }

     

  • As of Android Marshmallow Location permissions need to be explicitly approved by the user before the app begins to collect device location. To learn more about this read this.
  • We had already mentioned that FusedLocationProviderClient takes care of all the connection logic on its own. Therefore we don’t need to initialize GoogleApiClient nor do we need to implement connection callbacks. We only need to initialize the FusedLocationProviderClient as shown below
    FusedLocationProviderClient fusedLocationProviderClient=LocationServices.getFusedLocationProviderClient(this);
  • Once we have FusedLocationProviderClient we can fetch the current location using the getLastLocation() API. It returns Task object which represents a asynchronous operation. Read more about Task API here.
    Task<Location> task = fusedLocationProviderClient.getLastLocation();
  • We will add the success callback listener to the Task object which will be invoked once the connection is established and the location is fetched.
    task.addOnSuccessListener(new OnSuccessListener<Location>() {
        @Override
        public void onSuccess(Location location) {
           if(location!=null) {
                //Write your implemenation here
                Log.d("AndroidClarified",location.getLatitude()+" "+location.getLongitude());      }
           }
    });

    You must have noticed we add a null check for location in OnSuccessListener. This is to avoid crashes in some scenarios in which the location can be null. Below are some of these scenarios

  • GPS is turned off in the device settings.
  • Location was never recorded on the devices.  This could be the case of a new device or a device that has been restored to factory settings.

Complete Activity

  • Below code snippet shows how your activity will look after the complete implementation. Current Location is received  in the onSuccessListener added on the task object as shown below
public class MainActivity extends AppCompatActivity implements View.OnClickListener {

    Button button;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        button = findViewById(R.id.button);
        button.setOnClickListener(this);

    }

    @Override
    public void onClick(View view) {
        switch (view.getId()) {
            case R.id.button:
                if (ActivityCompat.checkSelfPermission(this, android.Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, android.Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
                   
                    return;
                }
                FusedLocationProviderClient fusedLocationProviderClient = LocationServices.getFusedLocationProviderClient(this);
                Task task = fusedLocationProviderClient.getLastLocation();
                task.addOnSuccessListener(new OnSuccessListener() {
                    @Override
                    public void onSuccess(Location location) {

                    }
                });
                break;
        }
    }
}
  • This is how current location is fetched with FusedLocationProviderClient. If you want to learn how to display this location map you can read this.
  • We also have a amazing collection of Android Examples which will help you become a better developer. Make sure you read them

Sliding Images with ViewPager Example | PagerAdapter

In this ViewPager example we will create an application which displays a sequence of  Images in ViewPager with help of PagerAdapter. We will also implement a CirculerIndicator to indicate the current view.

ViewPager is a layout manager which allows user to flip left and right through pages of data. Such interaction enriches user experience and is useful in displaying sequence of pages seamlessly. This is the reason why many modern apps use ViewPager extensively.

ViewPager is popularly used with fragments. Over there each fragment acts as a page and user can view multiple fragments by just swiping left and right on the screen. With fragments developers have a much wider range of possibility to show in a single page as each fragment has its own layout file and lifecycle. But there might be lot of cases where we don’t need such complex pages in our ViewPager. To visualize you can think of  a  ecommerce app which wants to display sliding banners of daily offers on its home screen as shown below. In these scenarios we can use simple Views instead of Fragments

 

Step 1 Adding Dependencies

For this ViewPager example to work add the following in your build.gradle

implementation 'com.android.support:appcompat-v7:26.1.0'
implementation 'me.relex:circleindicator:1.2.2@aar'

Step 2 Design layout for your activity

Add ViewPager and CircleIndicator to your layout file as shown below

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.example.irshadkumail.pagerexample.MainActivity">
  <android.support.v4.view.ViewPager
        android:id="@+id/view_pager"
        android:layout_width="match_parent"
        android:layout_height="220dp" />
  <me.relex.circleindicator.CircleIndicator
        android:id="@+id/circle"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignBottom="@id/view_pager"
        android:layout_centerHorizontal="true"
        android:padding="16dp" />
</RelativeLayout>

 

Step 3 Layout File for ViewPager Item

Create a layout file pager_item.xml. This layout file will be used for each page of your ViewPager. Since we are just displaying sequence of different images we can use the same layout for all our pages.

<?xml version="1.0" encoding="utf-8"?>
<ImageView xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="horizontal"
    android:id="@+id/image"
    android:layout_width="match_parent"
    android:layout_height="220dp"></ImageView>

</ImageView>

 

Step 4 Creating PagerAdapter

Whether the pages are Fragment or Views, Adapter is what creates and provides pages to your ViewPager. For fragment we usually implement FragmentStatePagerAdapter whereas for Views we will be implementing PagerAdapter.

When implementing PagerAdapter it is mandatory to override these methods

  • instantiateItem() :  This is to create a page at a given position in your ViewPager.  It returns a Object variable representing the page.
  • destroyItem() :   This is to destroy a page at a given position in your ViewPager. One of the parameter passed is the Object variable returned by the instantiateItem() method.
  • getCount() : Returns the total count of pages/views in your ViewPager.
  • isViewFromObject() : This method is required by PagerAdapter to function properly. It determines whether the page view is associated with the specific object returned by instantiateItem() 

You must have noticed that instantiateItem, which creates a page view, returns a Object variable instead of a View. This is because ViewPager associates each page with a key object rather than a View. This key is used to track and uniquely identify a given page independent of its position in the adapter. For the same reason we need isViewFromObject() to determine which view belongs to which key.

In this example we will use View only as key object, thereby directly returning the View in instantiateItem() after adding it to the parent ViewGroup. Similarly in destroyItem() we will remove the View passed as a Param from the parent ViewGroup. isViewFromObject will simply return view == object which will always be true.

public class MyPager extends PagerAdapter {

    private Context context;

    public MyPager(Context context) {

        this.context = context;
    }

    /*
    This callback is responsible for creating a page. We inflate the layout and set the drawable
    to the ImageView based on the position. In the end we add the inflated layout to the parent
    container .This method returns an object key to identify the page view, but in this example page view
    itself acts as the object key
    */

    @Override
    public Object instantiateItem(ViewGroup container, int position) {

        View view = LayoutInflater.from(context).inflate(R.layout.linear_layout, null);
        ImageView imageView = view.findViewById(R.id.image);
        imageView.setImageDrawable(context.getResources().getDrawable(getImageAt(position)));
        container.addView(view);
        return view;
    }

    /*
    This callback is responsible for destroying a page. Since we are using view only as the
    object key we just directly remove the view from parent container
    */
    @Override
    public void destroyItem(ViewGroup container, int position, Object view) {

        container.removeView((View) view);

    }

    /*
    Returns the count of the total pages
    */
    @Override
    public int getCount() {
        return 4;
    }

    /*
    Used to determine whether the page view is associated with object key returned by instantiateItem.
    Since here view only is the key we return view==object
    */

    @Override
    public boolean isViewFromObject(View view, Object object) {
        return object == view;
    }

    private int getImageAt(int position) {
        switch (position) {
            case 0:
                return R.drawable.india_taj_mahal;
            case 1:
                return R.drawable.colosseum;
            case 2:
                return R.drawable.eiffel_tower;
            case 3:
                return R.drawable.statue_of_liberty;
            default:
                return R.drawable.india_taj_mahal;
        }

    }

}

 

Step 5 

Once we have implemented PagerAdapter we just need to instantiate it in our MainActivity and associate it with the ViewPager. For the Circularindicator we just need to associate it with the ViewPager and it takes care of the rest on its own.

public class MainActivity extends AppCompatActivity {

    private ViewPager viewPager;

    private CircleIndicator circleIndicator;

    private MyPager myPager;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        myPager = new MyPager(this);
        viewPager = findViewById(R.id.view_pager);
        viewPager.setAdapter(myPager);
        circleIndicator = findViewById(R.id.circle);
        circleIndicator.setViewPager(viewPager);

    }
}

 

 

viewpager example

This completes our ViewPager Example . Above GIF gives a visual representation of how our app will look after this implementation. These sliding images definitely adds a visual appeal to your app.

We have a amazing collection of Android Examples which could help you become a better developer. Make sure you read them

Android Intent | Complete Tutorial with Example

Apart from the four Android components there is one more basic concept in Android which every beginner in Android Development should be aware of. The concept of Android Intent. Intents are used to request any action/operation from any android component of the same application, another application on the device. For example, consider you want to click a  picture in your application. Intents enable you to simply request camera app to click a picture and deliver the picture back to your application. They basically connect Android components with each other. Android defines Intents as the following

An Intent is a messaging object you can use to request an action from another app component.

The most common use of Android Intent is to start any of the three most important components in Android- Activity, Service, BroadcastReceiver

  • Activity
    You can start activity by calling startActivity(Intent) and passing an intent describing the target activity
  • Service
    Similar to Activities, Services can also be started using startService(Intent) and passing an Intent describing the Service
  • BroadcastReceiver
    Broadcasts are also delivered using Intents. You can notify other apps of any event by sending Broadcasts from your app using sendBroadcast(Intent) and passing the Intent describing the event.

 

Building an Android Intent

Android Intent object is a passive data structure holding abstract description of the operation to be performed. Basically it carries information describing the operation to be performed, this information is used by the Android System to decide which Component will handle the Intent. You can even bundle data which will be used by the receiving component to perform the operation along with the Intent.

Public Constructors

  • new Intent()
    Create an empty intent.
  • new Intent(String action)
    Create an intent with a given action.
  • new Intent(String action, Uri uri)
    Create an intent with a given action and for a given data url.
  • new Intent(Context context, Class<?> cls)
    Create an intent for a specific component.
  • new Intent(String action, Context packageContext, Class<?> cls)
    Create an intent for a specific component with a specified action and data.

Action

This is a string which names the action to be performed. You can use this to describe the action to be performed by the Intent. Android has list of predefined actions which can be used to describe many generic operations. Such as if the purpose of the Intent is to do a web search than the Action should be ACTION_WEB_SEARCH. The action largely determines what information is bundled along with the intent object. For example if the the Intent action is ACTION_WEB_SEARCH then you will sending URL of the web page/text to do a web search along with Intent.

Action is set by calling setAction() on the Intent object as shown below

Intent intent = new Intent();
intent.setAction(Intent.ACTION_WEB_SEARCH);
intent.putExtra(SearchManager.QUERY,"text_to_search");
startActivity(intent);

Category

Category is a string describing the kind of components this Intent should be handled by. This is optional information passed with an Intent which helps Android System to resolve which app component it should start. Similar to Action, Android has a predefined list of Categories which can be passed with your Intent to describe the target component. You can consider this scenario for example, if the user is viewing a web page or an e-mail and clicks on a link in the text, the Intent generated to execute that link should be passed with CATEGORY_BROWSABLE , so that only activities supporting this category will be considered as possible actions.

You can add category to your Intent by simply calling addCategory() on the Intent object as shown below

Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse("http://www.google.com"));
browserIntent.addCategory(CATEGORY_BROWSABLE);
startActivity(browserIntent);

Extras

Extras are key-value pairs sent along with the Intent to send additional information to the receiving component. This extra information is in most cases required by the receiving component to perform the requested operation. You can add any value (Boolean, Integer, String, Bundle etc) along with a String key using the putExtra() API to the Intent object. For example, notice how we pass the “search query” along with ACTION_WEB_SEARCH using the putExtra() API.

Intent intent = new Intent();
intent.setAction(Intent.ACTION_WEB_SEARCH);
intent.putExtra(SearchManager.QUERY,"text_to_search");
startActivity(intent);

Flag 

Flags are optional information passed along with an Intent. They instruct the Android System how to launch the component receiving the intent and how to treat it after its launched. Android has a predefined list of Flags any of which can be added to an Intent object by calling addFlag() on the Intent object. For example in the code snippet below we add the flag , this ensures that the new component which receives this intent is started in a new task.

Intent intent = new Intent(Intent.ACTION_WEB_SEARCH);
intent.putExtra(SearchManager.QUERY, stringBuilder.toString());
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent)

Data/ Type

This is to specify the URI of the data to be acted on. For example if the the Intent is for editing an Image then you can pass URI of the image by calling setData() on the Intent object.  This is often used used with setType() which used to specify the type(MIME type) of data bundled with the Intent. Specifying both data and type along with the Intent will help the Android system in selecting the proper app component for it. If you want set both data and type for an Intent use setDataAndType()  instead of setData() and setType() seperately because they cancel each other.

A very simple example for this would be starting an Intent to view a Image file. Here apart from setting the action as ACTION_VIEW we set the Data as the file URI and type as “image/*”. This informs Android System that file URI passed is an image and hence it selects only components which can display an image.

Intent intent = new Intent();
intent.setAction(Intent.ACTION_VIEW);
Uri uri = Uri.fromFile(imageFile);
intent.setDataAndType(uri, "image/*");
startActivity(intent);

Sending an Android Intent

Above we saw different kinds of information which can be bundled along with Android Intent. Based on this information Android decides which app components it should start

Explicit Intent

This is for cases where you know what your target component is. Here you directly specify the target component package/class name using the setComponent() API or use the public constructor. Android just resolves the package/ class name and directly opens the target component(if it is present on the device). This is mostly used for starting components in the same application, because you are sure that the present  on the device.

For example , in the code snippet below we start an activity by just naming the activity class.

Intent intent = new Intent(getApplicationContext(), SecondActivity.class);  
intent.putExtra("Value1", "Android Tutorial");  
intent.putExtra("Value2", "AndroidClarified");  
startActivity(intent);

Implicit Intent

Implicit Intent do not specify the target component but instead describe the operation to be performed. The operation is described with the help of setAction(), setData() and various other APIs mentioned above. Android System which receives the Intent, scans the device for all the components which can handle this Intent. If multiple components are able to handle the intent on a single device then it opens a dialog where user can select the component. Else It directly launches the selected component.

For example your application sends an Intent with ACTION_VIEW and a webpage URL, Android system will select all the browsers on the device and launch a dialog for the user to select any one browser. If only one browser is present on the device then it directly launches it.

Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse("http://www.google.com"));
browserIntent.addCategory(CATEGORY_BROWSABLE);
startActivity(browserIntent);

 

android intent chooser
Intent Chooser

 

Conclusion

This finishes the basics about Android Intent. If you liked this tutorial please share it with your friends and feel free to comment in case of any confusion.

If you want learn more about basics in Android Development read this

Retrofit Android Example : Sending HTTP GET, POST Request

In our last tutorial we discussed about how to send a network request using Volley Library, while Volley is a widely used network library for basic HTTP operations there is one more library which is quite popular among Android developers- Retrofit. In fact many developers prefer Retrofit over Volley due to its ease of use, performance, extensibility etc.

Retrofit is basically an HTTP client for Android and Java developed by the awesome folks at Square. It uses OKHttp by default for network operations. What makes it unique is that with Retrofit you don’t need to worry about parsing the response – meaning de-serialization is handled in the background itself. You just need to configure any convertor library (GSON, Jackson etc) and the job is done.

In this example we will develop an application which will send a network request with Retrofit and display the response. We will be using OpenWeather API to fetch current weather details. Its a free API service which provides a number of APIs to fetch weather details anywhere on the Globe. You just need to register to obtain the API key. Read this for more

API:
https://api.openweathermap.org/data/2.5/weather?q=London,uk

Continue reading

Android Example : HTTP GET, POST Request with Retrofit

In our last tutorial we discussed about how to send a network request using Volley Library, while Volley is a widely used network library for basic HTTP operations there is one more library which is quite popular among Android developers- Retrofit. In fact many developers prefer Retrofit over Volley due to its ease of use, performance, extensibility etc.

Retrofit is basically an HTTP client for Android and Java developed by the awesome folks at Square. What makes it unique is that with Retrofit you don’t need to worry about parsing the response – meaning de-serialization is handled in the background itself, you just need to configure any convertor library (GSON, Jackson etc). Retrofit uses OkHttp by default for HTTP operations.

In this example we will develop an application which will send a network request with Retrofit and display the response. We will be using OpenWeather API to fetch current weather details. Its a free API service which provider number of APIs to fetch weather details anywhere on the Globe, you just need to register to obtain the API key. Read this for more

API:
https://api.openweathermap.org/data/2.5/weather?q=London,uk

Continue reading