위험 권한 처리 시 발생하는 예외 상황
안드로이드 6.0 마시멜로우부터는 위험 권한(Dangerous Permissions)을 런타임에 동적으로 요청해야 합니다. 위치 정보 관련 권한도 이에 해당하며, 공식 문서에서는 권한 그룹 개념을 설명하고 있습니다.
LOCATION 권한 그룹에는 다음과 같은 두 가지 권한이 포함됩니다:
ACCESS_FINE_LOCATION: 정밀 위치 접근ACCESS_COARSE_LOCATION: 대략적 위치 접근
문서에 따르면 같은 그룹 내 권한 중 하나가 허용되면 다른 권한도 자동으로 허용되어야 합니다. 하지만 실제 구현에서는 그렇지 않은 경우가 발생합니다.
LocationManager locManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
if (locManager.isProviderEnabled(LocationManager.GPS_PROVIDER)) {
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED
&& ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
// 권한 요청 로직
requestPermissions(new String[]{
Manifest.permission.ACCESS_FINE_LOCATION,
Manifest.permission.ACCESS_COARSE_LOCATION
}, LOCATION_PERMISSION_REQUEST);
} else {
Location currentLocation = locManager.getLastKnownLocation(LocationManager.GPS_PROVIDER);
if (currentLocation != null) {
double lat = currentLocation.getLatitude();
double lng = currentLocation.getLongitude();
// 위치 정보 처리
}
}
}
이 코드에서 ACCESS_COARSE_LOCATION만 허용된 상태로 GPS 제공자를 사용하려고 하면 애플리케이션이 크래시납니다. 이는 시스템이 정밀 위치 정보를 필요로 하기 때문입니다.
Spinner 선택 인덱스 설정 관련 문제
Spinner 컴포넌트의 setSelection() 메서드는 특정 항목을 선택 상태로 만들지만, 시각적으로 반영되지 않는 문제가 종종 발생합니다.
두 개의 Spinner가 연동되는 경우라면 다음과 같이 해결할 수 있습니다:
// 방법 1: 애니메이션 플래그 사용
spinner.setSelection(position, true);
// 방법 2: 데이터 갱신 후 선택 (권장)
ArrayAdapter<String> adapter = new ArrayAdapter<>(this, android.R.layout.simple_spinner_item, dataList);
spinner.setAdapter(adapter);
adapter.notifyDataSetChanged();
spinner.setSelection(position);
배열 검색 메서드 사용 오류
다음은 잘못된 배열 검색으로 인해 발생한 문제의 예시입니다:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<Spinner
android:id="@+id/spinner_control"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true" />
</RelativeLayout>
public class SampleActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_sample);
String[] items = new String[20];
for (int i = 0; i < items.length; i++) {
items[i] = "항목 " + i;
}
Spinner spinner = findViewById(R.id.spinner_control);
ArrayAdapter<String> adapter = new ArrayAdapter<>(this,
android.R.layout.simple_dropdown_item_1line, items);
spinner.setAdapter(adapter);
// 잘못된 사용 예
int selectedIndex = Arrays.binarySearch(items, "항목 11");
spinner.setSelection(selectedIndex); // selectedIndex = -2
}
}
위 코드에서 Arrays.binarySearch() 메서드는 정렬된 배열에서만 올바른 결과를 반환합니다. 문자열 배열이 사전순으로 정렬되어 있지 않기 때문에 음수 값을 반환하게 되며, 이 값은 유효한 인덱스가 아닙니다.
binarySearch 메서드의 반환 규칙은 다음과 같습니다:
- 검색 성공: 요소의 인덱스 (0 이상)
- 검색 실패: 삽입 지점을 나타내는 음수 값 (-insertionPoint - 1)
정확한 인덱스를 얻으려면 배열이 정렬되어 있어야 하거나, 선형 검색을 사용해야 합니다:
// 올바른 사용법
int correctIndex = -1;
for (int i = 0; i < items.length; i++) {
if ("항목 11".equals(items[i])) {
correctIndex = i;
break;
}
}
if (correctIndex >= 0) {
spinner.setSelection(correctIndex);
}