Songnae
537
2021-02-02 23:09:11
3
238

안드로이드 쓰레드 사용이유 질문있습니다.


간단한 sns앱을 만들고 있습니다.프래그먼트에서 리싸이클러뷰를 사용하는데 어댑터랑 레이아웃매니저를 모두 지정했는데 CustomAdapter의 onCreateViewHolder메소드 자체가 실행이 되지 않습니다.오류가 뜨는건 아닌데 실행이 되지 않네요...

Skipped 34 frames!  The application may be doing too much work on its main thread. 이런 경고문구가 뜨는데 혹시 메인쓰레드에서 많은걸 실행해서 그런건지 해결방법이 궁금하네요...ㅠㅠㅠㅠ

코드는 아래와 같습니다.


package kr.co.hanbit.chatapp;

import android.content.Context;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import android.widget.Toast;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;

import com.google.firebase.database.DataSnapshot;
import com.google.firebase.database.DatabaseError;
import com.google.firebase.database.DatabaseReference;
import com.google.firebase.database.FirebaseDatabase;
import com.google.firebase.database.ValueEventListener;

import java.util.ArrayList;
import java.util.Map;
public class FragmentUsers extends Fragment {

    ArrayList<String> items;
    private DatabaseReference databaseReference;
    RecyclerView usersRecyclerView;
    UsersCustomAdapter customAdapter;
    Context context = getContext();
    LinearLayoutManager layoutManager;
    //int position = 0;


    //내비게이션에서 users누르면 onAttatch, onCreate, onCreateView 둘다 호출됨
    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        Log.d("FragmentUsers","onCreate() 호출");
        super.onCreate(savedInstanceState);
        databaseReference = FirebaseDatabase.getInstance().getReference();

    }

    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        Log.d("FragmentUsers", "View onCreateView() 실행");
        items = new ArrayList<>();//onDataChange가 데이터가 입력될때마다 콜백메소드로 작동되면 onCreate()로 옮겨도 될거같음...
        getUsersData();
        View view = inflater.inflate(R.layout.fragment_users, container, false);
        usersRecyclerView = (RecyclerView)view.findViewById(R.id.users_recyclerView);
        customAdapter = new UsersCustomAdapter(items, context);
        layoutManager = new LinearLayoutManager(getContext(), LinearLayoutManager.VERTICAL, false);
        usersRecyclerView.setLayoutManager(layoutManager);
        usersRecyclerView.setAdapter(customAdapter);
        //customAdapter.notifyDataSetChanged();
        //notifydataSetChange호출시 문제생김 아마도 쓰레드 사용해야될듯...
        return view;
        //return inflater.inflate(R.layout.fragment_users, container, false);
    }

    private void getUsersData() {//사용자 목록 정보를 디비에서 불러오는 함수
        databaseReference.child("ChatApp").child("LoginData").addValueEventListener(new ValueEventListener() {//데이터가 갱신될때마다 콜백호출
            @Override
            public void onDataChange(@NonNull DataSnapshot snapshot) {
                for(DataSnapshot dataSnapshot : snapshot.getChildren()){
                    items.add(dataSnapshot.getKey());
                    //Toast.makeText(getContext(), "데이터가 추가성공 " + items.get(position) , Toast.LENGTH_SHORT).show();
                    //position++;
                }
            }

            @Override
            public void onCancelled(@NonNull DatabaseError error) {
                Toast.makeText(getContext(), "데이터가 추가실패", Toast.LENGTH_SHORT).show();
            }
        });
    }


}
public class UsersCustomAdapter extends RecyclerView.Adapter<UsersCustomAdapter.ViewHolder> {

    ArrayList<String> items;
    FirebaseStorage firebaseStorage = FirebaseStorage.getInstance();
    Context context;

    public UsersCustomAdapter(ArrayList<String> items, Context context) {
        this.items = items;
        this.context = context;
        Log.d("UsersCustomAdapter", "UsersCustomAdapter(ArrayList<String> items, Context context)");
    }

    @NonNull
    @Override
    public UsersCustomAdapter.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        LayoutInflater inflater = LayoutInflater.from(parent.getContext());
        View itemView = inflater.inflate(R.layout.item_users, parent, false);
        Log.d("UsersCustomAdapter", "onCreateViewHolder호출");
        return new ViewHolder(itemView);
    }

    @Override
    public void onBindViewHolder(@NonNull UsersCustomAdapter.ViewHolder holder, int position) {
        StorageReference storageReference = firebaseStorage.getReference().child("usersProfiles/" + items.get(position));
        storageReference.getDownloadUrl().addOnCompleteListener(new OnCompleteListener<Uri>() {
            @Override
            public void onComplete(@NonNull Task<Uri> task) {
                if(task.isSuccessful()){
                    Log.d("UsersCustomAdapter", "task.isSuccessful()호출");
                    Glide.with(context).load(task.getResult()).into(holder.item_users_imageView);
                }else {
                    Toast.makeText(context, "이미지 로딩 실패", Toast.LENGTH_SHORT).show();
                }
            }
        });
        holder.item_users_textView.setText(""+items.get(position));
        Log.d("UsersCustomAdapter", "holder.item_users_textView.setText(items.get(position));");

        //notifyDataSetChanged();
    }

    @Override
    public int getItemCount() {
        return items.size();
    }

    public class ViewHolder extends RecyclerView.ViewHolder {
        ImageView item_users_imageView;
        TextView item_users_textView;
        public ViewHolder(@NonNull View itemView) {
            super(itemView);
            item_users_imageView = itemView.findViewById(R.id.item_users_imageView);
            item_users_textView = itemView.findViewById(R.id.item_users_textView);
        }
    }
}



0
  • 답변 3

  • p2c2kbf
    158
    2021-02-02 23:23:52 작성 2021-02-02 23:24:31 수정됨

    Firebase에서 사용자 목록을 가져오는 부분은 메인 쓰레드가 아닌 백그라운 쓰레드에서 처리되도록 비동기 처리가 필요합니다.  (handler/ rxjava 활용 가능합니다)


    그리고 데이터 가져오는 것과 관련된 로직은 adapter 클래스에서 처리하지 않도록 하는 것이 좋을 것 같습니다. context를 acitivity나 fragment의 외부 클래스에 넘겨주는 것은 안티 패턴입니다.

  • Songnae
    537
    2021-02-03 00:04:02

    답변감사합니다!!

    데이터를 가져오는 로직은 어떤거를 말씀하시는건가요?

    위의 CustomAdapter클래스에는 Stroage의이미지 불러오는것 밖에 없는데 혹시 그거를 말씀하시는건가요?

  • p2c2kbf
    158
    2021-02-03 21:56:39

    제가 자세한 코드 내용은 모르지만

    이미지 데이터 불러오는 부분이 한 부분 밖에 없다면, 그 부분이 맞을 것 같습니다.

  • 로그인을 하시면 답변을 등록할 수 있습니다.