마스터Q&A 안드로이드는 안드로이드 개발자들의 질문과 답변을 위한 지식 커뮤니티 사이트입니다. 안드로이드펍에서 운영하고 있습니다. [사용법, 운영진]

스피너 선택시, 해당 값을 숫자로 적용하는 법 문의 드립니다.

0 추천

안녕하세요, 간단한 설계값 계산기를 제작중에 있습니다.

여러가지 입력값을 EditText로 받아서 이를

a = Double.parseDouble(num1.getText().toString()); 으로 숫자로 전환 후

c=3.1416*a*b/60000; < 이런 방식으로 계산 해서

sum.setText(String.format("%.2f",g)); < 요렇게 출력하는 방식인데요,

 

문제는 입력값들 중에 정형화 된 값들 중 하나를 선정해서 골라야 하는 부분이 있어서,

(이를테면 1.1~1.9 사이에 0.1 단위로만 입력 필요)

이를 Spinner를 이용해 항목을 나열시켜 선택하게 하고 싶었습니다.

 

XML에 구현까지는 다 되었는데, 문제는 해당 선택값을 불러와서 숫자로 적용 후 수식에 넣는 방법을 모르겠습니다.

지식IN이나 구글링을 해도 뭔가 계속 오류가 발생해서 곤란한데,

올려드리는 소스를 보시고 조언좀 부탁드립니다.

 

 

<XML> : Spinner 부분만 발췌

    <Spinner
        android:id="@+id/num6"
        android:layout_width="wrap_content"
        android:layout_height="36dp"
        android:layout_below="@+id/num5"
        android:layout_alignParentEnd="true"
        android:layout_marginStart="20dp"
        android:layout_marginTop="5dp"
        android:layout_marginEnd="17dp"
        android:layout_toEndOf="@+id/textView8"
        android:layout_weight="1"
        android:entries="@array/numb6"
        android:scrollbarStyle="outsideInset" />

   

 

 

<MainActivity>

package com.example.ptbeltdesign;

import androidx.appcompat.app.AppCompatActivity;

import android.graphics.Rect;
import android.os.Bundle;
import android.content.DialogInterface;
import android.os.Bundle;
import android.view.MotionEvent;
import android.view.View;
import android.view.inputmethod.InputMethodManager;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Spinner;
import android.widget.TextView;
import android.widget.Toast;

public class MainActivity extends AppCompatActivity {
    EditText num1, num2, num3, num4, num5, num6, sum, sum1, sum2;
    Button pls, mia, gop, nau;
    double a, b, a1, b1, a2, a3, c = 0, d = 0, e = 0, f = 0, f1 = 0, g = 0, h = 0, i = 0; // C=속도 d=유효장력 e=긴장측장력 f=지수 g=초장력
    // h=접촉각
    View.OnClickListener cl;
         
    @Override
    protected void onCreate( Bundle savedInstanceState ) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        num1 = (EditText) findViewById(R.id.num1); // RPM
        num2 = (EditText) findViewById(R.id.num2); // 풀리경
        num3 = (EditText) findViewById(R.id.num3); // 축간거리
        num4 = (EditText) findViewById(R.id.num4); // 모터마력
        num5 = (EditText) findViewById(R.id.num5); // 큰풀리경
        Spinner num6=(Spinner) findViewById(R.id.num6); // 보정계수

        sum = (EditText) findViewById(R.id.sum); // 첫째칸 출력물
        sum1 = (EditText) findViewById(R.id.sum1); // 둘째칸 출력물
        sum2 = (EditText) findViewById(R.id.sum2); // 둘째칸 출력물
        pls = (Button) findViewById(R.id.pls);

        cl = new View.OnClickListener() {

            public void onClick(View v) {
                a = Double.parseDouble(num1.getText().toString()); // 작은풀리 RPM
                b = Double.parseDouble(num2.getText().toString()); // 작은풀리경
                a1 = Double.parseDouble(num3.getText().toString()); // 축간 거리
                b1 = Double.parseDouble(num4.getText().toString()); // 모터 마력
                a2 = Double.parseDouble(num5.getText().toString()); // 큰 풀리경

                c=3.1416*a*b/60000;
                d=(1000*b1*1.4)/c; // 원래는 좌측 1.4 항목이 Spinner 선택값으로 치환되어야 함.
                h=(180-(60*(a2-b)/a1))*3.1416/180; // 접촉각 계산
                f1=0.512*h;
                f= Math.pow(2.7183, f1);
                e=d*(f/(f-1));
                g=(d/2)*((f+1)/(f-1))*1.5;
                i=2*a1+1.57*(b+a2)+Math.pow(a2-b,2)/(4*a1);

                sum1.setText(String.format("%.2f",d));
                sum.setText(String.format("%.2f",g));
                sum2.setText(String.format("%.2f",i));
            }
        };
        pls.setOnClickListener(cl);
    }
}

 

