ButterKnife in multiple activity - java

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

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

Related

Views of Fragment Layout causing NullPointerException

I'm trying to use View Pager with Fragment State Adapter. But getting a NullPointerException when trying to invoke a Fragment method after creating its instance.
Here is the activity class and Adapter class:
public class AddScheduleActivity extends AppCompatActivity {
private FragmentOverview fragmentOverview;
private FragmentTodo fragmentTodo;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_add_schedule);
ViewPager2 viewPager = findViewById(R.id.viewPager_AddScheduleActivity);
viewPager.setAdapter(new ViewPagerAdapter(getSupportFragmentManager(), getLifecycle()));
fragmentOverview = new FragmentOverview();
fragmentOverview.setTargetView(); //ERROR IS HERE
My view pager adapter is:
private class ViewPagerAdapter extends FragmentStateAdapter {
public ViewPagerAdapter(#NonNull FragmentManager fragmentManager, #NonNull Lifecycle lifecycle) {
super(fragmentManager, lifecycle);
}
#NonNull
#Override
public Fragment createFragment(int position) {
switch (position) {
case 0:
return fragmentOverview;
case 1:
return fragmentTodo;
default:
return null;
}
}
#Override
public int getItemCount() {
return 2;
}
}
My FragmentOverView class is:
public class FragmentOverview extends Fragment{
private FrameLayout mTargetFrameLayout;
private FrameLayout mDescriptionFrameLayout;
public FragmentOverview() {
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_overview, container, false);
mDescriptionFrameLayout = rootView.findViewById(R.id.descriptionView_frameLayout_OverviewFragment);
mTargetFrameLayout = rootView.findViewById(R.id.targetView_frameLayout_OverviewFragment);
return rootView;
}
public void setTargetView() {
mTargetFrameLayout.removeAllViews();
if (progress.maxProgress != null) {
//ADD A CHILD VIEW
mTargetFrameLayout.setVisibility(View.VISIBLE);
} else mTargetFrameLayout.setVisibility(View.GONE);
}
}
But when I call the setTargetView() method after creating instance of FragmentOverview, I'm getting a NullPointerException. From log I noticed that the mTargetFrameLayout is null.
Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'void android.widget.FrameLayout.removeAllViews()' on a null object reference
I think this is because the activity lifecycle methods onCreate(), onStart(), onResume() are called before the fragment lifecycle methods onCreate() & onCreateView(). But how to overcome this problem? Or am I trying to do in a wrong way?
I think your assumption is right. The fragment layout is generated in onViewCreated() of FragmentOverview class. But this method start executing after the Activity lifecycle methods onCreate(), onStart() and onResume() are executed. You can checkout the lifecycle relation of Activity and Fragment by overwriting lifecycle methods and adding logs as mentioned by #Max_Hockeborn.
So you will always get the views i.e mTargetFrameLayout null if you call setTargetView() before executing onCreateView() in FragmentOverview.
To solve this, you can add a callback method that will be executed in parent class after executing the onCreateView() of FragmentOverveiw. And in that callback you can invoke setTargetView().
Here I'm providing a possible solution for your case:
In FragmentOverview add this lines:
public class FragmentOverview extends Fragment{
//all your fields;
private OverviewCallbacks callbacks;
public FragmentOverview(OverviewCallbacks callbacks) {
this.callbacks = callbacks;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
//inflate the rootView and find all the childViews;
//I think your codes are okey;
}
//Overwrite this method;
//You can also overwrite onViewCreated() lifecycle method;
//And add call this callback method from here;
#Override
public void onResume() {
super.onResume();
callbacks.onReach();
}
public void setTargetView() {
//Do what you want to do;
}
public interface OverviewCallbacks {
void onReach();
}
}
Thats all for FragmentOverView class.
Now modify your Activity class as follows:
public class AddScheduleActivity extends AppCompatActivity {
private FragmentOverview fragmentOverview;
private FragmentTodo fragmentTodo;
#Override
protected void onCreate(Bundle savedInstanceState) {
//Your codes
fragmentOverview = new FragmentOverview(new FragmentOverview.OverviewCallbacks() {
#Override
public void onReach() {
setTargetView();
}
});
}
}
Hope this will work. Comment if anything gone wrong.
This is just a fast idea that I couldn't test yet.
You could try to change this:
public class AddScheduleActivity extends AppCompatActivity {
private FragmentOverview fragmentOverview;
private FragmentTodo fragmentTodo;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_add_schedule);
ViewPager2 viewPager = findViewById(R.id.viewPager_AddScheduleActivity);
viewPager.setAdapter(new ViewPagerAdapter(getSupportFragmentManager(), getLifecycle()));
fragmentOverview = new FragmentOverview();
fragmentOverview.setTargetView(); //ERROR IS HERE
to this:
public class AddScheduleActivity extends AppCompatActivity {
private FragmentOverview fragmentOverview = new FragmentOverview();
private FragmentTodo fragmentTodo;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_add_schedule);
ViewPager2 viewPager = findViewById(R.id.viewPager_AddScheduleActivity);
viewPager.setAdapter(new ViewPagerAdapter(getSupportFragmentManager(), getLifecycle()));
fragmentOverview.setTargetView(); //ERROR IS HERE
To check your assumption that your problem is based on the call order you can add some logs and check the order they are called in with Logcat (given you use android studio)
Something like this:
public class AddScheduleActivity extends AppCompatActivity {
private FragmentOverview fragmentOverview;
private FragmentTodo fragmentTodo;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_add_schedule);
ViewPager2 viewPager = findViewById(R.id.viewPager_AddScheduleActivity);
viewPager.setAdapter(new ViewPagerAdapter(getSupportFragmentManager(), getLifecycle()));
Log.d("YOUR_TAG","Activity onCreate 1");
fragmentOverview = new FragmentOverview();
fragmentOverview.setTargetView(); //ERROR IS HERE
and
public class FragmentOverview extends Fragment{
private FrameLayout mTargetFrameLayout;
private FrameLayout mDescriptionFrameLayout;
public FragmentOverview() {
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_overview, container, false);
mDescriptionFrameLayout = rootView.findViewById(R.id.descriptionView_frameLayout_OverviewFragment);
mTargetFrameLayout = rootView.findViewById(R.id.targetView_frameLayout_OverviewFragment);
Log.d("YOUR_TAG","FragmentOverview onCreateView 1");
return rootView;
}
public void setTargetView() {
Log.d("YOUR_TAG","FragmentOverview setTargetView 1");
mTargetFrameLayout.removeAllViews();
if (progress.maxProgress != null) {
//ADD A CHILD VIEW
mTargetFrameLayout.setVisibility(View.VISIBLE);
} else mTargetFrameLayout.setVisibility(View.GONE);
}
}
The last one could be interesting for you to see if onCreateView (and the initiation of the variables that cause your problems) is finished before the setTargetView() function is called.

