Blog


RxJava. How to handle errors from multiple Observables?

Imagine you need to perform several parallel network request and you have Retrofit and Rx as instruments.
You may end up with zip or combineLatest operators:

    val firstObservable = ServerApi().firstRequest( requestParams1 )
    val secondObservable = ServerApi().secondRequest( requestParams2 )
    val thirdObservable = ServerApi().thirdRequest( requestParams3 )

    // combine observables into one
    Observable.combineLatest(
        firstObservable,
        secondObservable,
        thirdObservable,
        Function3<FirstResponse, SecondResponse, ThirdResponse, CombinedResult> { firstResponse, secondResponse, thirdResponse ->
            // combine responses and create result for return function Function3
            CombinedResult( firstResponse, secondResponse, thirdResponse )
        }
    )
    .flatMap { combinedResult ->
        // perform some intermediate logic with combined result if needed
        Observable.just(combinedResult) // return original observable unchanged
    }
    .subscribeOn(Schedulers.io())
    .observeOn(AndroidSchedulers.mainThread())
    .subscribe({ combinedResult ->
        // end of request
        // show result
    }, {
       it.printStackTrace()
    })

There is a problem with this chain. When one of observables throw an exception, for example, HttpException, then the whole chain will be terminated and we would not be able to show combinedResult.
How to avoid this situation? We just need to handle errors correctly for every Observable in the combinable list.
There is a handy operator for this: onErrorReturn() Call it on the combineLatest parameters as follows:

    Observable.combineLatest(
        firstObservable
            .onErrorReturn { responseFromException(it) },
        secondObservable
            .onErrorReturn { responseFromException(it) },
    ....

onErrorReturn

onErrorReturn is a handy operator which emits new created object instead of terminating chain.

Use Faсtory Method pattern or just write a function called responseFromException(throwable: Throwable)) which will create an empty Response object with error for you:

    ...
    // FirstResponse, SecondResponse and ThirdResponse should inherit from BaseResponse
    fun <T : Any> responseFromException(throwable: Throwable): BaseResponse<T> {
        var errorResponse: BaseResponse<T> = BaseResponse()
        if (throwable is HttpException) {
            errorResponse.code = it.code()
            errorResponse.message = it.message()
        }
      return errorResponse
     }

That’s all. The rest code stay the same. With only one line added for each observable we now may expect the initial chain to work as expected: perform all request without terminal state.




Stateful and stateless widgets in Flutter

As Flutter is declarative user interface is being build as some function from state

UI = f(state)

In other words, UI observes State.
As Android Java and Kotlin developer I got used to write everything imperative. For example

textView.setText("Lorem")

or in Kotlin

 textView.text="Lorem"

In Flutter, on other hand, if you want to change UI, you need first to change the State.

A State can be defined as “whatever data you need in order to rebuild your UI at any moment in time”

Stateful and stateless widgets

In short Stateful are like var and stateless are like val variables in Koltin.
You cannot change A stateless widget. Use it when you need to show UI element once and never wont change it state. For example, text labels, icons, images etc.

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
        title: 'Stateless Widget',
        home: Scaffold(
          appBar: AppBar(
            title: Text('Appbar title'),
          ),
        body: Center(
          child: Text('static content'),
        ),
      ),
    );
  }
}

A Stateful widget can be changed in runtime. It may be input TextField, Slider, Checkbox etc.
A widget’s state is stored in a State object. When the widget’s state changes, the state object calls setState(), telling the framework to redraw the widget.

To declare StatefulWidget you need to extend StatefulWidget and create State for it

class MyWidget extends StatefulWidget {
  @override
  _MyWidgetState createState() => _MyWidgetState();
}

class _MyWidgetState extends State<MyWidget> {
  int _count = 42;
  // ···
}

Ephemeral state and App state

First, Application state. It used when you need to share data between screens, widgets or even sessions. In this kind of data you may want to store business logic data, for example, user preferences, downloaded lists, shopping cart etc.

Ephemeral state is a widget state. Examples: current page in PageView, current progress, current selected radioButton in radioGroup




Kodein: Inherit parent dependencies

When you override Kodein instance in activity, fragment or somewhere else, you will lose all dependencies from parent scope.
To prevent this, there is a extend method

Example

In my App I have settings instance I want to use in Activity

 
class App : Application(), KodeinAware {

