我正在尝试创建自定义数字选择器,但在尝试自动降低值时,我得到了android.view.ViewRootImpl $ CalledFromWrongThreadException。
my_number.xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical">
<Button
android:layout_width="@dimen/numberpicker_button_size"
android:layout_height="@dimen/numberpicker_button_size"
android:enabled="true"
android:focusable="true"
android:background="@drawable/number_picker_top_btn"
android:layout_gravity="center_horizontal"
android:textColor="@color/white"
android:id="@+id/top_button" />
<EditText
android:layout_width="@dimen/numberpicker_middle"
android:layout_height="@dimen/numberpicker_middle"
android:inputType="number"
android:textSize="@dimen/text_size_small"
android:clickable="false"
android:textColor="@color/white"
android:background="@drawable/number_picker_middle"
android:gravity="center"
android:layout_marginTop="@dimen/numberpicker_gap"
android:id="@+id/middle_text" />
<Button
android:layout_width="@dimen/numberpicker_button_size"
android:layout_height="@dimen/numberpicker_button_size"
android:enabled="true"
android:focusable="true"
android:background="@drawable/number_picker_bottom_btn"
android:layout_gravity="center_horizontal"
android:layout_marginTop="@dimen/numberpicker_gap"
android:id="@+id/bottom_button" />
</LinearLayout>
我的CustomNumberPicker类:
public class CustomNumberPicker extends LinearLayout {
private Button plus_button, minus_button;
private EditText text;
private float text_size_sp;
private int MIN,MAX, current_value;
private boolean plus_pressed, minus_pressed;
private OnValueChangedListener mChangedListener;
private Timer minusTimer;
View rootView;
public CustomNumberPicker(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
}
private void init(Context context) {
mChangedListener = null;
plus_pressed = false;
minus_pressed = false;
rootView = inflate(context,R.layout.my_numberpicker,this);
//I'm new to this so this may not be best way to do this
text = (EditText) rootView.findViewById(R.id.middle_text);
minus_button = (Button)rootView.findViewById(R.id.top_button);
plus_button = (Button)rootView.findViewById(R.id.bottom_button);
text.setEnabled(false);
minus_button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
decreaseValue();
}
});
minus_button.setOnLongClickListener(new OnLongClickListener() {
@Override
/*The method set's the boolean state as pressed and starts the new thread which auto decrements values */
public boolean onLongClick(View v) {
minus_pressed = true;
Thread minus = new Thread(new autoValueChanger());
minus.start();
return false;
}
});
minus_button.setOnTouchListener(new OnTouchListener() {
@Override
/* the method used to stop decreasing the value */
public boolean onTouch(View v, MotionEvent event) {
if(event.getAction() == MotionEvent.ACTION_UP || event.getAction() == MotionEvent.ACTION_CANCEL){
minus_pressed = false;
}
return false;
}
});
plus_button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
increaseValue();
}
});
/* set the min value for this number picker */
public void setMinValue(final int min){
MIN = min;
if(current_value != MIN){
minus_button.setEnabled(true); //updates state
}
}
public void setMaxValue(final int max){
MAX = max;
if(current_value != MAX){
plus_button.setEnabled(true);
}
}
/* change text size */
public void setTextSize(final int size_sp){
text_size_sp = size_sp;
text.setTextSize(TypedValue.COMPLEX_UNIT_PX,size_sp);
}
/* change text colour */
public void setTexColor(int color){
text.setTextColor(color);
}
/* set a new value */
public void setValue(int value){
if(value == MIN){
current_value = value;
text.setText("" + current_value);
minus_button.setEnabled(false); //to stop user from decreasing futher
plus_button.setEnabled(true);
}else if (value == MAX) {
current_value = value;
text.setText("" + current_value);
plus_button.setEnabled(false);
minus_button.setEnabled(true);
}else if(value > MIN && value < MAX){
plus_button.setEnabled(true);
minus_button.setEnabled(true);
current_value = value;
text.setText("" + current_value);
}
}
increases value and notify the Listener
private void increaseValue() {
if(current_value + 1 <= MAX) {
int oldValue = current_value;
current_value++;
setValue(current_value);
notifyListener(oldValue,current_value);
}
}
private void decreaseValue(){
if(current_value - 1 >= MIN) {
int oldValue = current_value;
current_value--;
setValue(current_value);
notifyListener(oldValue,current_value);
}
}
public int getValue(){
return current_value;
}
public int getMinValue(){
return MIN;
}
public int getMaxValue(){
return MAX;
}
/* fires the call back method is there is a listener object instantiated */
private void notifyListener(int oldValue, int newValue){
if(mChangedListener != null){
mChangedListener.OnValueChanged(this,oldValue,newValue);
}
}
/* allows ability to set a new custom event listener */
public void setOnValueCahangedListener(OnValueChangedListener mChangedListener){
this.mChangedListener = mChangedListener;
}
/* custom event listener */
public interface OnValueChangedListener {
void OnValueChanged(CustomNumberPicker cnp, int oldValue, int newValue);
}
/* the class which allows the value to be decreased automaticaly and causing the error mentioned at the top */
private class autoValueChanger implements Runnable{
/**
* Starts executing the active part of the class' code. This method is
* called when a thread is started that has been created with a class which
* implements {@code Runnable}.
*/
@Override
public void run() {
minusTimer = new Timer();
minusTimer.scheduleAtFixedRate(new TimerTask() {
@Override
public void run() {
if(minus_pressed){
if(current_value > MIN)
decreaseValue();
else{
minusTimer.cancel();
}
}else {
minusTimer.cancel();
}
}
},0,100);
}
}
}
我做错了什么,我该如何解决这个问题。
答案 0 :(得分:0)
我能够通过使用android处理程序对象来解决这个问题:
import android.os.Handler;
public class CustomNumberPicker extends LinierLayout{
private final Handler handler = new Handler
private void init(Context context){
minus_button.setOnLongClickListener(new OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
if (!plus_held) {
minus_held = true;
handler.post(new autoValueChanger());
}
return false;
}
});
minus_button.setOnTouchListener(new OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
if (!plus_held && (event.getAction() == MotionEvent.ACTION_UP || event.getAction() == MotionEvent.ACTION_CANCEL)) {
minus_held = false;
}
return false;
}
});
}
private class autoValueChanger implements Runnable {
/**
* Starts executing the active part of the class' code. This method is
* called when a thread is started that has been created with a class which
* implements {@code Runnable}.
*/
@Override
public void run() {
if (minus_held) {
if (current_value > MIN) {
decreaseValue();
handler.postDelayed(new autoValueChanger(), 100);
}else{
minus_held = false;
}
}else if(plus_held) {
if (current_value < MAX){
increaseValue();
handler.postDelayed(new autoValueChanger(),100);
}else {
plus_held = false;
}
}
}
}