I have made an app that works fine and uses a default toolbar. However I want to add navigation buttons to this toolbar so I am implementing my own that I can inflate a menu onto it. However when I try to call SetSupportActionBar() the app crashes.
I have tried to set the app to not use the default action bar in both the manifest: <activity android:name=".MainMenu" android:theme="#style/Theme.AppCompat.NoActionBar"/> as well as in the XML file: android:theme="#style/Theme.AppCompat.NoActionBar", as this was the suggested solution for someone else with a similar issue however this has not worked.
The code I am using is as follows;
XML:
<Toolbar
android:id="#+id/my_toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
Java:
public class MainMenu extends AppCompatActivity {
Toolbar mToolbar;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main_menu);
mToolbar = findViewById(R.id.my_toolbar);
setSupportActionBar(mToolbar);
mToolbar.setNavigationIcon(R.drawable.menu_arrow);
mToolbar.setNavigationOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
}
});
}
}
Change the toolbar's xml to:
<android.support.v7.widget.Toolbar
android:id="#+id/my_toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
instead of Toolbar
also look at your imports, if you have this line:
import android.widget.Toolbar;
replace it with:
import android.support.v7.widget.Toolbar;
Related
when I execute the following code in debug (ADB via USB) it works, but when I install a generated release .apk, it crashes. More precisely the following code crashes.
.replace(R.id.settings, new SettingsFragment())
Here is the full version of the code.
public class SettingsActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.settings_activity);
getSupportFragmentManager()
.beginTransaction()
.replace(R.id.settings, new SettingsFragment())
.commit();
ActionBar actionBar = getSupportActionBar();
if (actionBar != null) {
actionBar.setDisplayHomeAsUpEnabled(true);
}
}
static class SettingsFragment extends PreferenceFragmentCompat {
#Override
public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
setPreferencesFromResource(R.xml.root_preferences, rootKey);
}
}
}
I found the error from the Google Play which says it throws an IllegalStateExcetion. I do not know any other way of retrieving error messages since it works perfectly fine in debug mode.
This is the corresponding XML file:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<FrameLayout
android:id="#+id/settings"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
I believe disabling Instant run may resolve this. Take a look at this thread:
Android App Crashes on Real Device If apk is manually installed
Had to make SettingsFragment public, now it looks like it works.
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.
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.
The MaterialDrawer will inflate views to your layout. By default it will add a DrawerLayout into the root of your activity, and add the other content (which is your main layout) as child to it again.
This decision was made to make it super simple to implement a Drawer into your application without needing to alter anything special.
Butterknife will bind the view's at the time you call the bind method.
All views of the MaterialDrawer, are bound at the time of you calling .build(), but as the views of the MaterialDrawer are bound internally you shouldn't have to worry about these.
To complete #user2695433 's answer, you can go a little futher : handle all butterknife init and close in the BaseActivity so you can't forget to release ressources ! Very useful if some new dev come in your team and dont know how butterknife work. Here it is :
--------In BaseActivity-------
protected Unbinder binder;
protected abstract int getLayoutResourceId();
...
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(getLayoutResourceId());
binder = ButterKnife.bind(this);
}
#Override
protected void onDestroy() {
super.onDestroy();
binder.unbind(); //release ressource
}
----- In ConcreteActivity------------
#BindView(R.id.title)
TextView title; // butterknife stuff
#Override
protected int getLayoutResourceId() { //define which Id
return R.layout.activity_main;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
Im new to android development and am really struggling to implement a more custom toolbar (or action bar) when using the navigation drawer created in android studio. When I created the navigation drawer activity from the template, the file that seems to be defining the tool bar is app_bar_main.xml
here is app_bar_main.xml
<android.support.design.widget.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="#style/AppTheme.AppBarOverlay"
>
<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:title="Press"
android:titleTextColor="#FFFFFF"
/>
</android.support.design.widget.AppBarLayout>
<FrameLayout
android:id="#+id/fragment_container"
android:layout_width="match_parent"
android:layout_height="match_parent">
</FrameLayout>
As you can see, I have tried to change the title (to press) and text color of the tool bar, however when running it, nothing changes and it still just says MainActivity which is what my Navigation drawer activity is called. How can I define this toolbar so I can customize it (center the title, make the background transparent, remove settings button, etc. I do need to keep the hamburger icon to open the drawer obviously)
Thanks for the future help everyone! Let me know if I need to provide any other pieces of my code
Setting the values inside of xml for the toolbar has never worked for me either. You should do them pragmatically. If you are generating the code from Android Studio, you will see inside of onCreate that it is setting the toolbar to the ActionBar:
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
One possible option is to remove setSupportActionbar().
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main2);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
// setSupportActionBar(toolbar);
toolbar.setTitle("Testing");
toolbar.setTitleTextColor(ContextCompat.getColor(this, R.color.colorAccent));
toolbar.inflateMenu(R.menu.menu_main);
toolbar.setOnMenuItemClickListener(new Toolbar.OnMenuItemClickListener() {
#Override
public boolean onMenuItemClick(MenuItem item) {
return false;
}
});
}
The other is to call getSupprtActionBar()
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main2);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
toolbar.setTitleTextColor(ContextCompat.getColor(this, R.color.colorAccent));
setSupportActionBar(toolbar);
if (getSupportActionBar() != null) {
getSupportActionBar().setTitle("Testing");
}
}
/**
* Here is where you would handle the actionbar items.
*/
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.main2, menu);
return true;
}
I tried to change the colour of my action bar in Android app using the following line of code:
getSupportActionBar().setBackgroundDrawable(new ColorDrawable(getResources().getColor(R.color.background_actionbar)));
However, this gives a warning that reads:
Method invocation 'getSupportActionBar().setBackgroundDrawable(new ColorDrawable(getResources().getColor(R.color.backgr...' may produce 'java.lang.NullPointerException'
Any ideas how to work around this?
Note: I am changing the colour programmatically because changing it via XML theme/style didn't work.
Using minimum SDK 16.
Testing on Android 4.4.4 device.
Yes, If you are using themes with NoActionBar then you will get the NullPointerException.
Try this:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// The Action Bar is a window feature. The feature must be requested
// before setting a content view. Normally this is set automatically
// by your Activity's theme in your manifest. The provided system
// theme Theme.WithActionBar enables this for you. Use it as you would
// use Theme.NoTitleBar. You can add an Action Bar to your own themes
// by adding the element <item name="android:windowActionBar">true</item>
// to your style definition.
getWindow().requestFeature(Window.FEATURE_ACTION_BAR);
setContentView(R.layout.main);
// experiment with the ActionBar
ActionBar actionBar = getActionBar();
actionBar.setBackgroundDrawable(new ColorDrawable(getResources().getColor(R.color.background_actionbar)));
//actionBar.hide();
}
or
You can use Toolbar
toolbar.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.Toolbar
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="#+id/toolbar"
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:fitsSystemWindows="true"
android:minHeight="?attr/actionBarSize"
android:background="#color/light_blue">
</android.support.v7.widget.Toolbar>
Include it in activity's layout:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:id="#+id/toolbar_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<include layout="#layout/toolbar" />
</LinearLayout>
</RelativeLayout>
Use this code to Activity:
public class YourActivity extends AppCompatActivity {
private Toolbar toolbar;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_layout);
// Set a Toolbar to replace the ActionBar.
toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
//toolbar.setTitle("Setting");
}
public void setSupportActionBar(#Nullable Toolbar toolbar) {
getDelegate().setSupportActionBar(toolbar);
}
}
I have two SearchViews in one xml layout:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<SearchView
android:id="#+id/my_first_custom_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content" >
</SearchView>
<SearchView
android:id="#+id/my_second_custom_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="#id/my_first_custom_view" >
</SearchView>
</RelativeLayout>
And I inflate this layout to my MainActivity by setContentView(). Then I call methods
setQuery() for each other.
Everything is ok until a screen rotation. When I rotate the screen every searchView has text "World" instead "Hello" and "World".
public class MainActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
SearchView firstSearchView = (SearchView) findViewById(R.id.my_first_custom_view);
SearchView secondSearchView = (SearchView) findViewById(R.id.my_second_custom_view);
firstSearchView.setQuery("Hello!", false);
secondSearchView.setQuery("World", false);
}
}
Someone can explain what's going wrong ?
The SearchView uses as its content the view resulted from inflating a layout file. As a result, all the SearchViews used in the layout of an activity(like your case) will have as content, views with the same ids. When Android will try to save the state to handle the configuration change it will see that the EditTexts from the SearchViews have the same id and it will restore the same state for all of them.
The simplest way to handle this issue is to use the Activity's onSaveInstanceState and onRestoreInstanceState like this:
#Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
// state for the first SearchView
outState.putString("sv1", firstSearchView.getQuery().toString());
// state for the second SearchView
outState.putString("sv2", secondSearchView.getQuery().toString());
}
#Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
// properly set the state to balance Android's own restore mechanism
firstSearchView.setQuery(savedInstanceState.getString("sv1"), false);
secondSearchView.setQuery(savedInstanceState.getString("sv2"), false);
}
Also have a look at this related question.
One way to alleviate this problem is to capture the orientation event change with your activity and then set the query again on your two search views.
Add this to manifest in activity in which you are having two SearchView
android:configChanges="keyboardHidden|orientation|screenSize"