[안드로이드] 공공데이터 기차역 정보 조회 서비스 API 사용 [3]
- 공유 링크 만들기
- X
- 이메일
- 기타 앱
이번에 포스팅 할 내용은,
[1]에서 열차정보와 코드를 구성했던 .txt 파일을
Android에 올리고, ListView로 구성 및 'ㄱㄴㄷ'순으로 정렬 및 EditText이용한 초성검색 입니다.
[2]에서 구성하였던 화면,
[출발역 설정] 버튼과 [도착역 설정]버튼이 눌러졌을시 등장하는 Activity입니다
이를 구성하기 위해,
Manifest 수정을 해 둘 필요성이 있습니다.
<activity android:name=".StationListActivity" />
화면 전환 할 Activity 클래스를 추가해 주셔야 합니다.
함수 별로 나눠서 설명하겠습니다.
이것을 테스트 하려면, 아마 모바일 기기를 사용하셔야 될 것입니다.
AVD로는 안해봣지만, 안 될것 같긴 한데 잘은 모르겠네요 ㅎㅎ...
일단 준비사항으로는, 프로젝트에 들어가셔서 app -> src -> assets 폴더안에 InfoTrainStation.txt 파일과 InfoTrainStationCode.txt 를 만들어 주셔야 합니다. text파일 정보는 [1] 에 포스팅 해두었습니다.
assets 폴더가 없으시면 생성하시면 됩니다.
StationInfo.java
public class StationInfo implements Serializable{
String st_station;
String st_stationCode;
public StationInfo(String st_station, String st_stationCode) {
this.st_station = st_station;
this.st_stationCode = st_stationCode;
}
}
코드와 역을 저장할 Class
StationListActivity의 Layout
activity_station.xml
StationListActivity.java
public class StationListActivity extends AppCompatActivity {
EditText et_searchStation; // 초성검색을 위한 EditText
ListView lv_stationList; // Text-> App 올리기위한 LsitView
ArrayList mInfo; // ListView만들기 위한 ArrayList
AssetManager mag; // assets 폴더에서 올리기 위한 Manager
String name_buffer;
String code_buffer;
StationListAdapter mAdapter; // Adapter
Intent mResult; // 결과물 Return 할 Intent
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_station);
onInit();
ReadStation();
mAdapter = new StationListAdapter(this,android.R.layout.simple_list_item_1, mInfo);
lv_stationList.setAdapter(mAdapter);
}
public Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
switch (msg.what) {
case HandlerMessage.THREAD_HANDLER_SUCCESS_INFO:
mResult = getIntent();
StationInfo tResult = (StationInfo)msg.obj;
mResult.putExtra("stationInfo", tResult);
setResult(RESULT_OK,mResult);
finish();
break;
default:
break;
}
}
};
void onInit()
{
mag = this.getResources().getAssets(); // Assets 초기화
mInfo = new ArrayList<>();
et_searchStation = (EditText)findViewById(R.id.et_stationSearch);
et_searchStation.addTextChangedListener((new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) { // 초성검색을 위한 함수, L
String temp = et_searchStation.getText().toString();
mAdapter.Filter(temp); // 단어 입력시 Filter 함수에 접근,
}
@Override
public void afterTextChanged(Editable s) {
}
}));
lv_stationList = (ListView)findViewById(R.id.lv_stationList);
}
void ReadStation()
{
try {
InputStream name = mag.open("InfoTrainStation.txt");
InputStream code = mag.open("InfoTrainStationCode.txt");
int nameSize = name.available();
int codeSize = code.available();
byte[] buffer = new byte[nameSize];
byte[] buffer2 = new byte[codeSize];
name.read(buffer);
code.read(buffer2);
name.close();
code.close();
name_buffer = new String(buffer); // byte -> string 변환
code_buffer = new String(buffer2);
StringToToken(name_buffer,code_buffer); // 단어별로 쪼갬
}catch(IOException e) {
throw new RuntimeException(e);
}
}
void StringToToken(String name,String code)
{
StringTokenizer mToken = new StringTokenizer(name, "\r\n"); // Enter 기준으로 쪼갭니다.
StringTokenizer mToken2 = new StringTokenizer(code, "\r\n");
while(mToken.hasMoreTokens() )
{
String mName = mToken.nextToken();
String mCode = mToken2.nextToken();
StationInfo temp = new StationInfo(mName+"역",mCode); // 만들어진 것을 Class 화
mInfo.add(temp); // List추가
}
}
}
다음은 ListView를 사용할 Adapter입니다.
ListView의 아이템 layout으로는 다음과 같습니다.
trainitem1.xml
초성검색은 다음 사이트 http://www.androidpub.com/1473929 에서 참고를 하였습니다.
StationListAdapter
public class StationListAdapter extends ArrayAdapterimplements View.OnClickListener { private static final char HANGUL_BEGIN_UNICODE = 44032; // 가 private static final char HANGUL_LAST_UNICODE = 55203; // 힣 private static final char HANGUL_BASE_UNIT = 588;//각자음 마다 가지는 글자수 //자음 private static final char[] INITIAL_SOUND = { 'ㄱ', 'ㄲ', 'ㄴ', 'ㄷ', 'ㄸ', 'ㄹ', 'ㅁ', 'ㅂ', 'ㅃ', 'ㅅ', 'ㅆ', 'ㅇ', 'ㅈ', 'ㅉ', 'ㅊ', 'ㅋ', 'ㅌ', 'ㅍ', 'ㅎ' }; ArrayList mData; ArrayList mTemp; Context mContext; StationListActivity mStationActivity; public StationListAdapter(Context context, int resource, ArrayList objects) { super(context, resource, objects); mData = objects; // 데이터 받음 mStationActivity = (StationListActivity)context; mContext = context; Sort_String(); // ㄱㄴㄷ 순으로 데이터 정렬 mTemp = new ArrayList<>(); mTemp.addAll(mData); // 데이터 복사 } @Override public View getView(int position, View convertView, ViewGroup parent) { parent.invalidate(); View v = convertView; final int set = position; if (v == null) { LayoutInflater vi = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE); v = vi.inflate(R.layout.trainitem1, null); } v.setTag(position); v.setOnClickListener(this); if(mData.size() <= position) return v; // 혹시모를 오류 예외처리. final StationInfo p = mData.get(position); if (p != null) { TextView tv = (TextView) v.findViewById(R.id.tv_stationList); if (tv != null) { tv.setText(p.st_station); } } return v; } @Override public void onClick(View v) { // ListView에 클릭 발생시, 메세지 전달 Message msg = new Message(); int position = (int)v.getTag(); msg.obj = mData.get(position); msg.what = HandlerMessage.THREAD_HANDLER_SUCCESS_INFO; mStationActivity.handler.sendMessage(msg); } public void Filter(String data) { if(data.length() == 0) { mData.clear(); mData.addAll(mTemp); Sort_String(); return ; } mData.clear(); // 모두 삭제, for(StationInfo temp : mTemp) // mTemp에 복제해둔 데이터 하나씩 불러옴 { if(matchString(temp.st_station,data)) // 초성에 해당하면, 데이터를 더한다. mData.add(temp); } Sort_String(); // 데이터를 다시 정렬 notifyDataSetChanged(); // 변화 알림 } private boolean isInitialSound(char searchar){ for(char c:INITIAL_SOUND){ if(c == searchar){ return true; } } return false; } public boolean matchString(String value, String search){ int t = 0; int seof = value.length() - search.length(); int slen = search.length(); if(seof < 0) return false; //검색어가 더 길면 false를 리턴한다. for(int i = 0;i <= seof;i++){ t = 0; while(t < slen){ if(isInitialSound(search.charAt(t))==true && isHangul(value.charAt(i+t))){ //만약 현재 char이 초성이고 value가 한글이면 if(getInitialSound(value.charAt(i+t))==search.charAt(t)) //각각의 초성끼리 같은지 비교한다 t++; else break; } else { //char이 초성이 아니라면 if(value.charAt(i+t)==search.charAt(t)) //그냥 같은지 비교한다. t++; else break; } } if(t == slen) return true; //모두 일치한 결과를 찾으면 true를 리턴한다. } return false; //일치하는 것을 찾지 못했으면 false를 리턴한다. } private boolean isHangul(char c) { // 한글인지 체크, return HANGUL_BEGIN_UNICODE <= c && c <= HANGUL_LAST_UNICODE; } private char getInitialSound(char c) { // char 가 한글이라면, 초성을 찾는다. int hanBegin = (c - HANGUL_BEGIN_UNICODE); int index = hanBegin / HANGUL_BASE_UNIT; return INITIAL_SOUND[index]; } void Sort_String() // 한글, 영어 공통 적용됩니다. 영어라면 ABC순일테고, 한글이면 ㄱㄴㄷ 순입니다. comparator는 정확히 공부가 되지 않아, 참고를 하여 작성하였습니다. { final Comparator myComparator= new Comparator () { private final Collator collator = Collator.getInstance(); @Override public int compare(StationInfo object1,StationInfo object2) { return collator.compare(object1.st_station, object2.st_station); } }; // Collections.sort 로 comparator 를 주어서 데이터를 정렬 시킨다. Collections.sort(mData, myComparator); // 정렬시킵니다. } }
이런식으로 Adapter가 구성됩니다.
이를 통해 위의 화면에 접근할 수 있습니다.
다음은 MainActivity간 Intent 통신 결과 입니다.
MainActivity.java
@Override
public void onClick(View v) {
Intent intent;
switch(v.getId())
{
case R.id.btn_endStation:
intent = new Intent(this,StationListActivity.class);
startActivityForResult(intent,HandlerMessage.END_SET); // requstCode를 설정합니다.
break;
case R.id.btn_startStation:
intent = new Intent(this,StationListActivity.class);
startActivityForResult(intent,HandlerMessage.START_SET); // requstCode를 설정합니다.
break;
case R.id.btn_SearchTicket:
mRequest = new URLRequest(mStartStation,mEndStation,mThis);
mRequest.run();
dialog = ProgressDialog.show(this, "",
"Loading", true);
break;
}
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
switch(requestCode)
{
case HandlerMessage.START_SET: //StationListActivity 종료 시 Request Code로 구분합니다.
if(data != null)
mStartStation = (StationInfo)data.getSerializableExtra("stationInfo");
tv_startStationName.setText(mStartStation.st_station);
break;
case HandlerMessage.END_SET:
if(data !=null)
mEndStation = (StationInfo)data.getSerializableExtra("stationInfo");
tv_endStationName.setText(mEndStation.st_station);
break;
}
}
이것이 완료되면 다음과 결과화면을 얻을 수 있습니다.



이상 포스팅을 마치겠습니다.
전체 파일은 깃허브 사이트에 업로드 하였습니다.
주소는 https://github.com/warguss/TicketApiKorea 입니다.
추가로 읽으면 좋을 것
- 공유 링크 만들기
- X
- 이메일
- 기타 앱
댓글
이 블로그의 인기 게시물
[로스트아크] 제작 효율 최적화 위한 영지 세팅
1. 대성공 확률 증가 vs. 제작 수수료 절감 - 대성공 확률 증가 : 대성공 확률이 2% 증가해도 실제 효과는 크지 않습니다. 예를 들어, 기본 대성공 확률 5%에 2% 증가를 적용해도 실질적인 효과는 0.1% 증가에 불과합니다. - 제작 수수료 절감 : 제작 수수료를 2% 절감할 경우, 제작할 때마다 발생하는 골드 비용을 직접적으로 줄일 수 있어 비용 절약 효과가 훨씬 큽니다. - 결과적으로, 제작 수수료 절감이 대성공 확률 증가보다 약 10배 더 많은 이득을 제공합니다. 따라서 대성공 확률보다는 수수료 절감에 집중하는 것이 권장됩니다. 2. 효율적인 영지 세팅을 위한 이득 극대화 세팅 - 영지 내 필수 세팅 아이템으로 "곡예사의 대기실," "찬란한 소원 나무," "여신의 가호"가 추천됩니다. - 곡예사의 대기실 : 마리샵에서 블루 크리스탈로 구매할 수 있으며, 기본적인 제작 효율을 높이는 데 필수 아이템입니다. - 찬란한 소원 나무 : 수수료 절감을 제공하여 제작 비용을 절감하는 효과가 있어 이득 극대화에 도움이 됩니다. - 여신의 가호 : 미술품 42개를 모아 획득할 수 있으며, 추가적인 제작 효율을 제공합니다. 여유가 있다면 필수로 장착하는 것이 좋습니다. - 여신의 가호 대신, 곡예사의 무기 진열대 를 구매해 사용할 수도 있으며, 경제적인 선택지로 활용할 수 있습니다. 3. 의상 세팅 (선택적 적용) - 특정 의상을 착용하면 제작 효율이 약간 증가하지만, 최적의 의상 옵션은 없기 때문에 필수는 아닙니다. 크리스탈 비용이 부담스러울 경우 생략 가능하며, 다른 세팅을 우선적으로 강화하는 것이 좋습니다. - 드레스룸 이용 : 크리스탈을 사용하여 드레스룸에서 특정 NPC와의 호감도로 얻을 수 있는 의상을 구매할 수 있습니다. - 추천 의상 : 페일린, 실리안, 엘리제로나운 의상이 추천되며, 각각 350 크리스탈로 구매할 수 있습니다. - 비용 절약 방법 : 크리스탈이 부족하거나 가성비...
[로스트아크] 로스트아크 생활 도구 옵션
생활 도구 옵션 및 확률 | 옵션 | 고급 | 희귀 | 영웅 | 전설 | 유물 | |-------------------------|-------------|------------|-------------|-------------|-------------| | 기본 보상 추가 획득률 | 5~10% | 10~20% | 15~30% | 20~40% | 25~50% | | 희귀 재료 획득률 | 5~10% | 10~20% | 15~30% | 20~40% | 25~50% | | 특수 획득 확률 | 0.5~1% | 1~2% | 1.5~3% | 2~4% | 2.5~5% | | 내구도 미차감 확률 | 2.5~5% | 5~10% | 7.5~15% | 10~20% | 12.5~25% | | 채집속도 | 1.25~2.5% | 2.5~5% | 3.75~7.5% | 5~10% | 6.25~12.5% | | 미니게임 난이도 하락 | 1 | 1~2 | 1~2 | 2~3 | 2~3 | | 미니게임 보상 획득 확률 | 5~10% | 10~20% | 15~30% | 20~40% | 25~50% | | 낚시 캐스팅 등급 | 1~2 | 2~4 | 4~6 | 6~8 | 8~10 | 생활 키트 옵션 정리 - 영웅 등급 생활 도구가 제작 비용면에서 효율 좋음 | 생활 유형 | 필수 옵션 (빨간색) ...
작은 거인 심권호: 한국 레슬링의 전설과 그의 성공 전략
# 심권호 프로필 및 수상 경력 심권호 는 대한민국을 대표하는 레슬링 선수로, 작은 체구에도 불구하고 강력한 체력과 기술로 세계적인 성과를 거둔 인물입니다. 그는 두 체급에서 올림픽과 세계 선수권 대회를 제패하며 한국 레슬링 역사상 가장 성공적인 선수로 기록되었습니다. 주요 수상 경력 - 1992년 : 아시아 주니어 선수권 - 금메달 - 1993년 : 아시아 선수권 - 금메달 - 1994년 : 히로시마 아시안 게임 - 금메달 (48kg급) - 1995년 : 세계 선수권 (체코 프라하) - 금메달 (48kg급) - 1996년 : 애틀랜타 올림픽 - 금메달 (48kg급) - 1998년 : 방콕 아시안 게임 - 금메달 (54kg급) - 1999년 : 세계 선수권 (그리스) - 금메달 (54kg급) - 2000년 : 시드니 올림픽 - 금메달 (54kg급) 그랜드슬램 달성 - 1996년 : 애틀랜타 올림픽 금메달을 획득하며, 아시아 선수권, 아시안 게임, 세계 선수권, 올림픽 금메달로 레슬링 그랜드슬램 달성 훈련 및 주요 기술 훈련 방법 - 체력 훈련 : 매일 장시간 러닝과 인터벌 트레이닝을 통해 지구력 강화. - 근력 강화 : 체중 대비 높은 힘 발휘를 위해 하체와 상체 근력 훈련 집중. - 기술 연습 : 실전에서 사용하는 기술을 반복 연습해 정확성과 속도 향상. - 유연성 훈련 : 스트레칭과 요가로 유연성 강화, 부상 방지에 주력. 자주 사용한 기술 - 들어 던지기 : 상대방을 들어 던져 균형을 무너뜨리는 기술. - 굴리기 및 뒤집기 : 상대를 회전시키며 포지션을 바꾸는 기술. - 후크 및 잠금 기술 : 상대의 다리나 팔을 걸어 잠금으로 고정. 식단 관리 - 단백질 중심 식단 : 닭가슴살, 생선, 두부, 계란 등을 통해 근육 회복과 유지. - 저지방, 저탄수화물 식단 : 체중 조절을 위해 저지방 식단 유지. - 수분 조절 : 경기 전후 수분 조절로 체중 관리 및 경기력 유지. - 비타민과 미네랄 보충 : 과일과 야채를 통한 비타민 ...
도움이 많이 됐습니다 !
답글삭제감사합니다
도움이 되셧다니 다행입니다 ^^
답글삭제작성자가 댓글을 삭제했습니다.
답글삭제작성자가 댓글을 삭제했습니다.
답글삭제