   override val kodein = Kodein {
     import(androidXContextTranslators)
     bind<ISettings>() with singleton { Settings(this@App) }
   }

Now in activity:

class MainActivity : Activity(), KodeinAware {

    private val appKodein by kodein(App.instance)

    override val kodein = Kodein {
       // or
       // extend(appApplication.appKodein(), allowOverride = true)
       extend(appKodein)
       // now you have all dependecies, you initialized in App
       //...
    }

    private val settings: ISettings by instance() // here we have it. Able to use settings instance



Dependency Injection with Kodein

If you build your Android application with Kotlin and want to implement DI technique then take a look at Kodein framework. Today I will take a quick look at it with you. I will not dive deep into dependency injection itself in this post. If you are not familiar with DI pattern, search articles on Dagger 2 for more info.
I will show Kodein practical usage on a simple example. Let’s say you want to inject singleton retrofit instance somewhere.

First, add Kodein dependency to the gradle file:

 implementation "org.kodein.di:kodein-di-generic-jvm:6.1.0"
 implementation "org.kodein.di:kodein-di-framework-android-core:6.1.0"
 implementation "org.kodein.di:kodein-di-framework-android-x:6.1.0"

Implement KodeinAware interface in your Application class. You will have to override kodein val and implement Retrofit instance there:

class App : Application(), KodeinAware {

    override val kodein = Kodein {
        import(androidXContextTranslators)
        bind<Retrofit>() with singleton {
            Retrofit.Builder()
                .client(OkHttpClient().newBuilder().build())
                .baseUrl("htttp://example.com")
                .addCallAdapterFactory(CoroutineCallAdapterFactory())
                .build()
        }
    }
}

All dependencies always starts with

 bind<TYPE>() with

followed by “singleton”, “provides” or “factory”
singleton” speaks for itself, “provides” generates new instance every time. If you need custom instance, then use “factory“; like”provides” it creates new instance every time but with applied constructor.

After declaring Dependency let’s use it!
You may need to inject Retrofit instance in Activity/Fragment or, if you use MVP pattern, in presenter. Difference is context: when in presenter you do not have context by default, you need to pass it. Let’s start with Activity case first.

Again, you need to imlpement KodeinAware interface and get the instance:

class MainActivity : AppCompatActivity, KodeinAware{

    override val kodein: Kodein by kodein()

    private val retrofit: Retrofit by instance()
    ...
    // use retrofit

Now, if you want to use retrofit in presenter or in some other class that is not aware of Android context,
first pass Context instance to get Kodein instance. I did it with App instance.
Add this into App class:

    ...
    override fun onCreate() {
        super.onCreate()
        instance = this
    }
    
    companion object {
        lateinit var instance: App
            private set
    }
    ...

Now in presenter:

class MyPresenterImpl : IMyPresenter, KodeinAware {

    override val kodein by kodein(App.instance)

    override val kodeinContext = kcontext(App.instance)

    private val retrofit: Retrofit by instance()

    ...
    // use retrofit

For more info check out official documentation




Flowable from Room database

Hi! Today I’ll tell you how to get data from Room database in reactive way.

Before starting make sure you have following in your build.gradel:

// Room components
implementation "android.arch.persistence.room:runtime:$rootProject.roomVersion"
implementation "android.arch.persistence.room:rxjava2:$rootProject.roomVersion"
annotationProcessor "android.arch.persistence.room:compiler:$rootProject.roomVersion"
androidTestImplementation "android.arch.persistence.room:testing:$rootProject.roomVersion"

// Lifecycle components
implementation "android.arch.lifecycle:extensions:$rootProject.archLifecycleVersion"
implementation "android.arch.lifecycle:reactivestreams:$rootProject.archLifecycleVersion"
annotationProcessor "android.arch.lifecycle:compiler:$rootProject.archLifecycleVersion"

// Rx
implementation 'io.reactivex.rxjava2:rxandroid:2.1.0'
implementation 'io.reactivex.rxjava2:rxjava:2.2.1'

First we need to get database from assets and define Dao class for data.

@Database(entities = {Verse.class}, version = 1, exportSchema = false)
public abstract class MyRoomDatabase extends RoomDatabase {
    public abstract MyDataDao myDataDao();

    private static MyRoomDatabase INSTANCE;

