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

파싱한 데이터를 recyclerview에 넣고, recyclerview안의 textcolor 바꾸는 방법에 대해 여쭙고 싶습니다

0 추천

안녕하세요, 이번에 졸업작품으로 버스 어플을 만들게 된 학생입니다.

버스 어플을 구현하는 중에 문제가 생겨서 혹시 실례가 아니라면 여쭈어봐도 될까요? 

 

(왼) 카카오버스의 화면, (좌) 만들고 있는 화면

 

현재 1. 특정 버스를 클릭하면 다음 엑티비티로 넘어가서 2. 그 버스가 지나다는 정류장의 목록과

3. 현재 돌아다니고 있는 버스들이 지나가고 있는 정류장은 글자색을 빨간색으로 변경하려고 합니다. 

그런데 계속 버스가 없는 곳에도 빨간색이 칠해지고, 심지어 스크롤을 올렸다 내리면 (새로고침 기능은 구현하지 않았습니다...) 방금전까지 빨간색이 아니었던 정류장까지 빨간색이 되었습니다. 혹시 어떻게 해야 할지 여쭤볼 수 있을까요?  

 

제가 생각했던 방법은 이러합니다.

1. 이전의 창(버스 선택창)에서 넘어올때 선택한 버스의 routeId(버스 번호 식별하는 변수) 를 intent로 넘겨줍니다.

2. 우선 routeId를 사용하여 해당 번호에 해당하는 버스들의 현재 지나가고 있는 정류장 정보을 api로 받아옵니다. 그리고 tracker_list에 저장합니다.

3. 그 다음에 routeId를 사용하여 routeid(특정 버스)가 지나가는 모든 정류장 목록을 받아옵니다. 그리고 list에 저장합니다. 

4. 2와 3에서는 공통적으로 정류장 식별변수 stationid가 나옵니다. 그래서 tracker_list가 가지고 있는 stationid와 list가 가지고 있는 stationid가 동일하면 list의 변수중 하나인 tracker을 1로 바꿔줍니다.

 4-1) tracker= 해당 정류장을 지나고 있는 버스가 있음을 알려주기 위한 변수

5. 후에 adpter에 list를 넘겨주는데, tracker의 값이 1일때 텍스트의 색을 바꿔줍니다.

 

 

class station_after {  //노선이 가지고 있는 정류장을 모두 출력하기 위해 만든 클래스
    String stationId; //정류소 아이디
    String mobileNo; //정류소 번호
    String stationName;
    int tracker;


    public String getStationId() { return stationId; }
    public String getMobileNo() { return mobileNo; }
    public String getStationName() { return stationName; }

    public int getTracker() { return tracker; }


    public void setStationId(String stationId) { this.stationId = stationId; }
    public void setStationName(String stationName) { this.stationName = stationName; }
    public void setMobileNo(String mobileNo) { this.mobileNo = mobileNo; }

    public void setTracker(int tracker) {this.tracker = tracker; }
}

class station_tracker { //이 클래스의 용도에 대한 자세한 설명은 Station_After_Number의 MySyncTask3 class 바로 위에 작성해두었다.
    String stationId;

    public String getStaionId() { return stationId;}

    public void setStationId(String stationId) {this.stationId= stationId;}
}


public class AdapterSAN extends RecyclerView.Adapter<AdapterSAN.MyViewHolder> {

    private ArrayList<station_after> mList;
    private LayoutInflater mInflate;
    private Context mContext;

    public AdapterSAN(Context context, ArrayList<station_after> itmes) {
        this.mList = itmes;
        this.mInflate = LayoutInflater.from(context);
        this.mContext = context;
    }


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

    @Override
    //뷰에 값이 채워질 3개를 여기서 하는 것
    public void onBindViewHolder(@NonNull MyViewHolder holder, final int position) {

          holder.tv_stationName.setText(mList.get(position).stationName);

          if(mList.get(position).tracker==1) { //tracker가 1인 애만 색을 바꾼다
              holder.tv_stationName.setTextColor(Color.rgb(255, 69, 19));
          }

        //Click event
    }

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

    //ViewHolder
    public static class MyViewHolder extends RecyclerView.ViewHolder {
        public TextView tv_stationName;
        public ImageView tv_buspointer;


        public MyViewHolder(View itemView) {
            super(itemView);

            tv_stationName = itemView.findViewById(R.id.tv_stationname2);
            tv_buspointer = itemView.findViewById(R.id.tv_image);

        }
    }

}

recyclerview에 쓰이는 AdapterSAN.java와 station_tracker(현재 지나가는 정류소를 위한 class) 와 station_number(특정 버스가 지나가는 모든 정류소의 정보를 위한 class)

 

public class Station_After_Number extends AppCompatActivity {

    final String TAG = "Station_After_Number";
    public String dataKey = "vgOxwLDnBL1K%2B0EV%2FG7Yi%2Bge%2BwfXMB66UwEnnmJEUuoej7Zg75Z85lE7wOcYZcysMUq5Sa2VGKzNsczJqzgg9A%3D%3D";
    private String requestUrl;
    private String requestUrl2;

    ArrayList<station_after> list = null;
    ArrayList<station_tracker> tracker_list = null;

    station_tracker tracker = null; //ArrayList인 tracker_list에 값을 집어넣어줄 tracker 객체
    station_after bus = null;
    RecyclerView recyclerView;
    String routeId;



    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.station_after_number);


        Intent intent = getIntent();
        routeId = intent.getStringExtra("RouteId");

        recyclerView = (RecyclerView) findViewById(R.id.recycler_viewSAN);
        recyclerView.setHasFixedSize(true);

        LinearLayoutManager layoutManager = new LinearLayoutManager(this);
        layoutManager.setOrientation(LinearLayoutManager.VERTICAL);
        recyclerView.setLayoutManager(layoutManager);

        MyAsyncTask3 myAsyncTask = new MyAsyncTask3();
        myAsyncTask.execute();

    }

    

    public class MyAsyncTask3 extends AsyncTask<String, Void, String> {


        @Override
        protected String doInBackground(String... strings) {

          

            //첫번째 데이터를 버스 위치 정보 조회 api로 받은 다음에 두번째 정보를 받으러 감
        

for(int i=0; i<tracker_list.size(); i++) {
    station_tracker sub = tracker_list.get(i);
    String sub_string = sub.getStaionId();

    for(int j=0; j<list.size(); j++){
        station_after sub2 = list.get(j);
        String sub_string2 = sub2.getStationId();
        if(sub_string2.equals(sub_string)) {
            sub2.setTracker(1); 
list.set(j, sub2);
        }
    }
}

            return null;
        }

        //   @Override
        protected void onPostExecute(String s) {
            super.onPostExecute(s);




            //어답터 연결
            AdapterSAN adapter = new AdapterSAN(getApplicationContext(), list);
            recyclerView.setAdapter(adapter);
        }
    

}

 

두개의 api를 파싱하여 각각의 Arraylist에 넣고, stationid가 동일할때 trakcer의 값을 1로 바꿔줌 

--글자수 제한 떄문에 파싱 부분은 생략하였습니다. 각각 개별적으로  api를 사용했을 때 정상적으로 값을 가져옵니다

 

 

익명사용자 님이 2019년 5월 19일 질문

1개의 답변

0 추천

recyclerview 의 특징을 생각해보셔야 합니다.

기본적으로 리사이클러뷰는 뷰를 재사용합니다.

 

따라서, 질문자님이 onBind 쪽에 case 에 따라 텍스트를 빨간색으로 만들었다면, 

케이스에 해당하지 않는 아이들은 원래색으로 설정해주는 분기처리가 필요합니다.

 

@Override
    //뷰에 값이 채워질 3개를 여기서 하는 것
    public void onBindViewHolder(@NonNull MyViewHolder holder, final int position) {
 
          holder.tv_stationName.setText(mList.get(position).stationName);
 
          if(mList.get(position).tracker==1) { //tracker가 1인 애만 색을 바꾼다
              holder.tv_stationName.setTextColor(Color.rgb(255, 69, 19));
          } else {
              // 이부분
}
 
        //Click event
    }

 

빨간색으로 설정했던 뷰가 스크롤을 밑으로 내려서 다시 재사용 될경우, 

질문자님의  tracker == 1 조건에 걸리지 않고, 텍스트뷰의 색상을 따로 설정하는 코드가 없기 때문에,

재사용되었을때의 색상을 그대로 이용합니다.

이해를 돕기위해 간단한 설명을 첨부하자면..

---------

리스트1

---------

리스트2

---------

리스트3

---------

처음에는 이런식으로 화면에 리스트를 보여주고 있다가, 스크롤을 아래로 내리면 

 

---------

리스트2

---------

리스트3

---------

리스트4 (리스트1의 재사용)

---------

 

리스트 1이 사라지고 리스트 4가 생길거예요.

이때, 리스트1의 뷰는 리사이클러뷰의 캐시스택에 들어가고,

스크롤이 움직여서 리스트4를 그릴때, 

리사이클러뷰가 자체적으로 판단해서 캐시에 재사용할수 있는 뷰가 있으면, 그걸 가져와서 onBind 부터 다시 그립니다.

물론, 뷰타입이나, 여러 플래그에 따라 다르게 움직이지만, 기본적으로 리사이클러뷰는 위와같은 방식으로 구현됩니다.

안드로이드로우 (15,740 포인트) 님이 2019년 5월 20일 답변
...