javaandroidlambdajava-8retrolambda

How to use Android’s DrawerLayout.DrawerListener in a lambda expression?


I've been exploring the concept of lambdas and how they provide a simpler syntax while implementing functional interfaces.

As per this article, if there is one method it's quite easy to implement the lambda. So,

interface OnClickListener {
    public void onClick(View v);
}

Can be used like:

etDate.setOnClickListener(view -> Timber.i("the date is xyz"));

I've seen this work for interfaces with methods having different types of arguments as well, for example:

public interface Observer<T> {
    void onSubscribe(Disposable d);
    void onNext(T t);
    void onError(Throwable e);
    void onComplete();
}

Can be used as

api.getData()
    .subscribeOn(Schedulers.io())
    .observeOn(AndroidSchedulers.mainThread())
    .subscribe(response -> {
               Toast.makeText(this, "Result: " + response.toString(), Toast.LENGTH_LONG).show();
            }, error -> {
                Toast.makeText(this, "API returned an error: " + error.getLocalizedMessage(), Toast.LENGTH_LONG).show();
            });

So I was able to use onNext followed by onError this way.

But take a look at the DrawerListener interface:

I'm not able to use this using RetroLambda. The IDE doesn't suggest me to change the code to lambda and neither am I able to use it as such. I have to write it like this...

drawer.addDrawerListener(new DrawerLayout.DrawerListener() {
    @Override
    public void onDrawerSlide(View drawerView, float slideOffset) {
        // My action goes here
    }

    @Override
    public void onDrawerOpened(View drawerView) {
    }

    @Override
    public void onDrawerClosed(View drawerView) {

    }

    @Override
    public void onDrawerStateChanged(int newState) {

    }
});

...which isn't neat. I am hoping for a solution to write it like:

drawer.addDrawerListener(view, offset -> {
        // My action goes here
    });

Solution

  • Lambdas are suitable only when there is only 1 abstract method to implement. In case of DrawerListener, there are 4 methods which need to be implemented. That is the reason you cannot code it the way you wanted. If you are adamant on using lambdas , you can create an interface that extends DrawerListener and provide default implementations for the methods in that. For this minSDK version should be 24 and jack should be enabled.

    interface CustomDrawerListener extends DrawerLayout.DrawerListener{
        @Override
        void onDrawerSlide(View drawerView, float slideOffset);
    
        @Override
        default public void onDrawerOpened(View drawerView) {
        }
    
        @Override
        default public void onDrawerClosed(View drawerView) {
    
        }
    
        @Override
        default public void onDrawerStateChanged(int newState) {
    
        }
    }
    

    Then you can write add drawer listener as follows:

    d1.addDrawerListener((CustomDrawerListener)(view,offset)->{
            // My action goes here
        });
    

    build.gradle changes:

    android {
        defaultConfig {
            minSdkVersion 24
            //others
            jackOptions {
                enabled true
            }
        }
    
        //other stuff
        compileOptions {
            sourceCompatibility JavaVersion.VERSION_1_8
            targetCompatibility JavaVersion.VERSION_1_8
        }
    }