    static MyRoomDatabase getDatabase(final Context context) {
        if (INSTANCE == null) {
            synchronized (MyRoomDatabase.class) {
                if (INSTANCE == null) {
                    INSTANCE = Room.databaseBuilder(context.getApplicationContext(),
                            MyRoomDatabase.class, "data.sqlite3") // get db from assets
                            .openHelperFactory(new AssetSQLiteOpenHelperFactory())
                            .build();

                }
            }
        }
        return INSTANCE;
    }

    public void destroyInstance() {
        synchronized (MyRoomDatabase.class) {
            INSTANCE = null;
        }
    }
}

@Dao
public interface MyDataDao {

    @Query("SELECT * from verses ORDER BY RANDOM() LIMIT 1")
    LiveData<Verse> getRandomVerse();

    @Query("SELECT * from verses ORDER BY RANDOM() LIMIT 1")
        // same request
    Flowable<Verse> getRxRandomVerse();
}

Above code represents raw request for random Verse objects from database table verses
What I like about Room is it allows us to get Rx Flowable as well as LiveData objects out of the box!
In our case we will use Flowable.
Next, define a repository class:

class MyRepository(context: Context?) {

    private val mDataDao: MyDataDao
    private val db: MyRoomDatabase? = MyRoomDatabase.getDatabase(context)

    init {
        mDataDao = db!!.myDataDao()
    }

    fun getRxRandomVerse(): Flowable<Verse> {
        return mDataDao.getRxRandomVerse
    }

    fun getDb(context: Context?): MyRoomDatabase? {
        return db ?: MyRoomDatabase.getDatabase(context)
    }

    fun closeDb() {
        db?.close()
    }
}

Finally, let’s extract data onto presentation layer:

class MainActivityPresenter {

    private var mRepository: MyRepository? = null

    fun attach(mainActivityView: MainActivityView, context: Context) {
        this.mainActivityView = mainActivityView
        this.mRepository = MyRepository(context)
    }

    fun getRandomVerse() {
        mainActivityView!!.showProgressBar()
        mRepository.getRxRandomVerse()
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe({ verse ->
                    mainActivityView!!.hideProgressBar()
                    updateUI(verse?.toString())
                }, { error ->
                    mainActivityView!!.hideProgressBar()
                    error.printStackTrace()
                })
    }
}

class MainActivity : MainActivityPresenter.MainActivityView {

    ...

    override fun updateUI(verse: String) {
        textViewVerse.text = verse
    }

    ...
}

That’s all in general. Pretty simple and handy. I’ve successfully implemented this code in a new random quote app

If you have any questions, leave in comments below.




Adapt Android application for Wear OS

In March 2018 Google made Android Wear platform re-branding. New name – Wear OS. According to statistics, currently in the world of smart watches the leader is the Apple’s watchOS, taking 16,2 %, whereas Wear OS has 7%. However, the smart watch market is still new and we definitely can expect the number of users to growth. This means, we may create apps and watchfaces for wearable gadgets.
Let’s create Wear OS module for an existing Android app. I have just the right one – same old Workout Stopwatch.

 

Create module

Create new module in android studio project and choose wearable app

In build.gradle of created module add wearable dependecies:

dependencies {
    implementation 'com.android.support:wear:27.1.1'
    implementation 'com.google.android.support:wearable:2.3.0'
    compileOnly 'com.google.android.wearable:wearable:2.3.0'
}

Wearable app may be in three states:

  • Completely independent of a phone app
  • Semi-independent (a phone app is not required and would provide only optional features)
  • Dependent on a phone app

For the first two, for independent ones, in Android Manifest add following for <application ../> tag:

