创建在longPress上自动减小值的方法时出错

时间:2016-06-17 00:33:28

标签: java android xml

我正在尝试创建自定义数字选择器,但在尝试自动降低值时,我得到了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);
    }
 }

}

我做错了什么,我该如何解决这个问题。

1 个答案:

答案 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;
            }
        }
    }
}