Call a method from MainActivity class from a non-activity class

I have troubles on calling the method update from MainActivity class in a the MSG0100 non-activity class
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
public void update(boolean msg100Preselection){
if(msg100Preselection){
mExpandableListViewAdapter.setSelectedChild(-1);
mExpandableListViewAdapter.notifyDataSetChanged();
}
}
}
And this is my class where i want to call the update method of Mainactivity.
public class MSG0100{
boolean msg100Preselection=false;
pulic void onUpdate(){
msg100Preselection=true;
// Want to call my update method here
MainActivity activity= new MainActivity();
activity.update(msg100Preselection); //<-------- Using mainactiviy object crashes my app.
}
}
What you want is impossible as you dont have a pointer to your main activity.
The following statement is invalid.
MainActivity activity= new MainActivity();
You are not allowed to use the new operator to create an activity. That should be done using an intent.
There are several things you could do:
Move your update method in another class
OR
declare your update method as static and use it like this:
MainActivity.update(msg100Preselection);
Try using a callbackListener :-
In your MSG0100 class
public class MSG0100 {
boolean msg100Preselection = false;
private static OnUpdateListener mListener;
public static setListener(OnUpdateListener mListener) {
this.mListener = mListener;
}
public void onUpdate() {
msg100Preselection = true;
if (mListener != null)
mListener.onUpdate(msg100Preselection);
}
public interface OnUpdateListener()
{
void onUpdate ( boolean msg100Preselection);
}
}
In your MainActivity-
public class MainActivity extends AppCompatActivity, OnUpdateListener {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
MSG0100.setListener(this)
}
#Override
public void onUpdate(boolean msg100Preselection) {
if (msg100Preselection) {
mExpandableListViewAdapter.setSelectedChild(-1);
mExpandableListViewAdapter.notifyDataSetChanged();
}
}
#Override
protected void onDestroy() {
super.onDestroy();
MSG0100.setListener(null)
}
}
This way you won't have any memory leaks or crashes due to Activity being killed.

Optimize night mode system