 <meta-data
 android:name="com.google.android.wearable.standalone"
 android:value="true" />

otherwise, the application will not be available to users with iPhone.
That is, if this flag is false, then the application can be installed only on the device connected to the phone on which the Play Store is installed.

In addition, for the wear-module, you must add In AndroidManifest.xml <uses-feature> with the value:

<manifest>
...
 <uses-feature android:name="android.hardware.type.watch" />
...
</manifest>


Packaging

Previously, apk for Wear 1.0 were embedded phone APKs. Wear OS allows us separate apk compiled for Wear 1.0 and upload it directly into Play Store. This helps to decrease phone apk size and gives flexibility in app versioning and distribution. “When you upload a watch APK via the Play Console, you can update your Wear APK independently from the phone APK, and users receive updates via the watch Play Store”  more…

Our app will be independent apk, but this doesn’t mean that we cannot use existing code again. Just extract common logic into a library module, and import it into app and wear. Thus, in app and wear modules, only the UI part of the application remains basically.

 

UI

To create beautiful responsive applications in wear os there are new UI-elements . For example, BoxInsetLayout – automatically adapting to round and rectangular screens layout.

BoxInsetLayout      BoxInsetLayout

To create lists for wearable devices there is a RecyclerView analog – WearableRecyclerView

WearableRecyclerView

 

 

Summary

We created wearable module in our project and adapted existing application for Wear OS. Remember that because of hardware limitations watches are not designed for complex applications. They are ideal for notifications, quick messages, or simple applications. Keep this in mind, and publish new applications or Wear OS versions of existing apps on Google Play!

That’s all for today!




A/B Testing with Firebase. Simple. Fast.

Sometimes we need to test a new feature in our mobile app. For example, if you want to see how new design will affect retention and DAU, whether users like it or not. AB Testing helps us here.
In a simplified form, it looks like this: on the backend side, administrator exposes which part of the users will see option A (new design), and which part is version B (old design). The client-side requests the server which option, A or B, it should show. And then a regular if- or switch- check starts the necessary code.
Fortunately for many mobile developers, the multifunctional service Firebase provides among other the possibility of AB-tests.
To create an experiment open Firebase console.
Open your project. If you do not have a project yet, create one.
For clarity, I will add an experiment to change the color of the UI element in my stopwatch project.
So, on the left, in the section Grow select A/B Testing and then Create experiment->Remote config. Enter the name of the experiment, description, select our application and enter the percentage of the target audience

Press Next. We may add not only two, but several options. In my case, two is enough. Now add parameter red_circle_enabled. Set values for created varinats:

It remains to choose the goals by which we will monitor the effectiveness of the tests:

Press Review and start experiment.

Now we need to implement A/B logic on client side.

In Codelabs there is a good tutorial how to make it on Android
Everything we need belongs to com.google.firebase.remoteconfig, so make sure you have added next dependency in your build.gradle:

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

Next, initialise Remote Config instance where you will implement A/B test logic (e.g. MainActivity):

FirebaseRemoteConfig mFirebaseRemoteConfig = FirebaseRemoteConfig.getInstance();FirebaseRemoteConfigSettings firebaseRemoteConfigSettings =
 new FirebaseRemoteConfigSettings.Builder()
 .setDeveloperModeEnabled(true)
 .build();
// Initialise default data
Map<String, Object> defaultConfigMap = new HashMap<>();
defaultConfigMap.put("red_circle_enabled", false);
firebaseRemoteConfig.setConfigSettings(firebaseRemoteConfigSettings);
firebaseRemoteConfig.setDefaults(defaultConfigMap);
fetchConfig();

fetchConfig() requests config data from Firebase

public void fetchConfig() {
    long cacheExpiration = 3600;
    if (firebaseRemoteConfig.getInfo().getConfigSettings()
            .isDeveloperModeEnabled()) {
        cacheExpiration = 0;
    }
    firebaseRemoteConfig.fetch(cacheExpiration)
            .addOnSuccessListener(aVoid -> {
                firebaseRemoteConfig.activateFetched();
                applyRedCircleTest();
            })
            .addOnFailureListener(e -> {
                Log.w(TAG, "Error fetching config: " +
                        e.getMessage());
                applyRedCircleTest();
            });
}

applyRedCircleTest() directly implements the logic depending on the received A/B test value

private void applyRedCircleTest() {
    Boolean redCircleEnabled = firebaseRemoteConfig.getBoolean(Constants.AB_TEST_RED_CIRCLE);
    circleStrokeTextView.setRedCircleEnabled(redCircleEnabled.booleanValue());
}

That’s all! We added the A/B test to the application in 15 minutes using Firebase!




RxJava. ConcatMap for dependent Observables

Today I’m gonna tell how concatMap helps to transform an existing sequential dependent synchronous chain of methods into a reactive and multithreaded one.
Suppose we get a boolean value from a presenter, and perform some UI event:

  ...
  boolean state = mPresenter.getBooleanState(context)
  if(state) {
      showViewA();
    } else {
      showViewB();
  }

The class, that provides data, Presenter in our case, has a dependent method structure, the second depends on the result of the first:

public class MyPresenter<MyView> {

  ...