혹시 더 필요한 내용이 있으시면 언제든 추가 하겠습니다.

감사합니다.

우라에누스 (290 포인트) 님이 2022년 3월 23일 질문

2개의 답변

+1 추천
 
채택된 답변
public class MainActivity extends AppCompatActivity {
    // 해당 클래스에만 사용하는 변수들이므로 private을 사용.
    // 변수의 이름들을 뭘하는지 알기쉬운 이름들로 바꾸세요. 이렇게 애매모호한 이름을 사용하면,
    // 한참 지나서 님이 짠 소스를 봐도 이해가 바로 가지 않아요. 몇개만 변경해서 사용합니다.
    private EditText rpmEdit, num2, num3, horsePowerEdit, num5, num6, sum, sum1, sum2;
    private Button pls, mia, gop, nau;
    private Spinner correctionFactorSpinner;
    private double a, b, a1, b1, a2, a3, velocity = 0, d = 0, e = 0, f = 0, f1 = 0, g = 0, h = 0, i = 0; // d=유효장력 e=긴장측장력 f=지수 g=초장력
    // h=접촉각 => h대신에 접촉각을 의미하는 변수명을 사용하세요.

    private String[] correctionFactors;
         
    @Override
    protected void onCreate( Bundle savedInstanceState ) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        correctionFactors = getResources().getStringArray(R.array.correction_factors);

        rpmEdit = (EditText) findViewById(R.id.rpmEdit);
        num2 = (EditText) findViewById(R.id.num2); // 풀리경
        num3 = (EditText) findViewById(R.id.num3); // 축간거리
        horsePowerEdit = (EditText) findViewById(R.id.horsePowerEdit); 
        num5 = (EditText) findViewById(R.id.num5); // 큰풀리경
        correctionFactorSpinner = (Spinner) findViewById(R.id.correctionFactorSpinner); // 보정계수

        sum = (EditText) findViewById(R.id.sum); // 첫째칸 출력물
        sum1 = (EditText) findViewById(R.id.sum1); // 둘째칸 출력물
        sum2 = (EditText) findViewById(R.id.sum2); // 둘째칸 출력물
        pls = (Button) findViewById(R.id.pls);

        pls.setOnClickListener(view -> 
               calculateClicked()
        );
    }

    private void calculateClicked() {
        Float cf = getCorrectionFactor();
        if (cf == null) {
           // TODO : 에러메세지를 보여주는 등의 적절한 에러처리를 할 것
           return;
        }

        CalcuationResult result = calculate(cf);
        bindCalcuationResult(result);
    }
    
    @Nullable
    private Float getCorrectionFactor() {
         int position = correctionFactorSpinner.getSelectedItemPosition();
         return strToFloatOrNull(correctionFactors[position]);
    }

    private CalcuationResult calulate(float correctionFactor) {
        ...
        // 입력값들을 파라미터로 받을 수 있다면, 이 로직을 별도의 클래스로 분리하기가 쉬워질 겁니다.

        // 고정된 숫자들은 상수를 사용하세요. 코드를 읽기가 훨씬 수월해 집니다. eg. private static final String PI = 3.1416

        d = (1000 * b1 * correctionFactor) / c; // 원래는 좌측 1.4 항목이 Spinner 선택값으로 치환되어야 함.
        h = (180 - (60 * (a2 - b) / a1)) * 3.1416 / 180; // 접촉각 계산
        f1 = 0.512 * h;
        f = Math.pow(2.7183, f1);
        e = d * (f / (f - 1));
        g = (d / 2) * ((f + 1) / (f - 1)) * 1.5;
        i = 2 * a1 + 1.57 * (b + a2) + Math.pow(a2 - b, 2) / (4 * a1);

        return CalcuationResult(d, g, i);
    }

    private void bindCalcuationResult(CalculationResult result) {
        sum1.setText(String.format("%.2f", result.getD()));
        sum.setText(String.format("%.2f", result.getG()));
        sum2.setText(String.format("%.2f", result.getI()));
    }

    @Nullable
    private Float strToFloatOrNull(String s) {
       try {
            return Float.valueOf(s);
        } catch (NumberFormatException e) {
            return null;
        }
    }
}

