공공데이터(data.go.kr)에서 전주시내버스 앱 개발(Fragment 적용하기)
- Android Studio에서 새 프로젝트 추가 후
- 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/frag_stop.xml 생성
12345678910<?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"><ListViewandroid:id="@+id/lstView"android:layout_width="match_parent"android:layout_height="match_parent" /></LinearLayout> - StopAdapter 클래스 생성
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758package kr.co.moak.jeonjubus99;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);final String stopid = arList.get(i).get("stopid");((TextView) row.findViewById(R.id.stopid)).setText(stopid);return row;}} - StopFragment 클래스 생성
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118package kr.co.moak.jeonjubus99;import android.content.Context;import android.os.AsyncTask;import android.os.Bundle;import android.util.Log;import android.view.LayoutInflater;import android.view.View;import android.view.ViewGroup;import android.widget.AdapterView;import android.widget.ListView;import android.widget.Toast;import androidx.annotation.NonNull;import androidx.annotation.Nullable;import androidx.fragment.app.Fragment;import org.w3c.dom.Document;import org.w3c.dom.NodeList;import org.xml.sax.InputSource;import java.net.URL;import java.util.ArrayList;import java.util.HashMap;import javax.xml.parsers.DocumentBuilder;import javax.xml.parsers.DocumentBuilderFactory;public class StopFragment extends Fragment {ArrayList<HashMap<String, String>> m_arList;StopAdapter m_adapter;@Nullable@Overridepublic View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {View view = inflater.inflate(R.layout.frag_stop, container, false);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(getContext()).execute(url);ListView lstView = (ListView)view.findViewById(R.id.lstView);m_arList = new ArrayList<>();m_adapter = new StopAdapter(getContext(), m_arList);lstView.setAdapter(m_adapter);lstView.setOnItemClickListener(new AdapterView.OnItemClickListener() {@Overridepublic void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {Toast.makeText(getContext(), m_arList.get(i).get("stopkname"), Toast.LENGTH_SHORT).show();}});return view;}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) {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();}}} - /layout/activity_main.xml 수정
123456789101112131415161718192021222324252627282930313233343536373839404142434445<?xml version="1.0" encoding="utf-8"?><RelativeLayout 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:layout_width="match_parent"android:layout_height="match_parent"tools:context=".MainActivity"><LinearLayoutandroid:id="@+id/linear1"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_alignParentBottom="true"android:orientation="horizontal"><Buttonandroid:id="@+id/b1"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_weight="1"android:text="즐겨찾기" /><Buttonandroid:id="@+id/b2"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_weight="1"android:text="노선" /><Buttonandroid:id="@+id/b3"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_weight="1"android:text="정류장" /></LinearLayout><FrameLayoutandroid:id="@+id/container"android:layout_width="match_parent"android:layout_height="match_parent"android:layout_above="@id/linear1"></FrameLayout></RelativeLayout> - 위 정류장과 유사하게 노선 관련 layout, class 생성
- Stop/layout/frag_route.xml 생성
- RouteAdapter 클래스 생성
- RouteFragement 생성
- MainActivity 클래스 수정
12345678910111213141516171819202122232425262728293031323334353637383940414243444546package kr.co.moak.jeonjubus99;import androidx.appcompat.app.AppCompatActivity;import androidx.fragment.app.Fragment;import android.os.Bundle;import android.view.View;import android.widget.Button;import android.widget.Toast;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) {Toast.makeText(MainActivity.this, "즐겨찾기", Toast.LENGTH_SHORT).show();}});Button b2 = (Button)this.findViewById(R.id.b2);b2.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View view) {Toast.makeText(MainActivity.this, "노선", Toast.LENGTH_SHORT).show();Fragment frag = new RouteFragment();getSupportFragmentManager().beginTransaction().replace(R.id.container, frag).commit();}});Button b3 = (Button)this.findViewById(R.id.b3);b3.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View view) {Toast.makeText(MainActivity.this, "정류장", Toast.LENGTH_SHORT).show();Fragment frag = new StopFragment();getSupportFragmentManager().beginTransaction().replace(R.id.container, frag).commit();}});}}- <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)