공공데이터(data.go.kr)에서 전주시내버스 승강장 정보 가져오기
- http://www.data.go.kr 에 가입
- [전라북도 전주시_승강장 정보 서비스] 활용 신청 -> 신청 1일 후부터 사용 가능, 일반 인증키 번호 받음
- 참고문서(IROS_SS_ID_DV_0501_OpenAPI활용가이드_전주시버스정보시스템_승강장정보서비스__v1.2)를 참조하여 프로그래밍
- 승강장정보 검색 결과 : 승강장명으로 검색
- MyConst.java 에 일반 인증키 번호 추가
123public class MyConst {public static final String DATA_POST_KEY = "data.go.kr에 받은 인증키 번호";} - Traffic 허용해주기 위해 /res/xml/network_security_config.xml 파일 생성
123456<?xml version="1.0" encoding="utf-8"?><network-security-config><domain-config cleartextTrafficPermitted="true"><domain includeSubdomains="true">openapi.jeonju.go.kr</domain></domain-config></network-security-config> - AndroidManifest.xml 에 위 xml 파일 등록
- AdnroidManifest.xml 에 인터넷 사용 가능하도록 추가
123456789101112131415161718192021222324252627<?xml version="1.0" encoding="utf-8"?><manifest xmlns:android="http://schemas.android.com/apk/res/android"package="kr.co.moak.proj001address"><uses-permission android:name="android.permission.INTERNET"/><uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/><applicationandroid:allowBackup="true"android:icon="@mipmap/ic_launcher"android:label="@string/app_name"android:roundIcon="@mipmap/ic_launcher_round"android:supportsRtl="true"android:theme="@style/AppTheme"><activityandroid:name=".MainActivity"android:label="@string/app_name"android:theme="@style/AppTheme.NoActionBar"><intent-filter><action android:name="android.intent.action.MAIN" /><category android:name="android.intent.category.LAUNCHER" /></intent-filter></activity></application></manifest> - /layout/activity_main.xml 수정
123456789101112131415161718192021222324252627<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"xmlns:tools="http://schemas.android.com/tools"android:orientation="vertical"android:layout_width="match_parent"android:layout_height="match_parent"tools:context=".MainActivity"><Buttonandroid:id="@+id/b1"android:layout_width="match_parent"android:layout_height="wrap_content"android:text="+" /><Buttonandroid:id="@+id/b2"android:layout_width="match_parent"android:layout_height="wrap_content"android:text="-" /><ListViewandroid:id="@+id/lstView"android:layout_width="match_parent"android:layout_height="match_parent"/></LinearLayout> - MainActivity 클래스 수정 1 : AsyncTask 클래스 사용하여 인터넷에서 자료 다운로드
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495package kr.co.moak.aithird;import androidx.appcompat.app.AppCompatActivity;import android.content.Context;import android.content.Intent;import android.os.AsyncTask;import android.os.Bundle;import android.util.Log;import android.view.View;import android.widget.Button;import android.widget.EditText;import android.widget.TextView;import org.w3c.dom.Document;import org.w3c.dom.NodeList;import org.xml.sax.InputSource;import java.net.URL;import javax.xml.parsers.DocumentBuilder;import javax.xml.parsers.DocumentBuilderFactory;public class MainActivity extends AppCompatActivity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);Button b1 = (Button)this.findViewById(R.id.b1);b1.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View view) {String apiKey = MyConst.API_KEY;String searchFld = "stopnm";String searchNm = "전주대";// 승강장명 목록 조회String url = "http://openapi.jeonju.go.kr/jeonjubus/openApi/traffic/bus_location2_stopnm_common.do"+ "?ServiceKey=" + apiKey + "&searchFld=stopnm&searchNm=" + searchNm;new MyAsyncTask(getBaseContext()).execute(url);}});}class MyAsyncTask extends AsyncTask<String, Integer, Document>{private Context m_context;public MyAsyncTask(Context context){this.m_context = context;}@Overrideprotected void onPreExecute() {super.onPreExecute();}@Overrideprotected Document doInBackground(String... urls) {URL url;Document doc = null;try{url = new URL(urls[0]);DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();DocumentBuilder db = dbf.newDocumentBuilder();doc = db.parse(new InputSource(url.openStream()));doc.getDocumentElement().normalize();}catch (Exception e){Log.v("MYTAG", "Parsing Error");}Log.v("MYTAG", urls[0]);return doc;}@Overrideprotected void onPostExecute(Document doc) {NodeList nodeList = doc.getElementsByTagName("list");Log.v("MYTAG", "cnt: " + nodeList.getLength());for(int i = 0; i<nodeList.getLength(); i++) {NodeList childList = nodeList.item(i).getChildNodes();for(int j=0; j<childList.getLength(); j++){Log.v("MYTAG", childList.item(j).getNodeName() + " "+ childList.item(j).getTextContent());}}//super.onPostExecute(document);}}}- <String, Integer, Document> : Document doInBackground(String)
- 첫번째 String : doInBackground()에서 받는 매개변수 타입
- 두번째 Integer : onProgressUpdate()에서 사용할 변수 타입
- 세번째 Document : doInBackground()의 리턴 타입
- onPreExecute() : 백그라운드 작업을 수행하기 전에 호출
- onProgressUpdate() :
- 백그라운드 작업의 진행 상태를 표시하기 위해 호출
- 작업 수행 중간 중간에 UI 객체에 접근하는 경우에 사용
- 작업 중간에 publishProgress()를 호출하면 실행 됨
- doInBackground() :
- 새로 만든 스레드에서 백그라운드 작업을 수행
- excute(인수1, 인수2,…)의 인수들을 배열로 전달받음
- new MyAsyncTask(getContext()).execute(url);
- strUrl을 urls[0]로 받음
- onPostExecute()
- 백그라운드 작업이 끝난 후 호출
- 메인 스레드에서 실행되며 전송받은 내용을 레이아웃에 나타내거나 DB에 저장 등의 작업을 수행
- <String, Integer, Document> : Document doInBackground(String)
- /layout/stop_list_item.xml 파일 생성
1234567891011121314151617181920212223242526272829303132<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:orientation="vertical" android:layout_width="match_parent"android:layout_height="match_parent"><TextViewandroid:id="@+id/stopkname"android:layout_width="match_parent"android:layout_height="wrap_content"android:text="TextView" /><LinearLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"android:orientation="horizontal"><TextViewandroid:id="@+id/stopx"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_weight="1"android:text="TextView" /><TextViewandroid:id="@+id/stopy"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_weight="1"android:text="TextView" /></LinearLayout></LinearLayout> - StopAdapter 클래스 생성(StopAdapter.java)
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455package kr.co.moak.aithird;import android.content.Context;import android.view.LayoutInflater;import android.view.View;import android.view.ViewGroup;import android.widget.BaseAdapter;import android.widget.TextView;import java.util.ArrayList;import java.util.HashMap;public class StopAdapter extends BaseAdapter {Context context;ArrayList<HashMap<String, String>> arList;LayoutInflater mInflater;public StopAdapter(Context context, ArrayList<HashMap<String, String>> arList){this.context = context;this.arList = arList;mInflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);}@Overridepublic int getCount() {return arList.size();}@Overridepublic Object getItem(int i) {return arList.get(i);}@Overridepublic long getItemId(int i) {return i;}@Overridepublic View getView(int i, View view, ViewGroup viewGroup) {View row = mInflater.inflate(R.layout.stop_list_item, viewGroup, false);final String stopkname = arList.get(i).get("stopkname");((TextView) row.findViewById(R.id.stopkname)).setText(stopkname);final String stopx = arList.get(i).get("stopx");((TextView) row.findViewById(R.id.stopx)).setText(stopx);final String stopy = arList.get(i).get("stopy");((TextView) row.findViewById(R.id.stopy)).setText(stopy);return row;}} - MainActivity 클래스 수정 : 멤버 필드로 ArrayList와 Adapter 추가
- MainActivity 클래스 수정 : onCreate() 함수에 ListView 추가
1234567891011121314151617181920212223242526272829303132333435@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);Button b1 = (Button)this.findViewById(R.id.b1);b1.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View view) {String apiKey = MyConst.API_KEY;String searchFld = "stopnm";String searchNm = "전주대";// 승강장명 목록 조회String url = "http://openapi.jeonju.go.kr/jeonjubus/openApi/traffic/bus_location2_stopnm_common.do"+ "?ServiceKey=" + apiKey + "&searchFld=stopnm&searchNm=" + searchNm;new MyAsyncTask(getBaseContext()).execute(url);}});ListView lstView = (ListView)this.findViewById(R.id.lstView);m_arList = new ArrayList<>();m_adapter = new StopAdapter(this.getApplicationContext(), m_arList);lstView.setAdapter(m_adapter);lstView.setOnItemClickListener(new AdapterView.OnItemClickListener() {@Overridepublic void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {Toast.makeText(getApplicationContext(), m_arList.get(i).get("stopkname"), Toast.LENGTH_SHORT).show();}});} - MainActivity 클래스 수정 3 : onPostExecute() 함수 수정하여 다운로드 된 값을 ArrayList에 저장
12345678910111213141516171819@Overrideprotected void onPostExecute(Document doc) {m_arList.clear();NodeList nodeList = doc.getElementsByTagName("list");Log.v("MYTAG", "cnt: " + nodeList.getLength());for(int i = 0; i<nodeList.getLength(); i++) {HashMap<String, String> hash = new HashMap<>();NodeList childList = nodeList.item(i).getChildNodes();for(int j=0; j<childList.getLength(); j++){hash.put(childList.item(j).getNodeName().toLowerCase(), childList.item(j).getTextContent());Log.v("MYTAG", childList.item(j).getNodeName().toLowerCase() + " "+ childList.item(j).getTextContent());}m_arList.add(hash);}m_adapter.notifyDataSetChanged();}