Hot questions for Using Butter Knife in android activity

Top 10 Java Open Source / Butter Knife / android activity

Question:

Yesterday I was working on my on going project using butterknife in it.But suddenly its stopped working.The ButterKnife.bind(this) is not able to bind the views so that all the views are throwing NullPointerException.I don't understand what happened that suddenly its stop working.Its a weird situation

Here are few points which i already did but its not working

  1. Using Latest version currently i am using 8.8.1
  2. Using old version i tried with 8.0.1 and 8.6.0
  3. Clean and Rebuild
  4. Invalidate Cache
  5. Removing Gradle and Build files

Following are the version i am using

ext {
    // sdk and tools
    minSdkVersion = 21
    targetSdkVersion = 27
    compileSdkVersion = 27
    buildToolsVersion = '26.0.2'

    // dependencies versions
    supportLibraryVersion = '27.0.0'
    playServicesVersion = '10.2.4'
    butterKnifeVersion = '8.8.1'
    retrofitVersion = '2.3.0'

}

I am banging my head from past 8 Hours on this silly issue.If anyone could help will be appropriated


Answer:

Finally i found the solution.Ii was due to Kotlin Plugin. It was happening since I updated the Kotlin plugin in Android Studio 3.0

If you are using Kotlin then annotationProcessor wont work instead you need to use kapt

So replace this

compile 'com.jakewharton:butterknife:8.8.1'
annotationProcessor 'com.jakewharton:butterknife-compiler:8.8.1'

with this

compile 'com.jakewharton:butterknife:8.8.1'
kapt'com.jakewharton:butterknife-compiler:8.8.1'

It will resolve the issue

Question:

I'm facing issues implementing MaterialDrawer (library MikePenz) using Multiple Activities ( not using fragments) which is implemented with a BaseActivity. Also, using ButterKnife to bind the views.

Found related issues here in SO and tried it out one by one , but in my case it was not working since most of them using standard Navigation Drawer with Fragments or they are not related with ButterKnife.

Code :

MainActivity class

public class MainActivity extends AppCompatActivity {

    @BindView(R.id.toolbar)
    Toolbar toolbar;

    private List<TestModel> destinations;
    private DestinationAdapter mAdapter;
    ProgressDialog progressDialog;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        ButterKnife.bind(this);
        setSupportActionBar(toolbar);
        navManagement();
    }
}

activity_main layout

<android.support.constraint.ConstraintLayout 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:id="@+id/maincontainer"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.tvs.ui.MainActivity">

    <android.support.design.widget.AppBarLayout
        android:id="@+id/appbar"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:theme="@style/AppTheme.AppBarOverlay"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        >

        <android.support.v7.widget.Toolbar
            android:id="@+id/toolbar"
            android:layout_width="match_parent"
            android:layout_height="?attr/actionBarSize"
            android:background="?attr/colorPrimary"
            app:popupTheme="@style/AppTheme.PopupOverlay"
             />

    </android.support.design.widget.AppBarLayout>

</android.support.constraint.ConstraintLayout>

StoreActivity

public class StoresActivity extends MainActivity {

    @BindView(R.id.searchEditText)
    EditText mSearchEditText; // errorRequired view 'searchEditText' with ID 2131558557 for field 'mSearchEditText' was not found
    @BindView(R.id.storesRecyclerView)
    RecyclerView recyclerView; // here too

    private List<TestModel> stores;
    private StoreAdapter mAdapter;

    //endregion
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_stores);
        ButterKnife.bind(this);

        loadRecyclerView();
        testData();

    }
    }

activity_store layout

<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <EditText
        android:id="@+id/searchEditText"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        />

    <android.support.v7.widget.RecyclerView
        android:id="@+id/storesRecyclerView"
        android:layout_width="0dp"
        android:layout_height="0dp"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        android:scrollbars="vertical">

    </android.support.v7.widget.RecyclerView>

</android.support.constraint.ConstraintLayout>

I understand that cause of error is that the ButterKnife.Bind in MainActivity is called when the Layout is inflated but the Views are not inflated in the inherited Activities . The Navigation drawer loads but on clicking item it fails as obvious reason. I cannot use a FrameLayout since I'm using MaterialDrawer library which doesn't ( or I'm not aware) have views to inflate.

I tried several methods extensively searching SO like SO1SO2 Git Git2 Link but was not successful .

Appreciate any help are deeply appreciated . Thanks in advance.


Answer:

Thanks @mikepenz for the response.

Posting it since it might help somebody

The issue was fixed by creating an abstract method in BaseActivity

@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(getLayoutResourceId());

        ButterKnife.bind(this); 
        setSupportActionBar(toolbar);
        navManagement();

    }
    protected abstract int getLayoutResourceId();

Concrete Activity

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    //setContentView(R.layout.activity_stores); not required
    ButterKnife.bind(this); 

    loadRecyclerView();
    testData();

}

@Override
protected int getLayoutResourceId() {
    return R.layout.activity_stores;
}

Please note that I was not using ButterKnife.Bind in the Concrete Activity and used @Nullable fields. But currently Binding in both Base and Implementing Activities.

Question:

This is the code that I try to use with ButterKnife but I got the following error when I run the project.

error: cannot find symbol class Activity error: package Activity does not exist error: package Activity does not exist

BaseActivity

public abstract class BaseActivity extends AppCompatActivity {

    private Unbinder unbinder;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(getLayoutResource());
        ButterKnife.bind(this);

        setupUI();
    }


    protected abstract int getLayoutResource();

    protected abstract void setupUI();
}

MainActivity

public class MainActivity extends BaseActivity {

    @Override
    protected void setupUI() {

    }

    @Override
    protected int getLayoutResource() {
        return R.layout.activity_main;
    }
}

RegisterActivity

public class RegisterActivity extends BaseActivity {

    @BindView(R.id.editText_username)
    EditText et;

    @Override
    protected void setupUI() {


        Toolbar toolbar = findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);

        getSupportActionBar().setDisplayHomeAsUpEnabled(true);


    }

    @Override
    protected int getLayoutResource() {
        return R.layout.activity_register;
    }

    @Override
    public void onBackPressed() {
        this.finish();
    }
}

What's my mistake why I can't bind multiple Activities with the abstract class?

Github Project


Answer:

First, you don't need Unbinder for Activitybecause Unbinder is only needed forFragment`.

Second, you better use another method to be override so that you don't need to set the onCreate. Something like this:

public abstract class BaseActivity extends AppCompatActivity {

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(getLayoutResource());
        ButterKnife.bind(this);

        setupUI();
    }

    protected abstract int getLayoutResource();

    protected abstract void setupUI();
}

which then you can use:

public class MainActivity extends BaseActivity {

    @Override
    protected void setupUI() {
      // setup the UI.
    }

    @Override
    protected int getLayoutResource() {
        return R.layout.activity_main;
    }
}

Here is the working example for using ButterKnife with abstract class:

https://github.com/isnotmenow/ButterKnifeAbstractSample