I created a day/night mode switch system in my app. Currently, I use a PreferenceFragmentCompat + SharedPreference to display and save the switch selection.
This is my code:
public class PreferencesActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_preferences);
PreferencesFragment preferencesFragment = new PreferencesFragment();
getSupportFragmentManager().beginTransaction().replace(R.id.preferences_container, preferencesFragment).commit();
}
public static class PreferencesFragment extends PreferenceFragmentCompat implements SharedPreferences.OnSharedPreferenceChangeListener {
#Override
public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
setPreferencesFromResource(R.xml.preferences, rootKey);
}
#Override
public void onResume() {
super.onResume();
getPreferenceManager().getSharedPreferences().registerOnSharedPreferenceChangeListener(this);
}
#Override
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
if (isAdded()) {
if (sharedPreferences.getBoolean(getString(R.string.KEY_PREF_NIGHT_MODE), false)) {
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES);
} else {
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO);
}
}
}
}
}
On top of that, I use the following code in the OnCreate method of my main Activity:
PreferenceManager.setDefaultValues(this, R.xml.preferences, false);
sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this);
int mode = sharedPreferences.getBoolean(getString(R.string.KEY_PREF_NIGHT_MODE), false) ? AppCompatDelegate.MODE_NIGHT_YES : AppCompatDelegate.MODE_NIGHT_NO;
if (AppCompatDelegate.getDefaultNightMode() != mode)
AppCompatDelegate.setDefaultNightMode(mode);
The problem is that when I activate the dark mode and I restart the application, it will launch then restart in the onCreate. Isn't there a more optimal way to implement this system?
you could create BaseActivity where you set the night mode
abstract class BaseActivity extends AppCompatActivity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_AUTO_BATTERY);
}
}
and then extend all your Activites from BaseActivity
public class PreferencesActivity extends BaseActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
...
}
}
then your night mode would be set in every activity before setContentView and no relaunch would be occured
UPDATE
change
#Override
public void onResume() {
super.onResume();
getPreferenceManager().getSharedPreferences().registerOnSharedPreferenceChangeListener(this);
}
to
#Override
public void onStart() {
super.onStart();
getPreferenceManager().getSharedPreferences().registerOnSharedPreferenceChangeListener(this);
}
onStart is called before view is visible
UPDATE 2
here is the singleton to access SharedPreferences
public class SharedManager {
private static SharedManager instance;
private final SharedPreferences preferences;
private SharedManager() {
preferences = MyApplication.getAppContext().getSharedPreferences(Constants.PREF_NAME, Context.MODE_PRIVATE);
}
public static SharedManager getInstance() {
if (instance == null) {
synchronized (SharedManager.class) {
if (instance == null) {
instance = new SharedManager();
}
}
}
return instance;
}
public SharedPreferences getPreferences() {
return preferences;
}
}
with call SharedManager.getInstance().getPreferences() you can get access to Preferences

Android App button press not functioning correctly

Being brand new to Java I'm not sure why this when called with android:onClick="changeInfo" isn't changing the text view back to the original value.
public class JavaTest extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_java_test);
}
public void changeInfo(View view){
setContentView(R.layout.activity_java_test);
TextView t = (TextView)findViewById(R.id.textSpace1);
if (t.getText()==getResources().getString(R.string.lorem_ipsum)){
t.setText("[Email Here]");
}
else{
t.setText(getResources().getString(R.string.lorem_ipsum));
}
}
Could anyone help, thank you.
Try removing setContentView(R.layout.activity_java_test); from the changeInfo(View view) method.
setContentView(R.layout.activity_java_test);
You don't have to call setContentView inside changeInfo method
t.getText()==getResources().getString(R.string.lorem_ipsum)
it should be t.getText().toString().equeals(getResources().getString(R.string.lorem_ipsum))
Try this
public class JavaTest extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_java_test);
}
public void changeInfo(View view){
TextView t = (TextView)findViewById(R.id.textSpace1);
if (t.getText().toString().equeals(getResources().getString(R.string.lorem_ipsum))){
t.setText("[Email Here]");
}
else{
t.setText(getResources().getString(R.string.lorem_ipsum));
}
}

How to check wether or not a method is called by a child?

The child Class extends a parent Class.
The parent Class has some code I don't want to execute in onCreate().
How can I do this?
Parent:
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if (!child)
{
... more code ...
}
}
}
Child:
public class SingleArticulo extends MainActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_single_articulo);
... other code ...
}
}
Use the Template Method pattern.
Base class:
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
this.doMoreOnCreate()
}
protected void doMoreOnCreate() {
... more code ...
}
}
Child:
public class SingleArticulo extends MainActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_single_articulo);
... other code ...
}
#Override
protected void doMoreOnCreate() {
}
}

Categories

Resources