본문 바로가기

Android/Basic

[Android] startActivityForResult() 활용 예제

* 예제에 포함된 리스트는 리사이클러뷰로 구현하였으며, 이에 대한 개념은 나중에 포스팅할것이다.


 다른 화면으로 데이터를 전달할 때에는 intent의 Bundle 객체에 putExtra 메소드로 데이터를 넣어 전달한다. 대부분의 예제들은 첫번째 화면의 데이터를 두번째 화면에 전송해서 뿌리는 기능을 하는 것들이었다. (내가 해본 바로는..)

그래서 화면 전환은 무조건 startActivity() 로 했던 나였다. intent 객체에 그냥 데이터를 실어서 start 해버리면 되니까...


 이번엔 간단한 다른 예제를 생각해보자. (부스트코스 과제하다가 알게돼서 포스팅하는 것이다.)


'한줄평 작성 화면에서, 이전 화면으로 데이터 넘기기!'


먼저 스크린샷은 다음과 같다.


전체보기 액티비티


작성 액티비티


추가된 화면


사진이 왜 이렇게 올라가는지,,, 너무 불편하다.


 전체보기 액티비티에서 작성하기 버튼을 누르면, 작성 액티비티가 나오고 작성 액티비티에서 작성한 데이터를 다시 전체보기 액티비티로 되돌려 추가하는 예제이다.

 이 예제를 제대로 구현하기 위해서는 원래 DB가 필요한데.... (내가 구현한만큼만 하면 앱을 종료했을 때 추가한 데이터들이 모두 사라진다.) 아직 과제 리뷰를 받지 못했기때문에 DB는 후에 추가할 예정이다.

 그리고 리사이클러뷰를 위한 뷰홀더와 어댑터를 정의해야하는데 그것도 나중에 포스팅할 것. (사실 완벽하게 숙지하지 못해 포스팅이 조금 어려울것같다.)


public class AllReviewActivity extends AppCompatActivity {
private RecyclerView recyclerView;
private ReviewAdapter adapter;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_all_review);

// 앱바 제목 텍스트 변경
ActionBar ab = getSupportActionBar();
ab.setTitle("한줄평 목록");
ab.setDisplayHomeAsUpEnabled(true);
ab.setHomeButtonEnabled(true);

findViewById(R.id.btn_write).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent intent = new Intent(AllReviewActivity.this, WriteReviewActivity.class);
startActivityForResult(intent, 100);
}
});

recyclerView = findViewById(R.id.review_list);

adapter = new ReviewAdapter(getApplicationContext());
recyclerView.setAdapter(adapter);
recyclerView.setLayoutManager(new LinearLayoutManager(getApplicationContext()));

// 구분선
DividerItemDecoration dividerItemDecoration = new DividerItemDecoration(getApplicationContext(), LinearLayoutManager.VERTICAL);
dividerItemDecoration.setDrawable(getApplicationContext().getResources().getDrawable(R.drawable.recyclerview_divider, getTheme()));
recyclerView.addItemDecoration(dividerItemDecoration);

adapter.addItem(new ReviewItem(R.drawable.user1, "kym71**", "10분전", 4, "적당히 재밌다. 오랜만에 잠 안오는 영화 봤네요.", "추천 0"));
adapter.addItem(new ReviewItem(R.drawable.user1, "su_m**", "12분전", 5, "완전 재밌고 흥미진진하네요! 다음에 또 보고싶습니다. 배우들의 연기력에도 감탄했습니다", "추천 0"));
adapter.addItem(new ReviewItem(R.drawable.user1, "abc12**", "15분전", 5, "웃긴 내용보다는 좀 더 진지한 영화.", "추천 1"));
adapter.addItem(new ReviewItem(R.drawable.user1, "bu_t**", "17분전", 3, "연기가 부족한 느낌이 드는 배우도 있지만 전체적으로 재밌다.", "추천 0"));
adapter.addItem(new ReviewItem(R.drawable.user1, "em_r2**", "20분전", 4, "말이 필요없어요.", "추천 0"));


adapter.setOnItemClickListener(new ReviewAdapter.OnItemClickListener() {
@Override
public void onItemClick(RecyclerView.ViewHolder holder, View view, int position) {
Toast.makeText(AllReviewActivity.this, "신고하기 버튼 클릭", Toast.LENGTH_SHORT).show();
}
});
}
}


코드가 좀 지저분한데... (DB가 없다보니 저렇게 수작업으로 데이터를 추가하게됐다.)


onCreate 메소드에서 작성하기 버튼을 클릭하면 startActivityForResult() 메소드가 호출된다. 두번째 파라미터는 그냥 아무 값이나 넣어도 무방하다. (뭔가 static 상수로 선언해놓으면 가독성이 좋을것같다.)


