addValueEventListener 콜백에 대해서 이해를 하실 필요가 있습니다. 콜백은 Asynchronous(비동기)로 동작합니다. 따라서 addValueEventListener 밖에 있는 코드는 addValueEventListener 내부와 동기화가 되지 않습니다. 님의 경우는 2번 주석 부분이 먼저 실해이 된 후 Firebase에서 데이터가 도착하면 addValueEventListener.onDataChange이 실행되기 때문에 그렇습니다.
따라서 "저 블럭을 빠져 나오는 순간 제가 groupId를 담아놓은 ArrayList는 작업했던 내용이 날아갑니다" 이 말은 정확하지 않고, 사실은 파이어베이스에서 데이터를 받으면 제대로 초기화를 하고 있지만, 이걸 사용하고 있지 않는 것 뿐이죠.
따라서 주석 2는 지우시고요, 파이어베이스에서 받은 데이터 확인은 addValueEventListener 내에서만 하세요. 그리고 코드를 좀 더 가독성이 생기도록 살짝 수정하면,
public class ParticipatingGroupRepository implments ValueEventListener {
interface Listener {
void onSuccess(List<GroupId> groupIdList);
void onCancel(DatabaseError error);
}
private static final USERS_PATH = "users"
private static final PARTICIPATING_GROUPS_PATH = "participatingGroups"
private final DatabaseReference dbRef = FirebaseDatabase.getInstance().getReference();
@Nullable
private Listener listener;
private ParticipatingGroupRepository() {
initParticipatingGroups();
}
private void initParticipatingGroups(){
dbRef.child(USERS_PATH)
.child(getCurrentUser().getUid())
.child(PARTICIPATING_GROUPS_PATH)
.addValueEventListener(this);
}
public void setListener(@Nullable Listener listener) {
this.lisetner = listener;
}
private FirebaseUser getCurrentUser() {
return FirebaseAuth.getInstance().getCurrentUser();
}
@Override
public void onDataChange(@NonNull DataSnapshot snapshot) {
handleSuccess(snapshot);
}
@Override
public void onCancelled(@NonNull DatabaseError error) {
if (lisetner == null) return;
listener.onCancel(error);
}
private void handleSuccess(DataSnapshot snapshot) {
List<GroupId> groupIdList = new ArrayList<GroupId>();
for(DataSnapshot dataSnapshot : snapshot.getChildren()){
GroupId groupId = dataSnapshot.getValue(GroupId.class);
if(groupId!=null) {
groupIdList.add(groupId);
}
}
if (lisetner == null) return;
listener.onSuccess(groupIdList)
}
}
public class ParticipantsRecyclerViewAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private final List<GroupId> groupIdList = new ArrayList<>();
public void submitList(List<GroupId> groupIdList) {
this.groupIdList.clear();
this.groupIdList.addAll(groupIdList);
notifyDataSetChanged();
}
...
}
public class MainActivity extends AppCompatActivity implements ParticipatingGroupRepository.Listener {
private ParticipatingGroupRepository participatingGroupRepository;
private ParticipantsRecyclerViewAdapter participantsRecyclerViewAdapter;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
participatingGroupRepository = new ParticipatingGroupRepository();
setupViews();
}
private void setupView() {
participantsRecyclerViewAdapter = new ParticipantsRecyclerViewAdapter();
}
@Override
public void onShow() {
super.onShow();
participatingGroupRepository.setListener(this);
}
public void onStop() {
super.onStop();
participatingGroupRepository.setListener(null);
}
@Override
public void onSuccess(List<GroupId> groupIdList) {
participantsRecyclerViewAdapter.submitList(groupIdList);
}
@Override
public void onCancel(DatabaseError error) {
// 에러처리
}
}
RecyclerViewAdpater나 액티비티 같은 View는 네트워크로 데이터를 가져오거나 하는 로직이 있으면 좋지 않습니다. 해당 코드는 분리를 해야 추후에 테스트도 쉽고 수정하기도 쉬워집니다. 이건 특별한 부분도 아니고 뷰와 뷰와 관련이 없는 로직을 분리하는 것은 앱개발에서 기본적이 부분에 해당합니다.