안드로이드&iOS 앱 개발자 양성(82일차)
** Ioc & Component
** Activity 생성과 호출 그리고 종료
1. 생성
2. 호출
3. 데이터 공유
** 애플리케이션 간의 통신
** AndroidPorfolio를 수정해서 하위 Activity로 전환하기
1. MainActivity.java 파일에서 List의 항목을 클릭했을 때 처리하는 이벤트 핸들러 수정
2. ItemDetailActivity를 수정
3. MainActivity의 onResume 메소드 수정
4. 만들고 나면 충분한 테스트를 해야 한다.
5. 현재 작성한 프로그램 리팩토링(수정 - 성능 개선과 코드 가독성 높이기 위한 작업)
** 암시적 인텐트
** 암시적 인테트나 앱이 앱을 호출하는 것은 포트폴리오에서 사용하면 유용
** 기본 앱 연동
1. 동작
** 기본 앱 연동 실습
1. Application을 생성
2. 전화기능을 사용하기 위해서 AndroidManifest.xml 파일에 전화 권한을 설정
3. 화면 디자인 - 레이아웃을 수정
4. xml 파일에 디자인한 뷰들을 사용하기 위해서 참조형 변수에 대입
** Activity
1. 개요
2. 안드로이드에서 Activity 사용
3. 안드로이드 애플리케이션의 실행
4. 안드로이드는 액티비티를 스택(Stack)을 이용해서 관리
5. 액티비티의 상태
6. 수명 주기 관련 메소드
7. 하위 데이터 출력시 화면의 호출
8. Activity 상태 저장
9. Android의 Task 관리
** URL & URI
** 권한 설정
** Android API 버전과 하위 호환성
1. Google의 support library를 이용
2. 개발자 코드에서 버전을 직접 식별해서 처리
3. 오픈 소스 라이브러리를 이용
** Fragment
** IoC & Component
- IoC(제어의 역전, 제어의 역흐름) : 클래스의 생성은 개발자가 하지만 인스턴스를 생성해서 생명주기를 관리하는 역할은 프레임워크, SDK가 수행하는 것을 말한다.
- 안드로이드에서 관리하는 것은 Component라고 하고,
Activity(화면), BroadcastReceiver(알림), Service(백그라운드 작업 수행), ContentProvider(데이터 공유) 4가지이다.
- Spring Framework에서 관리하는 것은 Bean이다.
- IoC를 사용하는 이유 : 개발자는 생명주기와 관련된 작업을 직접 이해해서 할 필요없이 비지니스 로직 작성에만 집중하도록 하기 위해서 이다.
** Activity 생성과 호출 그리고 종료
1. 생성
- Activity 클래스로부터 상속받아야 한다.
2. 호출
1) 명시적 호출 - 클래스 이름을 기재 : 애플리케이션 내의 Activity를 호출하기 위해서 이다.
- 애플리케이션 내에서는 클래스 이름을 알 수 있다.
Intent 인텐트 변수명 = new Intent(호출하는 클래스의 인스턴스, 호출당하는 클래스의 clazz);
- clazz는 Class이름.class : 클래스 정보를 넘겨주면 인스턴스 생성과 관련된 모든 수명주기를 안드로이드가 책임진다.
startActivity(인텐트); //호출당하는 액티비티가 없어질 때 콜백 메소드를 호출하지 않는다. - 하위 액티비티가 종료되고 상위 액티비티에게 넘겨줄 데이터가 없을 때
혹은
startActivityForResult(구분하기 위한 번호, 인텐트); //호출하는 곳에소의 콜백 메소드가 호출된다. - 하위 액티비티가 종료되고 상위 액티비티에게 넘겨줄 데이터가 있을 때
2) 암시적 호출 - 별명을 사용
- 다른 애플리케이션을 호출할 때는 클래스 이름을 사용할 수 없다.
- 스마트 폰 애플리케이션들은 샌드박스 형태로 외부에 숨겨진 채로 생성된다.
3. 데이터 공유
- public class를 만들고 static 변수를 만들면 프로그램내의 모든 곳에서 접근 가능 : 객체 지향 프로그래밍 그리고 Server 프로그래밍에서는 권장하지 않는다.
- 객체 지향에서는 필요한 경우 Singleton 디자인 패턴을 이용해서 클래스를 디자인하고 이 클래스에 인스턴스 변수를 생성해서 모든 곳에서 공유하는 방법을 권장 - 스마트 폰 SDK에서는 시작 객체를 Singleton으로 생성하고 그 Singleton에 접근할 수 있는 방법을 제공한다. : Android는 MainActivity.this
- 상위 Activity에서 하위 Acticity로 데이터를 전달
Intent를 생성하고 putExtra(String key, Serializable data)를 호출하면 된다.
하위 Activity에서는 getIntent()를 이용해서 Intent를 찾고 찾은 Intent를 가지고 get자료형Extra(String key)를 호출하면 된다.
일반 자료형이 아니라서 자료형Extra 메소드가 없는 경우에는 getSerializable() 메소드가 있고 이 메소드의 리턴 값을 강제 형 변환해서 사용하면 된다
- 하위 Activity에서 상위 Activityfh 데이터 전달
호출하는 곳에서는 startActivityForResult(int requestCode, Intent intent)를 호출 requestCode는 호출하는 Activity를 구분하기 위한 코드이다.
호출당하는 곳에서는 소멸되기 직전에
Intent ineten = new Intent();
Intent.putExtra(String key, Serializale data);
setResult(int resultCode, intent);
호출하는 곳에서는
Void onActivityResult(int requestCode, int resultCode, Intent intent)를 재정의
requestCode와 resultCode를 이용해서 어떤 하위 Activity가 종료되었는지 확인하고 intent를 이용해서 데이터를 가져와서 사용한다.
** 애플리케이션 간의 통신
- 애플리케이션들은 다른 애플리케이션의 클래스를 사용할 수 없기 때문에 데이터를 공유하기 위해서는 통신을 이용해야 한다.
안드로이드나 iOS는 독특하게 데이터를 공유할 수 있는 다른 방법을 제공한다.
** AndroidPortfolio를 수정해서 하위 Activity로 전환하기
1. MainActicity.java 파일에서 List의 항목을 클릭했을 때를 처리하는 이벤트 핸들러 수정
//항목을 선택했을 때 호출되는 이벤트 핸들러 작성
listView.setOnItemClickListener(new ListView.OnItemClickListener(){
@Override
//adapterView는 이벤트가 발생한 뷰 view는 선택한 항목 뷰
//i가 선택한 항목의 인덱스 l은 선택한 항목 뷰의 id
public void onItemClick(AdapterView<?> adapterView, View view, int i, long l){
//선택한 항목의 데이터
Item item = list.get(i);
//토스트로 itemid를 출력
//Toast.makeText(MainActivity.this, item.itemid + "", Toast.LENGTH_LONG).show();
//하위 Activity 출력
Intent intent = new Intent(MainActivity.this, ItemDetailActivity.class);
//데이터 전달하기
intent.putExtra("itemid", item.itemid);
startActivity(intent);
}
});
2. ItemDetatilActivity를 수정
1) 레이아웃 수정
- 뒤로 버튼을 추가
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="뒤로"
android:id="@+id/backbtn"/>
2) ThreadEx 클래스의 URL 만드는 부분을 수정
//URL 만들기
//호출하는 인테트 가져오기
Intent intent = getIntent();
//itemid의 값을 정수로 가져오고 없을 때는 1
int itemid = intent.getIntExtra("itemid", 1);
URL url = new URL("http://192.168.0.84:8080/mysqlserver/detail?itemid="+itemid);
3) onCreate 메소드에 뒤로 버튼을 눌렀을 때 현재 Activity를 종료하는 이벤트 핸들러를 작성
backbtn = (Button)findViewById(R.id.backbtn);
backbtn.setOnClickListener(new Button.OnClickListener(){
@Override
public void onClick(View view) {
//현재 액티비티 종료
finish();
}
});
3. MainActivity의 onResume 메소드 수정
- onCreate는 Activity가 생성될 때 1번만 호출되지만 onResume은 화면에 보여질 때마다 호출된다.
@Override
public void onResume(){
super.onResume();
//데이터가 없을 때만 데이터 가져오기
if(list == null || list.size() < 1){
new ThreadEx().start();
ind.setVisibility(View.VISIBLE);
}
}
4. 만들고 나면 충분한 테스트를 해야 한다.
5. 현재 작성한 프로그램 리팩토링(수정 - 성능 개선과 코드 가독성 높이기 위한 작업)
- 하나의 클래스나 하나의 메소드 코드가 길면 별도의 클래스로 분리하거나 메소드 코드를 줄이기 위해 다른 메소드를 생성해서 호출하도록 변경한다.
- 메인 화면에서 itemid를 넘겨서 그 itemid를 가지고 데이터를 다시 찾아오게 된다.
이미지를 다운로드받는 별도의 스레드까지 생각하면 상세보기를 위해서 서버에 3번 접근해야 한다.
서버의 접근횟수를 줄이는 것도 리팩토링의 중요한 과제 중의 하나이다.
** 암시적 인텐트
- AndroidManifest.xml 파일에 Activity를 등록할 때 Intent-filter를 추가해야 한다.
iOS는 App의 URI를 이용해서 App을 호출하는 구조지만 Android는 App 안의 화면 단위로 출력이 가능하다.
- 다른 Application에서 호출할 수 있도록 Activity를 만들 때는 아래와 같은 intent=filter를 등록한다.
<intent>
<action android:name="아무거나 가능 - 구별만 할 수 있으면 됨"/>
<category android:name="아무거나 가능"/>
</intent>
- 통상적으로 action의 name은 패키지이름.액티비티이름으로 많이 하고 category는 DEFAULT를 많이 사용한다.
- Intent를 생성할 때 클래스 이름을 기재하지 않고 intent.setAction("action name")
- 책이나 인터넷에서는 자신의 Application에 있는 인텐트를 암시적 인텐트로 사용하는 경우가 있는데 이것은 설명을 하기 위해서이다.
** 암시적 인텐트나 앱이 앱을 호출하는 것은 포트폴리오에서 사용하면 유용
** 기본 앱 연동
- Intent의 action에 기본 앱의 이름을 설정해서 현재 앱 안에서 기본 앱을 사용할 수 있도록 한다.
1. 동작
ACTION_CALL : 통화시작
ACTION_EDIT
ACTION_MAIN : 메인을 실행
ACTION_VIEW
ACTION_DIAL : 전화를 건다.
ACTION_BATTERY_LOW
ACTION_BATTERY_PLUG
ACTION_SCREEN_ON
ACTION_HEADSET_PLUG
ACTION_TIMEZONE_CHANGED
** 기본 앱 연동 실습
- 주소록, 카메라, 음성인식, 지도, 브라우저, 전화 앱을 실행
카메라의 경우는 촬영한 이미지를 ImageView에 가져와서 출력
주소록 API를 이용하는 경우 제조사에 따라 안되는 경우도 있다.
초창기 안드로이드 폰들은 자체 API를 추가해서 기본 앱을 사용할 수 있었다.
최근에는 Google에서 기본 앱 연동에 관련된 자체 API를 사용할 수 없도록 했다
지도와 브라우저, 전화 앱은 데이터를 설정해서 호출
1. Application을 생성
2. 전화기능을 사용하기 위해서 AndroidManifest.xml 파일에 전화 권한을 설정
<uses-permission android:name="android.permission.CALL_PHONE"/>
3. 화면 디자인 - 레이아웃을 수정
- 버튼을 6개 배치, 텍스트 뷰 1개, 이미지 뷰 1개
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity"
android:orientation="vertical">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/resultView"/>
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/btn_contacts"
android:text="주소록 앱 연동"/>
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/btn_camera"
android:text="카메라 앱 연동"/>
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/btn_voice"
android:text="음성인식 앱 연동"/>
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/btn_map"
android:text="지도 앱 연동"/>
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/btn_browser"
android:text="브라우저 앱 연동"/>
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/btn_call"
android:text="전화 앱 연동"/>
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/reusltImageView"
android:clickable="true"/>
</LinearLayout>
4. xml 파일에 디자인한 뷰들을 사용하기 위해서 참조형 변수에 대입
1) MainActivity.java 파일에 인스턴스 변수를 선언
ImageView resultImageView;
Button btn_contact, btn_map, btn_call, btn_voice, btn_browser, btn_camera;
TextView resultView;
2) MainActivity.java 파일의 onCreate 메소드에 인스턴스 변수의 뷰를 찾아서 대입
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
resultImageView = (ImageView)findViewById(R.id.reusltImageView);
btn_contact = (Button)findViewById(R.id.btn_contact);
btn_call = (Button)findViewById(R.id.btn_call);
btn_map = (Button)findViewById(R.id.btn_map);
btn_voice = (Button)findViewById(R.id.btn_voice);
btn_browser = (Button)findViewById(R.id.btn_browser);
btn_camera = (Button)findViewById(R.id.btn_camera);
resultView = (TextView)findViewById(R.id.resultView);
}
3) onCreate 메소드에 버튼들의 클릭 이벤트 처리를 위한 코드를 작성
//클릭 이벤트 처리 - 동일한 이벤트 처리가 많은 경우 이벤트 라우팅
View.OnClickListener listener = new View.OnClickListener(){
@Override
public void onClick(View view) {
Intent intent = null;
switch (view.getId()){
case R.id.btn_contact :
//주소록 앱 실행
intent = new Intent(Intent.ACTION_PICK);
intent.setData(ContactsContract.CommonDataKinds.Phone.CONTENT_URI);
//여러 개의 Activity를 실행하거나 하위 Activity로부터 데이터를 넘겨받고자 하는 경우 아래 메소드로 Activity를 호출
//번호를 구분하기 위한 거ㅅ이므로 임의로 배정해도 되지만 중복되면 안된다.
startActivityForResult(intent, 10);
break;
case R.id.btn_browser :
intent = new Intent(Intent.ACTION_VIEW, Uri.parse("http://seoul.go.kr"));
startActivityForResult(intent, 30);
break;
case R.id.btn_map :
intent = new Intent(Intent.ACTION_VIEW, Uri.parse("geo:37.5666, 126.9779"));
startActivityForResult(intent, 40);
break;
case R.id.btn_voice :
break;
case R.id.btn_camera :
intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
startActivityForResult(intent, 20);
break;
case R.id.btn_call :
//권한 설정 여부 확인
if(ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.CALL_PHONE) == PackageManager.PERMISSION_GRANTED){
//권한이 있는 경우
intent = new Intent(Intent.ACTION_CALL, Uri.parse("tel:010-5662-6631"));
startActivityForResult(intent, 50);
}else{
//권한이 없는 경우
ActivityCompat.requestPermissions(MainActivity.this,
new String [] {Manifest.permission.CALL_PHONE}, 100);
}
break;
case R.id.reusltImageView :
break;
}
}
};
//이벤트 핸들러 연경
btn_contact.setOnClickListener(listener);
btn_camera.setOnClickListener(listener);
btn_browser.setOnClickListener(listener);
btn_call.setOnClickListener(listener);
btn_map.setOnClickListener(listener);
btn_voice.setOnClickListener(listener);
resultImageView.setOnClickListener(listener);
4) MainActivity.java 파일에 호출된 Activity가 종료된 후 호출되는 메소드를 작성
//startActivityResult로 하위 Activity를 출력한 경우 하위 Activity가 소멸되면 호출되는 메소드
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
//상위 클래스의 메소드 호출 파괴하는 메소드가 아니면 상위 클래스의 메소드를 먼저 호출하는 것이 일반적이다.
super.onActivityResult(requestCode, resultCode, data);
//여러 Activity를 호출한 경우 requestCode로 구분해 주어야 한다.
if(requestCode == 20) {
//카메라는 촬용한 사진을 data라는 이름으로 Bitmap 타입으로 넘겨준다
Bitmap bitmap = (Bitmap) data.getExtras().get("data");
resultImageView.setImageBitmap(bitmap);
}
}
** Activity
1. 개요
- 애플리케이션의 기능을 갖는 단일의 독립 실행형 모듈(리눅스의 프로세스)
- 모듈 : 독립적으로 실행 가능한 객체
안드로이드에서는 Activity와 Application이 모듈
리눅스에서는 이렇게 독립적으로 실행 가능한 모듈을 프로세스라고 한다.
- 안드로이드에서는 Activity가 화면 구성의 단위이다.
- View는 화면에 출력은 되지만 모듈은 아니기 때문에 독립적으로 존재할 수 없다.
- 안드로이드에서는 화면에 출력되는 애플리케이션은 반드시 한 개 이상의 Activity를 소유해야 한다.
- Activity 클래스는 반드시 Activity클래스로부터 상속받는 클래스로 생성해야 한다.
- 실제 화면 구성요소는 없기 때문에 화면에 무엇인가를 출력하고자 할 때는 기본적으로 setContentView라는 메소드를 호출해야 한다.
매개변수로는 View 객체 또는 layout의 ID를 전달하면 된다.
setContentView 메소드는 디바이스 가로와 세로 크기를 인지하고 있다면 View의 크기를 그 크기에 맞추어서 출력한다.
- 전체 화면 위에 새로운 View를 추가하고자 하는 경우에는 addContentView를 이용해서 추가할 View와 크기 옵션을 설정하면 된다.
- 안드로이드나 iOS가 View를 직접 출력하지 않고 Activity나 ViewController라는 개념을 도입한 이유는 View를 화면에 직접 출력하게 되면 View에 출력할 데이터를 View가 소유하고 있어야 하는데 이 경우 하나의 화면에 여러 개의 View가 놓이게 되면 Model을 만드는 것이 너무 어려워진다.
- 이벤트 관리와 데이터 관리 및 View의 배치는 Activity나 ViewController가 관리를 하고 View는 화면 출력만 담당하도록 한다.
2. 안드로이드에서 Activity 사용
- 보안상의 이유로 반드시 AndroidManifest.xml 파일에 등록해야 한다.
이전에는 직접 등록을 했지만 지금은 Activity 추가 메뉴를 이용하면 자동으로 등록된다.
- Activity 클래스 이름을 작성할 때 현재 애플리케이션 내의 Activity는 패키지 이름을 전부 작성할 필용없이 .클래스이름으로 작성한다.
3. 안드로이드 애플리케이션의 실행
- 5.0이전까지는 달빅 가상 머신 위에서 실행했다.
- 5.0버전부터는 가상 머신을 없애고 안드로이드 런타임(ART) 시스템의 통제하에 리눅스의 프로세스로 실행
- 디바이스의 리소스가 한계에 달하면 APT가 스스로 애플리케이션을 중지시킨다.
포그라운드 프로세스 : 현재 화면에 출력된 상태에서 사용자와의 상호작용을 하는 것
가시적 프로세스 : 현재 화면에 출력은 되어 있지만 사용자와의 상호작용을 하지 않는 것
서비스 프로세스 : 화면에 출력되지 않지만 작업은 수행되고 있는 것
백그라운드 프로세스 : 사용자가 볼 수 없는 액티비티를 1개 이상 포함하고 있는 프로세스
비어있는 프로세스 : 실행되는 애플리케이션을 포함하지 않으면 새로 실행되는 애플리케이션을 호스팅하기 위해 메모리에 남아있는 프로세스
4. 안드로이드는 액티비티를 스택(Stack)을 이용해서 관리
5. 액티비티의 상태
- 활성 상태(Active)
- 일시정지 상태(Paused)
- 정지 상태(Stoped)
- 종료 상태(Finish)
6. 수명 주기 관련 메소드
- 도큐먼트를 반드시 확인 : 예측하면 안된다.
- 스마트 폰은 API가 수시로 변경되기 때문에 이전에는 호출되는 메소드가 새로운 API에서는 호출이 안되거나 순서가 변경될 수 있다.
onCreate : Activity가 처음 만들어질 때 호출되는 메소드
뷰를 초기화하고 Activity의 초기화를 수행
onRestart : Activity가 다시 시작될 때 호출되는 메소드
onStart : onCreate나 onRestart가 호출된 후 호출되는 메소드
onResume : Activity가 활성화 될 때 호출되는 메소드
화면에 출력될 때 호출되는 메소드
onPause : Activity가 비활성화될 때 호출되는 메소드
저장해야 하는 데이터가 있으면 전부 저장
음악 재생 중 전화가 올 때 전화가 끝난 후 다시 돌아올 때 음악을 이어 재생하고자 하면 이 메소드에 재생 시간을 저장
onPause가 호출되고 나면 애플리케이션은 언제든지 메모리에서 삭제될 수 있다.
onStop : onPause가 호출되고 화면에서 보이지 않게될 때 호출되는 메소드
onDestry : Activity가 파괴될 때 호출되는 메소드
isFinishing이라는 속성을 확인하면 애플리케이션이 종료시킨 것인지 시스템이 종료시킨 것이지 확인 가능
7. 하위 데이터 출력시 화면의 호출
상위 Activity -> 하위 Activity
- 상위에서 하위로 이동할 때는 상위에서 하위를 생성한다.
- 하위에서 상위로 이동할 때는 하위가 가리고 있던 부분을 다시 출력하는 것이다.
상위 Activity에서는 onResume만 호출된다.
8. Activity 상태 저장
- Activity가 종료됐다 다시 만들어지는 경우 이전 내용을 복원하기 위한 것
- 회전이 발생하면 Activity를 새로 만든다.
- onSaveInstanceState 메소드를 오버라이딩해서 Bundle에 데이터를 저장하면 onCreate 메소드가 호출될 그 저장된 내용이 전달된다.
마지막 상태를 저장했다가 액티비티가 시작될 때 다시 복원하고자 하면 Bundle을 이용한다.
이 Bundle은 Map과 유사하다.
- EditText는 설정하지 않아도 스스로 데이터를 저장해두었다가 다시 출력할 때 복원해야 한다.
9. Android의 Task 관리
- Task : 앱 실행을 위한 정보를 저장하는 공간
- 프로세스를 앱의 물리적인 실행단위라고 하고 태스크는 앱의 논리적인 실행단위
- 앱을 1개 실행하면 프로세스가 2개가 되고 태스크도 2개이다.
- 하나의 앱을 실행한 수 이 앱에서 다른 앱을 호출하게되면 프로세스는 2개이지만 태스크는 1개이다.
- 안드로이드의 Activity는 실행이 될 때 실행 모드를 설정할 수 있다.
- Activity를 등록할 때 android:launchMode에 속성을 지정해서 실행모드를 설정
standard : 기본 값으로 Intent를 생성할 때마다 Activity의 인스턴스가 생성되고 태스크 목록의 맨 위에 반복해서 올리는 구조
이 모드에서는 동일한 Activity의 Intent를 2번 생성하면 2개가 Task에 쌓이게 된다.
singleTop : 액티비티가 최상단에 존재하면 생성하지 않는 모드
singleTask : 다른 애플리케이션의 액티비티를 호출한 경우 새로운 Task를 생성하는 모드 - 새로운 액티비티에서 이전 버튼을 눌러도 이전으로 돌아오지 않고 종료된다.
singleInatance : 이 액티비티만 별도의 Task로 생성
- Intent에 Flag를 설정해서 Task 안의 내용을 변경하는 것도 가능하다.
Intent.setFlags(Intent.FALG_ACTIVITY_옵션)
옵션에 CLERE_TOP을 설정하면 이전 Activity 정보를 모두 삭제
** URL & URI
- URL : 인터넷 상에서의 자원의 위치
- URI : 모든 자원의 위치
- URI가 URL보다는 큰 개념
- URL을 요청하면 웹 주소를 대입하는 것이고 URI를 요청하면 웹 주소가 아닐 수도 있다.
** 권한 설정
- Android 6.0 이전까지는 권한 설정을 정적으로 수행
AndroidManifest.xml 파일에 필요한 권한을 설정하면 앱을 설치할 때 권한 사용 여부를 묻고 앱을 설치해서 사용한다.
- Android 6.0부터는 일부분의 기능은 정적만으로는 사용이 안되고 기능을 사용할 때 묻는 동적 설정 방식으로 변화되었다.
- 스마트 폰 SDK에서는 이러한 변화가 와서 안드로이드 뿐 아니라 대다수의 스마트 폰 SDK에서 발생했다.
- 안드로이드에서 동적 권한 설정 여부 묻기
if(ContextCompat.checkSelfPermission(Context context, Manifest.permission.권한) == PackageManager.PERMSSION_GRANTED){
권한이 부여된 경우 수행할 내용;
}else{
//권한이 부여되지 않은 경우 권한을 요청;
ActivityCompat.requestPermission(Context context, new String [] {Manifest.permission.권한...}, 번호);
}
- 외부에 파일을 저장할 때 카메라를 직접 사용할 때 이러한 동적 권한을 설정해야 한다.
** Android API 버전과 하위 호환성
- Application을 생성할 때 설치가 되는 최하 운영체제 버전을 설정할 수 있다.
minSdkVersion : 애플리케이션이 설치되는 최하 API 버전
targerSdkVersion : 애플리케이션을 개발할 때 사용한 API 버전
- minSdkVersionrhk targerSdkVersion이 다른 경우 minSdkVersion에서 모든 기능을 사용할 수 있도록 만들어 주는 것을 하위 호환성이라고 한다.
- 2개의 버전에 대한 설정은 build.gradle 파일을 수정해도 할 수 있다.
1. Google의 support library를 이용
- 표준 라이브러리는 아니고 하위 호환성 문제 때문에 구글이 제공하는 라이브러리
- dependencies에 설정해서 사용
이전에는 com.android...로 시작
2019년 androidx...로 시작
- 안드로이드의 Activity를 만들 때는 Activity 클래스로부터 상속을 받아야 하는데 이렇게 하게 되면 운영체제 버전 별로 다른 Activity 클래스를 상속받아야 한다.
AppCompatActivity를 상속받으면 설치되는 운영체제 버전에 따라 안드로이드 시스템이 Activity 클래스를 결정해 준다.
안드로이드에서 동일한 이름의 클래스가 AppCompat이 붙은 상태로 존재하면 이건 전부 하위 버전 호환성 문제를 해결해 주기 위한 것이다.
2. 개발자 코드에서 버전을 직접 식별해서 처리
- 현재 디바이스의 버전 확인 : Builde.VERSION.SDK.INT
- 각각의 버전은 Build.VERSION_CODES.운영체제이름 또는 약자
3. 오픈 소스 라이브러리를 이용
- 다른 개발자들이 API 버전에 상관없이 사용할 수 있도록 만든 API가 있으면 그 API를 사용하는 것
- 오픈 소스 라이브러리를 사용할 때 주의할 점은 마켓에서 reject 여부를 반드시 확인하고 사용해야 한다.
** Fragment
- API Level 11(Android 3.0)에서 등장한 뷰
- 안드로이드에서는 출력의 개념으로 2가지를 사용했는데 Activity와 View이다.
- 태블릿의 등장으로 인해 Activity 와 View 만으로 화면 출력을 하는데 한계
- 하나의 화면을 2개로 분할해서 출력하고자 하는 경우에