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

recyclerview에서 startactivityforresult 사용 방법

0 추천

다음과 같이 데이터를 이동하려고 합니다: BusRouteMapMyAdapter.java(recyclerview adapter) -> CustomerDialog.java -> BusRouteMapActivity.java(activity)


CustomerDialog.java는 다이얼로그 역할을 하는 AppCompatactivity입니다.

StartActivityForResult는 BusRouteMapMyAdapter의 onBindViewHolder 안에 작성되어 있고, setResult는 CustomerDialog의 btn_selectstart(button) setOnClickListener에 작성되어 있으며, onActivityResult는 BusRouteMapActivity에 작성되어 있습니다.

StartActivityForResult는 제대로 작동하지만, CustomerDialog에서 BusRouteMapActivity로 데이터가 전송되지 않는 문제가 발생합니다. onActivityResult의 Result_OK가 실행되어야 하지만 Result_Cancelled가 실행됩니다.

이 문제를 해결하는 방법이 있을까요?

BusRouteMapActivity.java(activity):

protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    if (requestCode == 1) {
        if (resultCode == Activity.RESULT_OK) {
            //데이터받기
            startBusRoutedId = data.getStringExtra("busRoutedId_start");
            startArsId = data.getStringExtra("arsId_start");
            startStationNm = data.getStringExtra("stationNm_start");
            startStId = data.getStringExtra("station_start");
            startStaOrd = data.getStringExtra("staOrd_start");
            startDirection = data.getStringExtra("direction_start");

            tv_selectstart = (TextView) findViewById(R.id.tv_selectstart);
            tv_selectstart.setText(startStationNm);
        }
        if (resultCode == Activity.RESULT_CANCELED) {
            Toast.makeText(BusRouteMapActivity.this, "불러온 데이터가 없습니다.", Toast.LENGTH_SHORT).show();

        }
    }
}

BusRouteMapMyAdapter.java(recyclerview adapter):

public BusRouteMapMyAdapter(ArrayList<busRouteMapItem> list, Context context){
    this.mList = list;
    this.mInflate = LayoutInflater.from(context);
    //this.mContext = context;
}


@Override
public BusRouteMapMyAdapter.MyViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
    View view = mInflate.inflate(R.layout.example_bus_route_map, parent, false);
    MyViewHolder viewHolder = new MyViewHolder(view);
    mContext = parent.getContext();
    return viewHolder;
}

@SuppressLint("RecyclerView")
@Override
public void onBindViewHolder(@NonNull MyViewHolder holder, int position) {
    holder.tv1.setText(mList.get(position).getStationNm());
    holder.tv_routId.setText(mList.get(position).getBusRouteId());
    holder.tv_seq.setText(mList.get(position).getSeq());
    busRouteId = mList.get(position).getBusRouteId();
    ord = mList.get(position).getSeq();
    holder.tv_routId.setText(busRouteId);
    holder.tv_seq.setText(ord);
    holder.tv3.setText(mList.get(position).getPlainNo());


    holder.btn_st.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            String station_name = (String)(mList.get(position).getStationNm());
            int pos = holder.getAbsoluteAdapterPosition();
            if (pos != RecyclerView.NO_POSITION) {
                Toast.makeText(mContext, station_name + "를 클릭하셨습니다", Toast.LENGTH_SHORT).show();
                Context context = v.getContext();

                    Intent intent = new Intent(v.getContext(), CustomDialog.class);
                    intent.putExtra("busRoutedId", mList.get(pos).getBusRouteId());    //노선ID
                    intent.putExtra("arsId", mList.get(pos).getArsId());        //정류소ID
                    intent.putExtra("stationNm", mList.get(pos).getStationNm());    //정류소명
                    intent.putExtra("beginTm", mList.get(pos).getBeginTm());    //첫차시간
                    intent.putExtra("lastTm", mList.get(pos).getLastTm());        //막차시간
                    intent.putExtra("station", mList.get(pos).getStation());        //정류장9자리ID
                    intent.putExtra("staOrd", mList.get(pos).getSeq());//순번
                    intent.putExtra("direction", mList.get(pos).getDirection()); //목적지(방면)
                    ((Activity)mContext).startActivityForResult(intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK),1);
                    
            }
        }
    });
}

 

 

CustomerDialog.java:

        btn_selectstart.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            Toast.makeText(CustomDialog.this, "출발지로 선택하였습니다." + busRouteId + arsId + stationNm + stId + staOrd+ direction, Toast.LENGTH_SHORT).show();

            Intent intent_start = new Intent();
            intent_start.putExtra("busRoutedId_start", busRouteId);    //노선ID
            intent_start.putExtra("arsId_start", arsId);        //정류소ID
            intent_start.putExtra("stationNm_start", stationNm);    //정류소명
            intent_start.putExtra("station_start", stId);        //정류장9자리ID
            intent_start.putExtra("staOrd_start", staOrd);//순번
            intent_start.putExtra("direction_start", direction); //목적지(방면)
            setResult(Activity.RESULT_OK, intent_start);
            //팝업 닫기
            finish();
        }
    });

 

익명입니다 (310 포인트) 님이 2021년 10월 18일 질문
어떤 상황에서 RESULT_CANCELLED가 발생하는지에 대한 설명이 빠져있네요. Back button을 눌렀을 때 처리를 원하시는 건지, 아니면 다른 상황인지요.
customerDialog에 있는 btn_selectstart 버튼을 누르면 BusRouteMapActivity에서 resultCode가 Activity.RESULT_OK가 되어 해당 액티비티로 데이터가 이동되어야합니다. 그러나 그러지 못하고 Activity.RESULTCANCELLED가 발생하여 데이터가 이동되지 않습니다. 해결할 수 있는 방법이 있을까요?
CustomDialog를 띄을 때 Intent.FLAG_ACTIVITY_NEW_TASK를 제거하고 해보시겠어요?