public class CalcuationResult {
    private final float d;
    private final float g;
    private final float i;
   
    public CalcuationResult(float d, float g, float i) {
       this.d = d;
       this.g = g;
       this.i = i;
    }
   
    public float getD() {
       return d;
    }

    public float getG() {
       return g;
    }

    public float getI() {
       return i;
    }
}

    

위처럼 하면 될 것 같은데, 제가 님이 작업하시는 분야의 용어는 잘 몰라서 클래스명, 메소드명, 변수명을 제맘대로 적절하지 않은 이름을 사용했기 때문에, 읽기쉬운 명확한 이름들로 변경하시기 바랍니다. 제가 일부 변경한 변수명 중 바뀌지 않은 부분이 있는데, 그 부분을 금방 아실 수 있으니, 고치시기 바랍니다.

그리고 계산 로직은 가능하면 별도로 클래스로 분리하시면 좋을 듯 합니다. 뷰와는 전혀 상관이 없는 코드이므로 계산로직이 변경되거나 하면 뷰를 건드릴 필요가 없습니다. 계산로직을 백그라운드 쓰레드에서 처리하는 것이 정석이지만, 위의 계산로직은 무겁지 않아 보이므로 우선은 메인쓰레드에서 처리하셔도 될 것같아 보입니다. 나중에 필요가 생기면 그 때 처리하시면 되겠네요.

계산로직 검증을 위해서 유닛테스트를 만드는 법을 공부하셔서 테스트를 짜시기를 강력하게 권장합니다. 이것만으로도 많은 버그를 방지하실 수 있어요.

spark (227,870 포인트) 님이 2022년 3월 24일 답변
우라에누스님이 2022년 3월 24일 채택됨
상세한 답변 너무 감사드립니다! 복받으세요
혹 Float타입이 적절하지 않다면 Double을 사용하시면 될 겁니다.
+1 추천

먼저 Spinner 문서를 참조하시길 바랍니다.

https://developer.android.com/guide/topics/ui/controls/spinner

문서를 잘 보시면 선택값의 변경을 감지하기 위해 Spinner에 listener를 연결하라고 나옵니다.

https://developer.android.com/reference/android/widget/AdapterView#setOnItemSelectedListener(android.widget.AdapterView.OnItemSelectedListener)

public class SpinnerActivity extends Activity implements OnItemSelectedListener {
  
    @Override
    protected void onCreate(....) {
        super.onCreate(...);
        setContentView(...);

        Spinner spinner = (Spinner) findViewById(R.id.spinner);
        // adapter가 꼭 필요한지는 테스트를 해보세요.
        ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(this,
        R.array.planets_array, android.R.layout.simple_spinner_item); 
        adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); r
        spinner.setAdapter(adapter);
        spinner.setOnItemSelectedListener(this);
    }

    public void onItemSelected(AdapterView<?> parent, View view,
            int pos, long id) {
        String selectecText = parent.getItemAtPosition(pos);
        calculate();
    }

    public void onNothingSelected(AdapterView<?> parent) {
       // 무시
    }

     // goodVariableName은 1.4에 해당하는 값이고 변수명을 적절하게 바꾸세요.
     private void calculate(String goodVariableName) {
         //기존 계산 로직을 여기에 두세요.
         // 그리고 이런 계산 로직은 UI를 블록시키지 않기위해 백그라운드 쓰레드에서 처리하고 결과를 메인쓰레드에서 화면 보여주는 게 좋지만,
         // 가벼운 연산이라면 그냥 메인쓰레드에서 하도록 일단 두시고, 나중에 쓰레드를 처리하실 수 있을 때, 변경하세요.
     }
}

 

spark (227,870 포인트) 님이 2022년 3월 23일 답변
답변 감사드립니다. 추가로 여쭤볼게 있어요..
...