작성하기 버튼을 클릭하면, 작성 액티비티가 띄워진다.


public class WriteReviewActivity extends AppCompatActivity {
RatingBar ratingBar;
EditText contents;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_write_review);

// 앱바 제목 텍스트 변경
ActionBar ab = getSupportActionBar();
ab.setTitle("한줄평 작성");

ratingBar = findViewById(R.id.rating_bar);
contents = findViewById(R.id.review_content);

findViewById(R.id.btn_save).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
returnToReviewList();
}
});

findViewById(R.id.btn_cancel).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent returnIntent = new Intent();
setResult(Activity.RESULT_CANCELED, returnIntent);
finish();
}
});
}

private void returnToReviewList(){
float rating = ratingBar.getRating();
String content = contents.getText().toString();

Intent returnIntent = new Intent();
returnIntent.putExtra("rating", rating);
returnIntent.putExtra("content", content);
setResult(Activity.RESULT_OK, returnIntent);
finish();
}
}


 정석대로 findViewById()로 뷰들 찾아주고, 그 뷰들로부터 get 메소드를 통해 입력하고자 하는 데이터를 가져와서 intent에 put한다.

 그리고 setResult() 메소드로 인텐트에 저장을 하는데, 첫번째 파라미터는 request 코드인 것 같다. (전체보기 액티비티에 있었던 것처럼 아무값이나 해도 되지만 Activity 클래스에 이미 구현되어있길래 그냥 넣어봤다. 아마 제대로 응답했는지 구분하려고 넣은 것 같다.)

 startActivity()와 다르게, 그냥 해당 액티비티를 finish() 해버리면 전체보기 액티비티로 인텐트가 전달된다. 원래 finish() 메소드는 화면을 그냥 꺼버리는 줄 알고있었는데 아주 신기하다.


 전달된 인텐트를 참조하기 위해서는 원래 getIntent() 메소드를 이용한다. 하지만 이번 예제는 다르게 startActivityForResult() 메소드를 이용했기 때문에, onActivityResult() 콜백 메소드를 오버라이드하면 된다. (호출했던 인텐트가 되돌아오면서 이 콜백 메소드가 호출된다.)

 

전체보기 액티비티의 onCreate 아래에 ctrl+o 해서 onActivityResult() 메소드를 골라 오버라이드하자.


@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);

if(data != null) {
float rating = data.getFloatExtra("rating", 0.0f);
String content = data.getStringExtra("content");
adapter.addItem(new ReviewItem(R.drawable.user1, "guest", "방금", rating, content, "추천 0"));
adapter.notifyDataSetChanged();
}
}


여기서 중요한게, 작성 액티비티로부터 넘어온 인텐트가 null 일수도 있다는 것이다. (백버튼을 누르면 null로 날라온다.) intent가 null일때 참조하려고하면 NullPointerException이 발생하고 앱이 꺼져버린다.


아무튼 원하는 대로 오버라이드하면 된다. 나는 안했지만 requestCode, resultCode를 이용해 분기를 나눠서 하면 좋을것이다. (RESULT_OK일 때, RESULT_CANCELED일 때!)

나는 작성 액티비티로부터 입력한 평점, 한줄평 내용을 리사이클러뷰 어댑터에 추가했다. (작성 화면에서 누락된게 있어서 나머지는 그냥 임의로 추가했다.)

여기서 또 실수를 한게 데이터가 변경되면 notifyDataSetChanged() 메소드를 꼭 호출해야한다는 것이다. 왜자꾸 까먹는건지... 역시 리사이클러뷰 개념 확립이 시급하다.


아무튼 나는 원래 위 과정을

startActivity - finish - startActivity - finish 순서로 했었는데,


이번엔 아주 간단하게

startActivityForResult - setResult - finish 순서로 말끔하게 끝낼 수 있었다.


기분탓이지만 저렇게하니 애니메이션도 다른것 같다.

새로운 액티비티가 띄워지면 오른쪽에서 밀려나오는 애니메이션이어서 기존에 한 방법은 계속 같은 방향으로 애니메이션이 적용됐다. 

그런데 되돌아오는 방식을 이용했더니 작성화면이 종료되면 오른쪽으로 밀려나갔다. (그래서 뭔가 더 있어보인다)



전체 코드 : https://github.com/Onedelay/MyMovie



'Android > Basic' 카테고리의 다른 글

[Android] Time to String 및 시간순으로 정렬하기  (0) 2018.06.22
[Android] Action Bar  (0) 2018.05.27
[Android] Permission  (0) 2018.05.17
[Android] Broadcast receiver 예제  (6) 2018.05.16
[Android] Activity 생명주기  (0) 2018.05.15