Intent intent = new Intent(v.getContext(), CustomDialog.class);
// 중간 생략
mContext.startActivityForResult(intent,1);

그리고 혹 AndroidManifest에 해당 액티비티에 singleton mode나 이런게 적용되어 있나요?
선생님 정말 감사합니다.  FLAG를 제거하고 해봤더니 바로 실행 됩니다.
다른 조언들도 너무 감사드립니다.
혹시 FLAG_ACTIVITY_NEW_TASK를 설정했을 때 작동이 안 되는 이유가 있을까요?
아래에 올린 개발자 문서에 나온 내용을 참고하세요. 해당 플래그를 사용하면 앱을 새로 여는 것과 마찬가지로 단순히 화면을 내앱의 앞에 가져다 놓게 되는 거지, 상호작용을 할 수 있는 상태가 아닙니다.

2개의 답변

0 추천

API document에 보면 FLAG_ACTIVITY_NEW_TASK에 이렇게 나와 있습니다.

FLAG_ACTIVITY_NEW_TASK

Added in API level 1

public static final int FLAG_ACTIVITY_NEW_TASK

If set, this activity will become the start of a new task on this history stack. A task (from the activity that started it to the next task activity) defines an atomic group of activities that the user can move to. Tasks can be moved to the foreground and background; all of the activities inside of a particular task always remain in the same order. See Tasks and Back Stack for more information about tasks.

This flag is generally used by activities that want to present a "launcher" style behavior: they give the user a list of separate things that can be done, which otherwise run completely independently of the activity launching them.

When using this flag, if a task is already running for the activity you are now starting, then a new activity will not be started; instead, the current task will simply be brought to the front of the screen with the state it was last in. See FLAG_ACTIVITY_MULTIPLE_TASK for a flag to disable this behavior.

This flag can not be used when the caller is requesting a result from the activity being launched.

Constant Value: 268435456 (0x10000000)

spark (227,530 포인트) 님이 2021년 10월 18일 답변
0 추천
// Serializable를 구현
public class BusRouteMapItem implements Serializable {
   //기존과 동일
}


public class BusRouteMapMyAdapter ... {
    // 인터페이스를 통해 외부와 커뮤니케이션을 합니다. 이게 정석적인 방법입니다.
    interface Listener {
        void onRouteClicked(BusRouteMapItem route);
    }

    private final Lisetner listener;
    public class BusRouteMapMyAdapter(ArrayList<busRouteMapItem> list, Listener listener) {
        this.mList = list;
        this.mInflate = LayoutInflater.from(context);
        // 리스너를 외부에서 주입.
        this.listener = listener;
    }

 
  private BusRouteMapItem getItem(int position) {
       return mList.get(position);
  }
 
@Override
public void onBindViewHolder(@NonNull MyViewHolder holder, int position) {
    if (pos == RecyclerView.NO_POSITION) return;

    BusRouteMapItem item = getItem(position);
    holder.bindItem(item);   
    holder.btn_st.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            // 리스너에게 아이템이 눌렸음을 알려줌.
            listener.onRouteClicked(item);
        }
    });
}


// Activity
// 액티비티에서 어댑터의 생성자에 리스너 인스턴스를 전달하여 어탭터와 커뮤니케이션을 함.
BusRouteMapMyAdapter adapter = new BusRouteMapMyAdapter(items, new BusRouteMapMyAdapter.Listner() {
    @Override
    public void onRouteClicked(BusRouteMapItem route) {
          // 어댑터에서 아이템이 눌리면 여기가 호출되겠죠.
          showCustomDialogForResult(route); 
    }
});

private void showCustomDialogForResult(BusRouteMapItem route) {
    Intent intent = new Intent(v.getContext(), CustomDialog.class);
    // 필드를 개별적으로 넘기지 말고 BusRouteMapItem를 Serializable로 만들어서 오브젝트를 통째로 넘김. 
    // 이래야 개별 필드를 빼먹는 실수도 방지하고 코드도 훨씬 읽기 편해짐.
    intent.putExtra(CustomDialog.EXTRA_ROUTE, route)
    startActivityForResult(intent, CustomDialog.REQUEST_ROUTE);
}
                   


public class CustomDialog ... {
    public static final String EXTRA_ROUTE = "Route";
    public static final int REQUEST_ROUTE = 1;


   @Override
   public void onCreate(Bundle savedInstance) [
         super.onCreaste(savedInstance);
         setContentView(...);

          // 앞에서 Serializable타입으로 넘겼으므로, 같은 타입으로 읽은 다음, 타입캐스팅.
         BusRouteMapItem givenRoute = (BusRouteMapItem) getIntent().getSerializableExtra(EXTRA_ROUTE);
         // 필요한 처리
   }
}

 

작성하신 코드를 눈에 띄는 부분만 수정을 해봤습니다. 어댑터는 아이템이 선택되었을 때의 동작에 대해 알 필요가 없습니다. 액티비티가 알아야 하죠. 따라서 아이템 클릭에 대한 처리는 인터페이스를 이용해 액티비티에서 하도록 만들어 주는 것이 좋습니다.

spark (227,530 포인트) 님이 2021년 10월 18일 답변
...