콜백함수란?
- 비동기 개념이 선행되어야 함
- 메인 스레드외에 다른 스레드를 사용해서 작업을 병렬적으로 (동시수행) 처리하는 것
- 다른 스레드가 진행중이던 작업이 끝났을 경우 호출하는 함수가 콜백함수
- 메인 스레드는 이 콜백함수를 이용해서 의도한 결과가 나올 수 있도록 다른 스레드에서 완료한 작업에 뒤이어서 진행할 수 있음
구체적인 예시
- 콜백함수가 없어서 에러 나는 코드
recyclerView_notices.addOnScrollListener(object : RecyclerView.OnScrollListener() {
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
super.onScrolled(recyclerView, dx, dy)
if (!recyclerView_notices.canScrollVertically(1){
공지사항을 불러옴 // (네트워크 작업)
리스트에 공지사항을 추가하고 새로고침 // (UI 작업)
}
})
- 콜백함수 사용
class MainActivity : AppCompatActivity(), PostListener { // PostListener를 구현한다.
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
recyclerView_notices.addOnScrollListener(object : RecyclerView.OnScrollListener() {
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
super.onScrolled(recyclerView, dx, dy)
if (!recyclerView_notices.canScrollVertically(1){
네트워크 작업(this) // this는 listener를 뜻한다.
// 여기서 했던 UI 작업을 loadPage 함수에서 한다.
}
}
})
}
override fun loadPage(notices: ArrayList<NoticeList>) { // override 함
UI 작업
}
}
class 네트워크 작업(listener: PostListener){
var mCallback = listener
...
...
...
mCallback.loadPage(notices) // 작업이 다 끝나고 loadPage를 호출한다.
}
- 위 그림의 네트워크 작업은 비동기 함수
- 즉 네트워크 작업이 완벽히 끝났는지 여부는 상관없이 메인 쓰레드는 바로
네트워크 작업
호출 이후UI 작업
호출함 - 네트워크 작업은 완료하는데 까지 상대적으로 오래걸리기 때문에 UI 작업을 하기 위해 필요한 리스트가 Null로 넘어오는 에러 발생
- 네트워크 작업이 끝난 이후 UI 작업이 진행되야 함
- 이때 필요한 것이 콜백함수
- 즉 네트워크 작업이 완벽히 끝났는지 여부는 상관없이 메인 쓰레드는 바로
간단한 코드 예시
자바
private interface OnStringCallback {
void onCallback(String string);
}
private void testCallback(OnStringCallback callback) {
callback.onCallback("hello callback");
}
testCallback(new OnStringCallback() {
@Override
public void onCallback(String string) {
Log.d("Test","Called : "+string);
}
});
코틀린
private fun testCallback(callback: ((String)->Unit)) {
// String 값을 콜백 받을것인데 return의 기본값은 Unit으로 설정한다
callback.invoke("hello callback")
}
testCallback {
Log.d("Test","Called : "+it)
}
좀더 자세한 코드 (자바)
// 선언과 정의의 단어 차이
//// 선언은 메모리에 안 올라감, 정의는 메모리에 올라감
// 콜백 클래스 선언
// 나머지 값을 뱉어주는 콜백 클래스 작성할 것임
class CallClass{
// 인터페이스 선언 (뼈대만. 기능 구현은 메인클래스에서)
interface onRestNumberCb{
void onRestNumber(int Number, int Rest);
}
// Number, DivNumber, CallBack 선언
private int Number = 0;
private int DivNumber = 0;
private onRestNumberCb myCallBack; // 위에서 정의한 인터페이스의 타입임을 주목
public void setOnRestNumberCb(onRestNumberCb callBack){
// 객체지향적 코드를 만들기 위해 CallBack 함수를 위한 set함수 선언
myCallBack = callBack;
}
public void setDivNumber(int div){
// 역시나 객체지향적 코드를 위한 set
DivNumber = div;
}
public void addNumber(int adder){
Number = adder;
if(myCallBack != null){
myCallBack.onRestNumber(Number, Number % DivNumber);
}
}
}
public class study{
public static void main(String[] args){
CallClass total = new CallClass();
// 인터페이스 선언을 해놓은 상태임
// 구체적 기능은 여기 Main 클래스에서 아래와 같이 재정의할 수 있음
// 인터페이스는 의도한 대로 구조만 형성해주고, 그 구조에서 돌아가는 "기능"을 사용자가 직접
// 정의해준다고 생각하면 편할 듯
CallClass.onRestNumberCb callBack = new CallClass.onRestNumberCb(){
@Override
public void onRestNumber(int Number, int Rest){
System.out.println(Number + "를 5로 나눈 나머지는 " + Rest + " 입니다.");
}
};
// 나눌값 셋팅
total.setDivNumber(5);
// callback 셋팅
// Main에서 정의해준 callback 함수의 기능을 살려서 이제 "객체" 만들어주는 것임
total.setOnRestNumberCb(callBack);
for(int i = 1; i <= 100; i++){
total.addNumber(i);
}
}
}
안드로이드에서의 활용
registerForActivityResult
- 핸드폰내의 이미지 가져오는 코드
val getContent = registerForActivityResult(GetContent()) { uri: Uri? ->
// Handle the returned Uri
// 여기서 갤러리의 이미지 Uri를 어떻게 처리할 지 정할 수 있음
}
override fun onCreate(savedInstanceState: Bundle?) {
// ...
val selectButton = findViewById<Button>(R.id.select_button)
selectButton.setOnClickListener {
// Pass in the mime type you'd like to allow the user to select
// as the input
getContent.launch("image/*")
}
}
PREVIOUS경제