Most of Android developers nowadays know about OkHttp Interceptors, which help to implement many widespread things related to network operations as logging response body, adding header parameters to all requests, handling errors and etc. Most importantly all these things are done in one place, so that you can track bugs and make changes without additional effort.

OkHttpClient.Builder().apply {
writeTimeout(60, TimeUnit.SECONDS)
readTimeout(60, TimeUnit.SECONDS)
addInterceptor(HeadersInterceptor(get()))
addNetworkInterceptor(HttpLoggingInterceptor().setLevel(HttpLoggingInterceptor.Level.BODY))
addInterceptor(HandleErrorInterceptor(get(), get(), get(), get()))}.build()

As calls to remote server API are the core thing in 90+ percent of modern apps, it is natural that you need the same things when changing technology stack. As Kotlin…


It is a common story for modern mobile apps to have vertical list with items that have horizontal list inside, which can be scrolled simultaneosly. This can be implemented using 2 RecyclerView or combining RecyclerView and ViewPager2. However, there is a bit rare case when nested inner list should be scrolled in the same direction as the main list.

Each item can be scrolled vertically, similarly to its parent

When user touches certain area and performs scroll on it, the inner list would be scrolled, otherwise the main list will scroll. For that to work, the onInterceptTouchEvent of child RecyclerView should be overriden. …


I had to show bottom sheet dialog fragment above my fragment and I was getting java.lang.IllegalArgumentException: No view found for id.

After several minutes of WTF I figured out that I was passing fragment manager from Activity, instead of fragment’s own manager (childFragmentManager).

So, if you’re getting such exception then most probably you’ve written something like this:

val bottomSheet = BottomSheet.newInstance()
bottomSheet.show(requireActivity().supportFragmentManager, BottomSheet::class.java.simpleName)

Just replace requireActivity().supportFragmentManager by childFragmentManager and you’re fine to go!


Android: Disable emoji on keyboard

Sometimes in client-server applications backend can not accept emoji, in this case mobile developers have to restrict user from entering them. While it is impossible to hide them from keyboard, we still can suppress emojis. For this Android’s InputFilter class will be used.

Java:

private void disableEmojiInTitle() {
InputFilter emojiFilter = new InputFilter() {
@Override
public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend) {
for (int index = start; index < end - 1; index++) {
int type = Character.getType(source.charAt(index));

if (type == Character.SURROGATE) …


To stop Android Studio from indexing the project every 2 seconds just close the project and from Studio’s welcome screen import it :)


To create UIView with rounded corners you should create your own class extending UIView. I’ll call mine RoundedView:

import UIKitclass RoundedView: UIView {@IBInspectable var borderColor: UIColor = UIColor.white {didSet {self.layer.borderColor = borderColor.cgColor}}@IBInspectable var borderWidth: CGFloat = 2.0 {didSet {self.layer.borderWidth = borderWidth}}@IBInspectable var cornerRadius: CGFloat = 0.0 {didSet {self.layer.cornerRadius = cornerRadius}}}

Add UIView in your storyboard or xib and set newly created RoundedView as its custom class in Identity Inspector:

Save the changes. Now, in Attributes Inspector you can see a new property called Corner Radius:


If you are writing Android projects on Kotlin, it might happen that Android Studio doesn’t recognize databinding. It means that it is not enabled in your project. To enable it do the following:

  1. Add Kotlin gradle plugin to your build.gradle (Project) dependencies:
ext.kotlin_version = '1.2.41'
ext.android_plugin_version = '3.1.2'
repositories {
google()
jcenter()
}
dependencies {
classpath “com.android.tools.build:gradle:$android_plugin_version”
classpath “org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version”
}

2. At the top of build.gradle (app) add apply plugin: ‘kotlin-kapt’ and dataBinding {enabled = true} in android section:

apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
apply plugin: 'kotlin-kapt'

android {
compileSdkVersion 27
dataBinding {…


Recently I had such problem: RecyclerView in my fragment didn’t show (update) its content after adapter.notifyDataSetChanged() and sometimes after recyclerView.setAdapter(adapter). I’ve googled it and couldn’t find any similar cases until this question on Stackoverflow: https://stackoverflow.com/questions/27955741/support-recyclerview-doesnt-show-anything-until-touched?rq=1

As the author states in edit, the problem occurs due to using RxJava2, which doesn’t handle threading very well in this case, thus you should explicitly (and repetitively) state that Observable should be observed on AndroidSchedulers.mainThread(). Therefore I’ve added this method to my observable, though I already had class where I added compose(ObservableTransformer) to all my Observables.

Anyway, if you have problem similar to this, when content of activity/fragment is not displayed even if your code is correct and is running as it should, there is likely a problem with threading, as all UI-related stuff should be performed on UI-thread, so dig in this direction.


I was getting such error when I was trying to force close the fragment by calling activity.onBackPressed():

Caused by java.lang.IllegalStateException

The specified child already has a parent. You must call removeView() on the child’s parent first.

Finally, after several attempts I’ve found a solution. I had to clear fragment’s parent from views before destroying and I’ve used the next peace of code for this:

override fun onDestroyView() {
super.onDestroyView()
if (view != null) {
val parentViewGroup = view.parent as ViewGroup?
parentViewGroup?.removeAllViews();
}
}

Though, this didn’t work either and then I’ve replaced the code and put it before super.onDestroyView(). Thus, this is the solution:

override fun onDestroyView() {
if (view != null) {
val parentViewGroup = view.parent as ViewGroup?
parentViewGroup?.removeAllViews();
}
super.onDestroyView()
}

Yusuf

23 y.o. android engineer from Uzbekistan

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store