준비
android studio 1.4 이상 (1.3은 안됨)
환경설정 – Appearance & Behavior – System Setting – Updates – Automatically check updates for 를 Beta Channel로 선택하면 베타로 업데이트 할 수 있다.
build.gradle 변경
top level build.gradle을 아래와 같이 수정한다.
buildscript { repositories { jcenter() } dependencies { classpath 'com.android.tools.build:gradle:1.3.1' // add classpath "com.android.databinding:dataBinder:1.+" // add } }
app/build.gradle은 이렇게 변경한다.
apply plugin: 'com.android.application' apply plugin: 'com.android.databinding' // add android { buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } packagingOptions { // add exclude 'META-INF/LICENSE' exclude 'META-INF/NOTICE' } } dependencies { compile fileTree(dir: 'libs', include: ['*.jar']) testCompile 'junit:junit:4.12' compile 'com.android.support:appcompat-v7:23.0.1' compile 'com.android.support:design:23.0.1' compile 'com.navercorp.volleyextensions:volleyer:2.0.+' // add compile 'com.mcxiaoke.volley:library:1.0.+' // add compile 'com.fasterxml.jackson.core:jackson-databind:2.6.+' // add }
예제 데이터 준비
서울 열린 데이터 광장의 중랑여성인력개발 교육강좌의 샘플 url을 사용한다.
http://openapi.seoul.go.kr:8088/sample/json/SeoulJungNangWomenResourcesClass/1/5/
{ "SeoulJungNangWomenResourcesClass": { "list_total_count":71, "RESULT": { "CODE":"INFO-000", "MESSAGE":"정상 처리되었습니다" }, "row":[ { "CLASS_CODE":"C100067424", "CLASS_NAME":"요양보호사1급_간호(조무)사_10월", "ORGAN_CODE":"25", "ORGAN_NAME":"중랑여성인력개발센터", "DIFFICULTY":"N", "DIFFICULTY_NAME":"관계없음", "RECEIVE_FROM":"20141201", "RECEIVE_TO":"20150929", "RECEIVE_TIME_FROM":"09:00", "RECEIVE_TIME_TO":"18:00", "EDUCATE_FROM":"20151001", "EDUCATE_TO":"20151218", "EDUCATE_TIME_FROM":"09:30", "EDUCATE_TIME_TO":"13:20", "MONDAY":"Y", "TUESDAY":"Y", "WEDNESDAY":"Y", "THURSDAY":"Y", "FRIDAY":"Y", "SATURDAY":"", "SUNDAY":"", "COLLECT_NUM":30.0, "SPARE_NUM":0.0, "EDUCATE_FEE":250000.0, "VISIT_RECEIVE_FLAG":"Y", "ONLINE_RECEIVE_FLAG":"Y", "URL":"http://jungnang.seoulwomen.or.kr/edu/edu_info_view_01.jsp?course_code=07&class_code=C100067424" } ] } }
Jackson을 위한 Item Class 추가
굳이 필요없어 보이는 SeoulJungNangWomenResourcesClass 때문에 클래스를 하나 더 만들어야 하는게 맘에 안든다 -_-
import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; @JsonIgnoreProperties(ignoreUnknown = true) public class ParentResourceClassItem { @JsonProperty("SeoulJungNangWomenResourcesClass") public ResourceClassItem resourceClassItem; }
import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; import java.util.ArrayList; @JsonIgnoreProperties(ignoreUnknown = true) public class ResourceClassItem { @JsonProperty("list_total_count") public int totalCount; @JsonProperty("RESULT") public ResultItem result; @JsonProperty("row") public ArrayList<RowItem> rows; }
import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; @JsonIgnoreProperties(ignoreUnknown = true) public class ResultItem { @JsonProperty("CODE") public String code; @JsonProperty("MESSAGE") public String message; }
@JsonIgnoreProperties(ignoreUnknown = true) public class RowItem { @JsonProperty("CLASS_CODE") public String classCode; @JsonProperty("CLASS_NAME") public String className; @JsonProperty("ORGAN_CODE") public String organCode; @JsonProperty("ORGAN_NAME") public String organName; @JsonProperty("DIFFICULTY") public String difficulty; @JsonProperty("DIFFICULTY_NAME") public String difficultyName; @JsonProperty("RECEIVE_FROM") public String receiveFrom; @JsonProperty("RECEIVE_TO") public String receiveTo; @JsonProperty("RECEIVE_TIME_FROM") public String receiveTimeFrom; @JsonProperty("RECEIVE_TIME_TO") public String receiveTimeTo; @JsonProperty("EDUCATE_FROM") public String educateFrom; @JsonProperty("EDUCATE_TO") public String educateTo; @JsonProperty("EDUCATE_TIME_FROM") public String educateTimeFrom; @JsonProperty("EDUCATE_TIME_TO") public String educateTimeTo; @JsonProperty("MONDAY") public String monday; @JsonProperty("TUESDAY") public String tuesday; @JsonProperty("WEDNESDAY") public String wednesday; @JsonProperty("THURSDAY") public String thursday; @JsonProperty("FRIDAY") public String friday; @JsonProperty("SATURDAY") public String saturday; @JsonProperty("SUNDAY") public String sunday; @JsonProperty("COLLECT_NUM") public String collectNum; @JsonProperty("SPARE_NUM") public String spareNum; @JsonProperty("EDUCATE_FEE") public String educateFee; @JsonProperty("VISIT_RECEIVE_FLAG") public String visitReceiveFlag; @JsonProperty("ONLINE_RECEIVE_FLAG") public String onlineReceiveFlag; @JsonProperty("URL") public String url; public String displayReceiveFrom() { return parseDate(receiveFrom, "yyyyMMdd"); } public String displayReceiveTo() { return parseDate(receiveTo, "yyyyMMdd"); } private String parseDate(String dateStr, String pattern) { String result = dateStr; try { SimpleDateFormat formatter = new SimpleDateFormat(pattern); Date date = formatter.parse(dateStr); result = format(date.getTime(), "yyyy.MM.dd"); } catch (Exception e) { e.printStackTrace(); } return result; } private String format(long timeInMills, String pattern) { SimpleDateFormat formatter = new SimpleDateFormat(pattern); return formatter.format(timeInMills); } }
row item layout 추가
리스트 뷰의 row에 사용할 list item을 만든다
<?xml version="1.0" encoding="utf-8"?> <layout xmlns:android="http://schemas.android.com/apk/res/android"> <data> <variable name="row" type="kr.susemi99.databindingsample.items.RowItem"/> </data> <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:paddingBottom="5dp" android:paddingLeft="10dp" android:paddingRight="10dp" android:paddingTop="5dp"> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:background="#E5D1D1FF" android:orientation="horizontal" android:paddingLeft="3dp"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text='@{"["+row.difficultyName+"] "}' android:textAppearance="?android:attr/textAppearanceSmall"/> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="@{row.className}" android:textAppearance="?android:attr/textAppearanceMedium"/> </LinearLayout> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="신청기간 : "/> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text='@{row.displayReceiveFrom() +" "+ row.receiveTimeFrom +" ~ "+ row.displayReceiveTo() +" "+row.receiveTimeTo}'/> </LinearLayout> </LinearLayout> </layout>
ListView Adapter 추가
리스트 뷰에서 사용할 어댑터를 만든다.
데이터 바인딩을 이용하면 getView()의 코드가 많이 줄어든다.
public class ClassListAdapter extends BaseAdapter { private ArrayList<RowItem> items = new ArrayList<>(); public void add(RowItem item) { items.add(item); } public void clear() { items.clear(); } @Override public int getCount() { return items.size(); } @Override public Object getItem(int position) { return items.get(position); } @Override public long getItemId(int position) { return position; } @Override public View getView(int position, View convertView, ViewGroup parent) { ListItemClassBinding binding = ListItemClassBinding.inflate(LayoutInflater.from(parent.getContext()), parent, false); binding.setRow(items.get(position)); return binding.getRoot(); } }
volleyer 추가
기본 설정은 http://susemi99.kr/3089 를 참고하면 된다.
이제 호출만 해주면 자동으로 리스트 뷰에 표시가 된다.
private void load() { adapter.clear(); adapter.notifyDataSetChanged(); String url = "http://openapi.seoul.go.kr:8088/sample/json/SeoulJungNangWomenResourcesClass/1/5/"; Volleyer.volleyer().get(url) .withTargetClass(ParentResourceClassItem.class) .withListener(listener) .withErrorListener(errorListener) .execute(); } ///////////////////////////////////// // listener //////////////////////////////////// private Response.Listener<ParentResourceClassItem> listener = new Response.Listener<ParentResourceClassItem>() { @Override public void onResponse(ParentResourceClassItem item) { Log.i("MainActivity | onResponse", "|" + item.resourceClassItem.result.code + "|" + item.resourceClassItem.result.message + "|"); if(!item.resourceClassItem.result.code.equals("INFO-000")) return; for (RowItem row : item.resourceClassItem.rows) { adapter.add(row); } adapter.notifyDataSetChanged(); } }; private Response.ErrorListener errorListener = new Response.ErrorListener() { @Override public void onErrorResponse(VolleyError error) { Log.i("MainActivity | onErrorResponse", "|" + error.getLocalizedMessage() + "|"); } };
소스는 https://github.com/susemi99/DataBinding-with-Volleyer-sample 에 있다.