  private int getIntValue(Context context) {
      int retValue = someCalculationMethod(context);
      return retValue;
  }
  public boolean getBooleanState(Context context) {
      int intValue = getIntValue(context);
      return performSomeCalculationWith(intValue);
  }
}

When someCalculationMethod executes immediately, it might be run on the main thread. If it for example, server request, and we may expect some time delay, then it should be executed in a background thread.
With Rx we can easily achieve it, preliminary transformed methods getIntValue and getBooleanState into Observable:

  private Observable<Integer> getIntValue(Context context) {
      return Observable.fromCallable(() -> {
         int retValue = someCalculationMethod(context);
         return retValue;
      });
  }

  private Observable<Boolean> getBooleanState(Context context, Integer intValue) {
     return Observable.fromCallable(() -> {
        boolean retValue = performSomeCalculationWith(intValue);
        return retValue;
     });
  }

So, how do we get Observable from the getBooleanState without having getIntValue performed? All magic on merging these two Observables is made by concatMap operator:

  private Observable<Boolean> rxGetBooleanState(Context context) {
      Observable integerObservable = getIntValue(context)
        .subscribeOn(Schedulers.io())
        .observeOn(AndroidSchedulers.mainThread());

      Observable retObservable = integerObservable
        .concatMap(intValue -> getBooleanState(context, intValue));
      return retObservable;
  }

ConcatMap works similarly to flatMap. Important distinctive feature is it keeps elements order.

Let’s check docs:

Returns a new Observable that emits items resulting from applying a function that you supply to each item emitted by the source Observable, where that function returns an Observable, and then emitting the items that result from concatenating those resulting Observables.

And look at the concatMap operator scheme:

concatMap

concatMap scheme

concatMap applies a function (Observable) that you supply to each item emitted by the original Observable, and then merges the results of that function applied to every item emitted by the original Observable, thus creating a new Observable saving original order from first Observable.

And now we’re only need to call our method from appropriate context:

Disposable disposable = mPresenter.rxGetBooleanState(this)
        .observeOn(AndroidSchedulers.mainThread())
        .subscribe { state ->
            if (required) {
                showViewA();
            } else {
               showViewB();
            }
        }



RxJava. share operator with RxBinding

Today I’ll tell you about a convenient reactive approach to handle EditText input. As an example, we will take a search string in a SearchView.

The task

Search usually takes a while. No matter if we requesting data from the server, or read the local database. User may input letters in the textfield much faster than the requests would work off. Therefore we need to settle some time threshold not making any requests more frequent than necessary. Besides, we may need to update some UI changes in real-time, without those time gaps.

Solution

Without Rx in Android we can use Runnable and Handler, which is not handy. But thanks to the RxBinding we may use the debounce operator and get an elegant solution:

RxSearchView.queryTextChanges(searchView) 
 .debounce(500, TimeUnit.MILLISECONDS) // задержка в 500 мс 
 .observeOn(AndroidSchedulers.mainThread()) 
 .subscribe(query -> mPresenter.searchRequest(query));

Now, regardless of input speed, requests to the server will be performed no more often than twice a second.
But, what should we do, if we need to update UI on every letter input? For example, hint needs to be changed. Using the code above we would have debounced UI updates with 500 ms, what is not quite user-friendly.

Fortunately, in Rx there is the possibility to broadcast to multiple subscribers. In order to use it we need to call .share() on our Observable and voila!

Observable<String> sharedTextChanges = RxSearchView.queryTextChages(searchViw).share()
 
sharedTextChanges 
 .debounce(500, TimeUnit.MILLISECONDS) // use debounce 
 .observeOn(AndroidSchedulers.mainThread()) 
 .subscribe(query -> mPresenter.searchRequest(query)); 
 
sharedTextChanges 
 .observeOn(AndroidSchedulers.mainThread()) 
 .subscribe(query -> mPresenter.updateUI(query));

We subscribed to Observable twice: with and without debounce. Now UI refreshes on every letter input, whereas server request being performed no more frequent than 500 ms.

What’s under the hood?

Operator .share() is an wrapper for .publish().refcount(). They allow to “share” items emitted by a stream. Let’s look deeper.

Operator.publish( ) — transforms Observable into ConnectableObservable.

rxjava publish operator scheme

“ConnectedObservable” is an Observable, which is not emitting data until someone wouldn’t call .connect() operator on it.

Operator .refcount() controls multiple subscribers. According to the docs,

Returns an Observable that stays connected to this ConnectableObservable as long as there is at least one subscription to this ConnectableObservable.

RxJava operator refcount

refcount() operator knows how many subscribers are subscribed to the Observable and doesn’t disconnect from the source ConnectedObservable until all Observables are unsubscribed.

That’s all. Very effective and elegant, as always with Rx. Hope this post was useful for you!




Setup proxy in Android Studio

Recently I was need to setup Android Studio IDE on a windows host with corporate proxy. Topic isn’t new and has been discussed on stackoverflow and in other blogs However, this problem can not be solved immediately – it takes a lot of time and a bit of blood. So I decided to write this post with step-by-step instruction on IDE setup for Android-developer in proxy environment.

We will use windows PC. For linux algorithm would be the same.

After first run Android Studio suggests to configure a proxy:

Click Setup Proxy and enter proxy server address and your credentials:

You can check out your proxy server address with ipconfig (windows)

ipconfig /all | find /i "Dns Suffix"

 

You may check connection on same window. If everything is OK, move next.

After IDE starts next window appears where you should write your proxy settings again for http and https:


Also, you can set configurations via gradle.properties file:

systemProp.http.proxyPassword=<PASSWORD>
systemProp.http.proxyHost=<PROXY_URL>
systemProp.http.proxyUser=<LOGIN>
systemProp.http.proxyPort=<PORT>
systemProp.https.proxyPassword=<PASSWORD>
systemProp.https.proxyHost=<PROXY_URL>
systemProp.https.proxyUser=<LOGIN>
systemProp.https.proxyPort=<PORT>

But keep in mind that IDE’s settings proxy overrides your projects settings.

If you try to compile project now, it will likely fail with error message

SSLHandshakeException: sun.security.validator.ValidatorException: PKIX fix

Gradle tries to get to repositories servers without certificates. We need to add them into cacerts storage.

But before we will add new lines in gradle.properties:

systemProp.javax.net.ssl.trustStore=<ANDROID STUDIO PATH>\\jre\\lib\\security\\cacerts
systemProp.javax.net.ssl.trustStorePassword=changeit

Here we set path to cacerts storeage file. Default password is changeit. If you didn’t changed it, leave it as it is.

So, how do you add certificates to cacerts?

Setting certificates

After first start IDE suggest to accept certificates. You should accept them, but it may not help. We need to import certificates by hands into cacerts storage of IDE and JVM. To do so perform next steps:

