I hope this is not a silly question.
Having 3 basic constructors
public MyClass(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
// TODO Auto-generated constructor stub
}
public MyClass(Context context, AttributeSet attrs) {
super(context, attrs);
// TODO Auto-generated constructor stub
}
public MyClass(Context context) {
super(context);
// TODO Auto-generated constructor stub
}
Each calls the super class constructor first. So does it mean all common constructor code I have to put in a private method like this?:
public MyClass(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
common(context);
}
public MyClass(Context context, AttributeSet attrs) {
super(context, attrs);
common(context);
}
public MyClass(Context context) {
super(context);
common(context);
}
private void common(Context context) { ... }
I though that I could chain the constructor for common code, but I get an error saying constructor calls must be the first statement in the code.
public MyClass(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
this(context, attrs);
}
public MyClass(Context context, AttributeSet attrs) {
super(context, attrs);
// Some code
this(context);
}
public MyClass(Context context) {
super(context);
// Some more code
}
And the first statement is either the super constructor call or the class constructor call, cannot be both.
Constructor call must be the first statement in a constructor
The best way is to use this() - You don't need to create a new method, and you respect the DRY principle (Don't Repeat Yourself)
public MyClass(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
// your code here
}
public MyClass(Context context, AttributeSet attrs) {
// Assuming 0 is the default value of defStyle, else pass the default value
this(context, attrs, 0);
}
public MyClass(Context context) {
// Assuming null is the default value for attrs
this(context, null);
}
You don't have to create another method, you respect the DRY principle and it's easy.
public MyClass(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
// your code here
}
public MyClass(Context context, AttributeSet attrs) {
this(context, attrs,null);
}
public MyClass(Context context) {
this(context,null,null);
}
you can use in this way
What I suggest is put the common code in the most parameterizable constructor and call that constructor from every other (less parameterizable) constructor, with some default values of course for the now missing arguments (you can chain same class constructors with a this(...) statement). If the superclass you're extending is properly designed, you should be able to use your most parameterizable constructor to call its most parameterizable constructor by chaining (with a super(...) statement).
If that doesn't work for your case, then a private method is a very fine way to deal with this, there's usually no benefit in trying to work around it further.
Well, put the common code in a constructer and make sure to call it from every other constructer take care with last parameter int defStyle, I am assuming that 0 is default for defStyle.
public MyClass(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
common(context);
}
public MyClass(Context context, AttributeSet attrs) {
this(context, attrs,0);
}
public MyClass(Context context) {
this(context,null,0);
}
private void common(Context context) { ... }
Related
I am trying to take this Time Preference java class and convert it to Kotlin :
public TimePreference(Context context) {
this(context, null);
}
public TimePreference(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public TimePreference(Context context, AttributeSet attrs,
int defStyleAttr) {
this(context, attrs, defStyleAttr, defStyleAttr);
}
public TimePreference(Context context, AttributeSet attrs,
int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
// Do custom stuff here
// ...
// read attributes etc.
}
I am able to get the primary constructor but not the secondary constructors. I am getting a crash due to layout inflation errors when running.
class SpinnerPreference constructor(context: Context, attrs:
AttributeSet, defStyleAttributes: Int, defStyleRes: Int) :
Preference(context, attrs, defStyleAttributes, defStyleRes) {
}
From commonsware's comment checked the docs again a little more carfully this time and this seems to be working :).
class SpinnerPreference : Preference {
constructor(context: Context, attrs: AttributeSet, defStyleAttributes: Int, defStyleRes: Int) : super(context, attrs, defStyleAttributes, defStyleRes)
constructor(context: Context, attrs: AttributeSet, defStyleAttributes: Int) : super(context, attrs, defStyleAttributes)
constructor(context: Context, attrs: AttributeSet) : super(context, attrs)
constructor(context: Context) : super(context)
}
I wanted to draw an image on canvas using bitmapFactory, but it gave me an error.
java.lang.NullPointerException: Attempt to invoke virtual method 'boolean android.graphics.Bitmap.isRecycled()' on a null object reference
at android.graphics.BaseCanvas.throwIfCannotDraw(BaseCanvas.java:54)
at android.view.DisplayListCanvas.throwIfCannotDraw(DisplayListCanvas.java:226)
at android.view.RecordingCanvas.drawBitmap(RecordingCanvas.java:78)
at com.example.canvastest.GameView.onDraw(GameView.java:23)
I tried to change null paint with actual paint object but it was no good.
I also tried using Rect for space but is was also not good.
private Bitmap bmp;
public GameView(Context context) {
super(context);
bmp = BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher);
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawColor(Color.BLUE);
canvas.drawBitmap(bmp, 10, 10, null);
}
Try to create method init(Context context) like this:
public void init(Context context) {
this.context = context;
bmp = BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher);
}
Then:
public GameView(Context context) {
super(context);
init(context);
}
public GameView(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
}
public GameView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context);
}
public GameView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
init(context);
}
I am extending ScrollView and in that i have used non-static block after constructors to initialize some of the variables.
Code
public ScrollViewExtended(Context context) {
super(context);
}
public ScrollViewExtended(Context context, AttributeSet attrs) {
super(context, attrs);
}
public ScrollViewExtended(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
#RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
public ScrollViewExtended(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
}
private void init(Context context) {
activity = (Activity) context;
userActivityLogDao = new UserActivityLogDao();
activity_name = activity.getClass().getSimpleName();
}
{
init(getContext());
}
I don't want to call init(context) method in each constructor. Thats why i have used non-static block. Can you please suggest if this is the correct way of doing it?
*I am able to run this code without any error.
you can't use the static context. If your problem is the fact that you don't want to call init in each constructor just use this instead of super (explicit constructor invocation). Eg
public ScrollViewExtended(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public ScrollViewExtended(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(this);
}
I have extended the Button class and not implemented onClick in extended button. And I am using the extended button every where and setting the onClick listener in each activity.
How can I detect the button is clicked in the Extended class.
public class ButtonExtended extends Button {
public ButtonExtended(Context context) {
super(context);
}
public ButtonExtended(Context context, AttributeSet attrs) {
super(context, attrs);
}
public ButtonExtended(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
#RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
public ButtonExtended(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
}
//onClick(){ here i want to detect the click }
}
In this ButtonExtended class, I want to detect, if the button is clicked just for the logging purpose. How can I achieve this?
You can override performClick() behavior to get the clicked state.
public class ButtonExtended extends AppCompatButton{
public ButtonExtended(Context context) {
super(context);
}
public ButtonExtended(Context context, AttributeSet attrs) {
super(context, attrs);
}
public ButtonExtended(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
#Override
public boolean performClick() {
Log.d("Button","performClick");
return super.performClick();
}
}
performClick() will get called first before the the listener. Do not omit return super.performClick() in method performClick() this consume the event and your listener will not get called.
I need to know when the user scroll up or down. I managed to achieve that but now I am stuck getting the result back to my main class where I need it. Specifically I don't know how to pass the results to an interface I created.
Here is the error I get:
Attempt to invoke interface method 'void
com.app.android.interfaces.ScrollDirection.Down(int)' on a
null object reference
And here is my custom ScrollView:
public class CustomScrollView extends ScrollView {
private ScrollDirection scrolldirection;
public CustomScrollView(Context context) {
super(context);
scrolldirection = (ScrollDirection) context;
}
public CustomScrollView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public CustomScrollView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
#Override
protected void onScrollChanged(int scrollX, int scrollY, int oldScrollX, int oldScrollY) {
super.onScrollChanged(scrollX, scrollY, oldScrollX, oldScrollY);
if(scrollY<oldScrollY){
scrolldirection.Down(1);
}else{
scrolldirection.Down(-1);
}
}
public interface ScrollDirection{
public void Down(int direction);
}
}
you need to add this line scrolldirection = (ScrollDirection) context; inside every constructor
public CustomScrollView(Context context, AttributeSet attrs) {
super(context, attrs);
scrolldirection = (ScrollDirection) context;
}
public CustomScrollView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
scrolldirection = (ScrollDirection) context;
}
To allow Android Studio to interact with your view, at a minimum you must provide a constructor that takes a Context and an AttributeSet object as parameters
Docs link
Update : The recent issue was the implementation of CustomScrollView inside Fragment but Fragment do not have their context. To implement this ,make parent Activity implements the ScrollDirection and make some function in Fragment and call them from Activity's Down function.