Hot questions for Using Butter Knife in 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
- Using Latest version currently i am using 8.8.1
- Using old version i tried with 8.0.1 and 8.6.0
- Clean and Rebuild
- Invalidate Cache
- 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?
Answer:
First, you don't need Unbinder
for Activitybecause Unbinder is only needed for
Fragment`.
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: