프로그래밍/Android

안드로이드 아름다운 카드뷰(Card View) 리스트 만들기 - (2)

Lou Park 2016. 4. 5. 00:40

레이아웃을 만들기가 끝났으니, 이제는 데이터를 모아 Adapter로 연결하는 일만 남았다.

이 예제에서는 Fragment에서 RecyclerView를 불러올 것이기 때문에 Activity를 사용한다면 조금 수정할 부분이 있다.

- onCreateView() -> onCreate()

- getActivity() -> getApplicationContext() 또는 ~Activity.this 또는 this


그리고 이 예제에서는 공지사항을 불러오기 위한 카드뷰이므로

웹 DB에서 만들어진 데이터를 php를 이용해 JSON 객체로 만들어

불러오고, 안드로이드는 JSON을 읽어 ArrayList 형태로 데이터를 정리한다.

그리고 그 데이터를 카드뷰 하나 하나에 뿌려준다.

중간에 있는 DBhelper나 getData() 메소드는 그것을 위한 것이니 참고하도록!


NoticeFragment.java

public class NoticeFragment extends Fragment {
//DATA parsing 관련
String url = "http://pho901121.cafe24.com/login/db_get_notice_posts.php";
private static final String TAG_RESULTS="posts";
private static final String TAG_WRITER = "writer";
private static final String TAG_TITLE = "title";
private static final String TAG_DATE = "regist_day";
private static final String TAG_CONTENT = "content";
JSONArray posts = null;
ArrayList<HashMap<String,String>> noticeList;
DBhelper helper;
//UI 관련
private RecyclerView rv;
private LinearLayoutManager mLinearLayoutManager;

@Override
public View onCreateView(LayoutInflater inflater,ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_notice, container, false);
noticeList = new ArrayList<HashMap<String, String>>();
mLinearLayoutManager = new LinearLayoutManager(getActivity());
mLinearLayoutManager.setOrientation(LinearLayoutManager.VERTICAL);
rv = (RecyclerView) view.findViewById(R.id.rv);
rv.setHasFixedSize(true);
rv.setLayoutManager(mLinearLayoutManager);

//폰 내 db와 연결하여 uid 얻어와 보내기 - Fragment 이기 때문에 context가 getActivity()
helper = new DBhelper(getActivity(), "users2.db",null,DBhelper.DB_VER);
url += "?uid=" + helper.getId(getActivity());
Log.e("getuid: ", helper.getId(getActivity()));
getData(url);

return view;
}
/** JSON 파싱 메소드 **/
public void getData(String url) {
class GetDataJSON extends AsyncTask<String,Void,String> {
@Override
protected String doInBackground(String... params) {
//JSON 받아온다.
String uri = params[0];
BufferedReader br = null;
try {
URL url = new URL(uri);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
StringBuilder sb = new StringBuilder();

br = new BufferedReader(new InputStreamReader(conn.getInputStream()));

String json;
while((json = br.readLine()) != null) {
sb.append(json+"\n");
}
return sb.toString().trim();
}catch (Exception e) {
return null;
}
}
@Override
protected void onPostExecute(String myJSON) {
makeList(myJSON); //리스트를 보여줌
}
}
GetDataJSON g = new GetDataJSON();
g.execute(url);
}
/** JSON -> LIST 가공 메소드 **/
public void makeList(String myJSON) {
try {
JSONObject jsonObj = new JSONObject(myJSON);
posts = jsonObj.getJSONArray(TAG_RESULTS);
for(int i=0; i<posts.length(); i++) {
//JSON에서 각각의 요소를 뽑아옴
JSONObject c = posts.getJSONObject(i);
String title = c.getString(TAG_TITLE);
String writer = c.getString(TAG_WRITER);
String date = c.getString(TAG_DATE);
String content = c.getString(TAG_CONTENT);
if(content.length() > 50 ) {
content = content.substring(0,50) + "..."; //50자 자르고 ... 붙이기
}
if(title.length() > 16 ) {
title = title.substring(0,16) + "..."; //18자 자르고 ... 붙이기
}

//HashMap에 붙이기
HashMap<String,String> posts = new HashMap<String,String>();
posts.put(TAG_TITLE,title);
posts.put(TAG_WRITER,writer);
posts.put(TAG_DATE,date);
posts.put(TAG_CONTENT, content);

//ArrayList에 HashMap 붙이기
noticeList.add(posts);
}
//카드 리스트뷰 어댑터에 연결
NoticeAdapter adapter = new NoticeAdapter(getActivity(),noticeList);
Log.e("onCreate[noticeList]", "" + noticeList.size());
rv.setAdapter(adapter);
adapter.notifyDataSetChanged();

}catch(JSONException e) {
e.printStackTrace();
}
}
}

RecyclerView가 있는 xml을 보여줄 Activity 또는 Fragment 코드다.

여기서 주의 깊게 볼 부분은 LinearLayoutManager이다.

LinearLayoutManager를 사용해 주지 않을 경우 레이아웃 매니저가 없다는 에러 메세지가 뜬다.

예제에서는 ArrayList<HashMap<String,String>>를 이용했는데, 각자 사용처에 맞게 적절한 타입으로 데이터를 Adapter에 넘겨주면 된다.

다음으로는 Adapter를 만들어보겠다.


NoticeAdapter.java

public class NoticeAdapter extends RecyclerView.Adapter<NoticeAdapter.ViewHolder> {
Context context;
ArrayList<HashMap<String,String>> noticeList; //공지사항 정보 담겨있음

public NoticeAdapter(Context context, ArrayList<HashMap<String,String>> noticeList) {
this.context = context;
this.noticeList = noticeList;
}

@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
//recycler view에 반복될 아이템 레이아웃 연결
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_notice,null);
return new ViewHolder(v);
}
@TargetApi(Build.VERSION_CODES.JELLY_BEAN)
/** 정보 및 이벤트 처리는 이 메소드에서 구현 **/
@Override
public void onBindViewHolder(final ViewHolder holder, int position) {
HashMap<String,String> noticeItem = noticeList.get(position);
holder.tv_writer.setText(noticeItem.get("writer")); //작성자
Log.e("[writer]", noticeItem.get("writer"));
holder.tv_title.setText(noticeItem.get("title")); //제목
holder.tv_content.setText(noticeItem.get("content")); //내용 일부
holder.tv_date.setText(noticeItem.get("regist_day")); //작성일
}

@Override
public int getItemCount() {
return this.noticeList.size();
}
/** item layout 불러오기 **/
public class ViewHolder extends RecyclerView.ViewHolder {
TextView tv_title;
TextView tv_date;
TextView tv_content;
TextView tv_writer;
CardView cv;

public ViewHolder(View v) {
super(v);
tv_title = (TextView) v.findViewById(R.id.tv_title);
tv_date = (TextView) v.findViewById(R.id.tv_date);
tv_content = (TextView) v.findViewById(R.id.tv_content);
tv_writer = (TextView) v.findViewById(R.id.tv_writer);
cv = (CardView) v.findViewById(R.id.cv);
}
}
}

Adapter를 생성할 때 데이터를 담은 ArrayList<...>를 인자로 받아서 

onBindViewHolder()에서 하나하나를 처리한다.

카드 하나를 클릭했을 때 발동하는 onClickListener의 경우도 저기서 처리해주면 된다. onClickListener는 다음 강의에서도 자세히 다룰 것이다.

ViewHolder 클래스에서는 사용할 UI Element를 초기화 시켜준다.

Adapter를 처리할 때 중요한게 또 하나 있는데, 바로 @TargetApi(Build.VERSION_CODES.JELLY_BEAN)이다.

이 코드를 적어주지 않으면 카드뷰가 보이지 않는다. 이유는 모르겠지만...ㅠㅠ


어쨌건, 이렇게 하면 이제 카드뷰가 쫙 뿌려질 것이다.

다음 강의는 이미지 불러오기,클릭 이벤트 등을 구현해 보도록 할 것이다.