[android] data binding sample with Volleyer + Jackson

준비

android studio 1.4 이상 (1.3은 안됨)

환경설정 – Appearance & Behavior – System Setting – Updates – Automatically check updates for 를 Beta Channel로 선택하면 베타로 업데이트 할 수 있다.

 

screenshot

 

 

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() + "|");
    }
  };

 

 

th_device-2015-09-25-185638

 

 

소스는 https://github.com/susemi99/DataBinding-with-Volleyer-sample 에 있다.