  1. Download certificate. You may use web-browser or openssl
  2. Import certificate via keytool

To import downloaded on step 1 certificate on Windows PC  run as administrator cmd and type:

keytool -import -alias <alias> -keystore C:\Progra~1\Android\Android Studio3.0\jre\jre\lib\security\cacerts -file <path_to/certificate_file>

Also, add this certificate into other cacerts storages (JVM и Android Studio):

keytool -import -alias <alias> -keystore <path_to_studio>\.AndroidStudio3.0\system\tasks\cacerts -file <path_to/certificate_file>
 keytool -import -alias <alias> -keystore "C:\Progra~1\Java\jre_V.V.V\lib\security\cacerts" <path_to/certificate_file>

alternatively, instead of adding, we may just copy certificates from one storage to another with next command:

keytool -importkeystore -srckeystore <path_to_studio>\.AndroidStudio3.0\system\tasks\cacerts -destkeystore C:\Progra~1\Java\jre_V.V.V\lib\security\cacerts -v
 password changeit

After importing the certificates, clean the gradle cache in the C:\Users\<User>\.gradle folder and reboot the system.

Also, start Android Studio as administrator if you getting Access denied error when IDE tries to read cacerts file.

Build your project… Build successful!

If certificate import didn’t help, you can try to use regular http instead of https:

jcenter {
 url "http://jcenter.bintray.com/"
 }

Git

Besides gradle, you may face some problems with git also. To avoid 403 error change git global proxy settings. Run command:

 git config --global http.proxy http[s]://userName:password@proxyaddress:port

And if you see next error when trying to pull/push from/into Git server

SSL certificate problem: self signed certificate in certificate chain

then run next command from administrator:

 git config --system http.sslCAPath <path_to_studio>/.AndroidStudio<v.No>/system/tasks/cacerts

To be able to push/pull with Android Studio IDE’s Git also change Settings->Version Control->Git section SSH executable set Native

That’s all, we can work! Hope this article was useful for you. If you liked it, leave your comments below!