App crashes when trying to add a view programmatically
-
14-11-2019 - |
Question
Hey, I didn't like the Android's TimePicker (it's very big) so I created one by myself, but everytime I try to add it, it just crashes my app. I tried to add a TimePicker in the same way and it's working. this is the code, 3 classes, the inside class create the digits scroller, the second class create a time picker with two digits scrollers, one for the hours and one for the minutes. the third class is for the app, and create a set of two time pickers one for the open time, and one for the close time.
public class openCloseTimesPicker extends LinearLayout{ private smallTimePicker openTimePicker; private smallTimePicker closeTimePicker;
public openCloseTimesPicker(Context context) {
super(context);
setOrientation(HORIZONTAL);
setLayoutParams(new LinearLayout.LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT));
TextView from = new TextView(context);
TextView until = new TextView(context);
from.setGravity(Gravity.CENTER_VERTICAL);
from.setLayoutParams(new LinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
from.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 25.0f);
from.setText("מ:");
until.setGravity(Gravity.CENTER_VERTICAL);
until.setLayoutParams(new LinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
until.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 25.0f);
until.setText("עד:");
addView(closeTimePicker);
addView(until);
addView(openTimePicker);
addView(from);
}
public String getOpenHour(){
return openTimePicker.getHour();
}
public String getCloseHour(){
return closeTimePicker.getHour();
}
private class smallTimePicker extends LinearLayout{
private digitsScroller minutes;
private digitsScroller hours;
public smallTimePicker(Context context) {
super(context);
minutes = new digitsScroller(context, 0, 59);
hours = new digitsScroller(context, 0, 23);
setLayoutParams(new LinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
setGravity(Gravity.CENTER_HORIZONTAL);
// Stacks elements vertically
setOrientation(HORIZONTAL);
TextView colon = new TextView(context);
colon.setGravity(Gravity.CENTER_VERTICAL);
colon.setLayoutParams(new LinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
colon.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 25.0f);
colon.setText(':');
addView(hours);
addView(colon);
addView(minutes);
}
public String getHour(){
return hours.getDigits() + ':' + minutes.getDigits();
}
private class digitsScroller extends LinearLayout{
private ImageView increase;
private ImageView decrease;
private TextView digitDisplay;
private int minimum, maximum;
public digitsScroller(Context context, int minimum, int maximum) {
super(context);
this.minimum = minimum;
this.maximum = maximum;
setLayoutParams(new LinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
setGravity(Gravity.CENTER_HORIZONTAL);
// Stacks elements vertically
setOrientation(VERTICAL);
initializeViews(context);
addView(increase);
addView(digitDisplay);
addView(decrease);
}
private void initializeViews(Context context) {
// Layout settings
LayoutParams childParams = new LinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
// Setting the increase button
increase = new ImageView(context);
increase.setLayoutParams(childParams);
increase.setImageResource(R.drawable.add_increase);
increase.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// Evaluate whether the digit display may be increased further
int currentValue = Integer.valueOf(digitDisplay.getText().toString());
currentValue = currentValue < maximum ? currentValue + 1 : minimum;
updateDigitValue(currentValue);
}
});
// Setting the decrease button
decrease = new ImageView(context);
decrease.setLayoutParams(childParams);
decrease.setImageResource(R.drawable.add_decrease);
decrease.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// Evaluate whether the digit display may be increased further
int currentValue = Integer.valueOf(digitDisplay.getText().toString());
currentValue = currentValue > minimum ? currentValue - 1 : maximum;
updateDigitValue(currentValue);
}
});
// Setting the digits display
digitDisplay = new TextView(context);
digitDisplay.setGravity(Gravity.CENTER_HORIZONTAL);
digitDisplay.setLayoutParams(childParams);
digitDisplay.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 25.0f);
digitDisplay.setText('0'+minimum);
}
private void updateDigitValue(int newValue) {
digitDisplay.setText((newValue > 9) ? Integer.toString(newValue) : '0'+ Integer.toString(newValue));
digitDisplay.postInvalidate();
}
public String getDigits(){
String digits = digitDisplay.getText().toString();
return (digits.length()>1) ? digits : '0'+digits;
}
}
}
}
This is the code to add the view to the layout:
else if(v.getId() == R.id.add_open_time){
table.addView(new openCloseTimesPicker(AddShopActivity.this));
}
I'll say it again, when I'm trying somehing like this, it's working:
else if(v.getId() == R.id.add_open_time){
table.addView(new TimePicker(AddShopActivity.this));
}
This is the log using adb logcat:
D/AndroidRuntime( 227): Shutting down VM
W/dalvikvm( 227): threadid=3: thread exiting with uncaught exception (group=0x4
001aa28)
E/AndroidRuntime( 227): Uncaught handler: thread main exiting due to uncaught e
xception
E/AndroidRuntime( 227): java.lang.NullPointerException
E/AndroidRuntime( 227): at android.view.ViewGroup.addView(ViewGroup.java
:1701)
E/AndroidRuntime( 227): at android.view.ViewGroup.addView(ViewGroup.java
:1688)
E/AndroidRuntime( 227): at elad.openapp.AddShopActivity$openCloseTimesPi
cker.<init>(AddShopActivity.java:99)
E/AndroidRuntime( 227): at elad.openapp.AddShopActivity.onClick(AddShopA
ctivity.java:72)
E/AndroidRuntime( 227): at android.view.View.performClick(View.java:2344
)
E/AndroidRuntime( 227): at android.view.View.onTouchEvent(View.java:4133
)
E/AndroidRuntime( 227): at android.widget.TextView.onTouchEvent(TextView
.java:6510)
E/AndroidRuntime( 227): at android.view.View.dispatchTouchEvent(View.jav
a:3672)
E/AndroidRuntime( 227): at android.view.ViewGroup.dispatchTouchEvent(Vie
wGroup.java:882)
E/AndroidRuntime( 227): at android.view.ViewGroup.dispatchTouchEvent(Vie
wGroup.java:882)
E/AndroidRuntime( 227): at android.view.ViewGroup.dispatchTouchEvent(Vie
wGroup.java:882)
E/AndroidRuntime( 227): at android.view.ViewGroup.dispatchTouchEvent(Vie
wGroup.java:882)
E/AndroidRuntime( 227): at com.android.internal.policy.impl.PhoneWindow$
DecorView.superDispatchTouchEvent(PhoneWindow.java:1712)
E/AndroidRuntime( 227): at com.android.internal.policy.impl.PhoneWindow.
superDispatchTouchEvent(PhoneWindow.java:1202)
E/AndroidRuntime( 227): at android.app.Activity.dispatchTouchEvent(Activ
ity.java:1987)
E/AndroidRuntime( 227): at com.android.internal.policy.impl.PhoneWindow$
DecorView.dispatchTouchEvent(PhoneWindow.java:1696)
E/AndroidRuntime( 227): at android.view.ViewRoot.handleMessage(ViewRoot.
java:1658)
E/AndroidRuntime( 227): at android.os.Handler.dispatchMessage(Handler.ja
va:99)
E/AndroidRuntime( 227): at android.os.Looper.loop(Looper.java:123)
E/AndroidRuntime( 227): at android.app.ActivityThread.main(ActivityThrea
d.java:4203)
E/AndroidRuntime( 227): at java.lang.reflect.Method.invokeNative(Native
Method)
E/AndroidRuntime( 227): at java.lang.reflect.Method.invoke(Method.java:5
21)
E/AndroidRuntime( 227): at com.android.internal.os.ZygoteInit$MethodAndA
rgsCaller.run(ZygoteInit.java:791)
E/AndroidRuntime( 227): at com.android.internal.os.ZygoteInit.main(Zygot
eInit.java:549)
E/AndroidRuntime( 227): at dalvik.system.NativeStart.main(Native Method)
I/Process ( 44): Sending signal. PID: 227 SIG: 3
I/dalvikvm( 227): threadid=7: reacting to signal 3
E/dalvikvm( 227): Unable to open stack trace file '/data/anr/traces.txt': Permi
ssion denied
Thanks, Elad!
Solution
In your openCloseTimesPicker
constructor. It seems closeTimePicker
and openTimePicker
are uninitialized.
addView(closeTimePicker);
addView(until);
addView(openTimePicker);
addView(from);
OTHER TIPS
Nowhere in the code you posted do you actually create openTimePicker and closeTimePicker. I see the variable declarations, but no calls to create instances.
Without creating them your call to
addView(closeTimePicker);
is just passing null to addView