**XML Parsing
1.XML
=> eXtensible Markup Language 의 약자
=> HTML이 구조적이지 못하고 해석을 웹 브라우저가 하는 문제 때문에 데이터 포맷으로 부적합
=> 구조적이고 엄격한 문법을 적용하고 해석을 브라우저가 아닌 곳에서 할 수 있는 문자열 포맷을 고안했는데 이 문자열 포맷이 XML
=> 최근에 사용되던 HTML은 HTML에 XML 문법을 적용한 XHTML 이었고 이것을 HTML4.01 이라고 했습니다.
- 요즈음은 HTML5 문법을 많이 사용
=> Web의 대중화 시절 RSS(Rich Site Summary, Really Simple Syndication - 실시간 데이터 제공), SOAP(Simple Object Access Protocol - 서버에서 클라이언트에게 객체를 단순하게 전달하는 프로토콜)가 등장. 이 때 사용한 데이터 표준이 XML
=> 자바스크립트에서 서버에 데이터를 비동기적으로 요청하여 일부분의 UI만 갱신할 필요성 등장, 이 때 채택한 기술이 AJAX(X=XML)
=> 최근에는 REST API의 등장으로 json을 데이터 포맷으로 더 많이 이용
=> 순수하게 넘겨주는 데이터는 json을 많이 사용하지만 사람이 직접 설정하는 부분은 아직 대부분 XML
2. XML의 기본 문법
<xml 구조나 인코딩 방식>
<!-- 없으면 에러인데 설정 파일의 경우는 프레임워크가 대신 추가해주기소 함.
안드로이드에서 XML을 만들 때 이 부분을 생략해도 됨-->
<DTD>
<!-- xml 파일의 내용을 해석하여 다른 코드로 변경해주는 위치를
설정하는 것으로 설정 파일일 때는 필수이지만 데이터 일때는 생략-->
<Root 태그>
데이터를 의미하는 태그와 내용
</Root>
=> XML을 생성하는 것은 직접 작성하지 않고 라이브러리를 이용하여 데이터만 설정하면 됨
3. XML 파싱
=> 2가지가 있는데 DOM Parsing과 SAX Parsing 2가지
=> 거의 대다수의 프로그래밍 언어가 2가지 방법을 동일하게 지원
1) DOM(Document Object Model)
=> HTML이나 XML의 내용을 메모리에 펼쳐서 사용할 수 있도록 한 것
2) DOM Parser
=> XML 내용을 메모리에 전부 펼쳐놓고 필요한 DOM을 찾아서 파싱
=> 처음부터 내용을 메모리에 전부 저장하므로 메모리 사용량이 많지만 속도는 빠름
=> 편집도 가능
=> Root까지 찾기
DocumentBuilderFactory factory = new DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
InputStream inputStream = new ByteArrayInputStream(문자열.getBytes("인코딩 방식"));
Document document = builder.parse(inputStream);
Element root = document.getDocumentElement();
=> 파싱하고자 하는 태그 찾기
NodeList items = root.getElementsByTagName("태그명");
for(int i=0; i<item.length(); i += 1){
Node item = items.get(i);
Node text = items.getFirstChild();
String content = text.getNodeValue();
}
3) SAX Parser
=> 태그 하나하나를 읽어가면서 파싱하는 방식
=> 하나의 태그를 읽을 때 호출되는 콜백 메소드를 이용하여 파싱
=> 내용을 전부 메모리에 저장하지 않기 때무에 메모리 사용량이 적지만 속도는 느림
=> 편집도 불가능
=> DefaultHandlerfh부터 상속받는 클래스를 생성하여 메소드 재정의 후 사용
- public void startDocument() : 문서의 시작을 만나면 호출되는 메소드
- public void endDocument() :
- public void startElement(String uri, String localName, String qName, Attributes attrs)
: 열리는 태그를 만나면 호출되는 메소드 - qName이 태그명이고 attrs가 태그의 속성들의 집합
- public void endElement(String url, String localName, String qName)
: 닫는 태그를 만나면 호출되는 메소드
- public void characters(char[] chars, int start, int length)
: 여는 태그와 닫는 태그 사이의 문자열을 만나면 호출되는 메소드 - chars : 내용, start : 시작위치, length : 길이
: 태그명은 하나의 패킷에 전부 전송이 가능하지만 태그 안의 내용은 하나의 패킷을 초과하는 경우도 있을 수 있음
: 이 메소드는 유일하게 하나의 태그에 여러번 호출될 수 있음
: 긴 문자열의 데이터를 가져올 때는 이 메소드를 잘 사용해야 함
=> 파싱 수행
- SAXParserFactory factory = SAXParserFactory.newInstance();
- SAXParser parser = factory.newSAXParser();
- XMLReader reader = parser.getXMLReader();
- DefaultHandler 클래스 객체 = new DefaultHandler 클래스();
- Reader.setContentHandler(객체);
- InputStream inputStream = new ByteArrayInputStream(문자열.getBytes("인코딩방식");
- reader.parse(new InputSource(inputStream)); //핸들러
4. 한겨레 신문사의 전체 기사를 파싱하여 title과 link의 내용을 가져와서 출력
=> 단 첫번째 title과 link는 제외
1) 프로젝트 생성 - 실행가능한 Activity를 생성하거나 추가
2) 웹에서 가져와야 하므로 인터넷 권한을 설정하고 프로토콜을 확인하여 Application에 설정 추가
=> www.hani.co.kr/rss
=> AndroidManifest.xml 파일에 추가
<!-- 권한 설정 -->
<uses-permission android:name="android.permission.INTERNET"/>
<application
android:usesCleartextTraffic="true"
3) activity_main.xml 파일에 화면 디자인
=> 화면 전체를 사용하는 텍스트뷰를 작성
<?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:layout_width="match_parent"
android:orientation="vertical"
android:layout_height="match_parent"
tools:context=".MainActivity">
<ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/hanidisplay"/>
</ScrollView>
</LinearLayout>
4) MainActivity 클래스에서 디자인 뷰를 전부 찾아오기
=> 인스턴스 변수 선언
-TextView hanidisplay;
=> onCreate 메소드에 뷰를 찾아오는 코드를 작성
- haniDisplay = (TextView)findViewById(R.id.hanidisplay);
5) 데이터 다운로드를 위한 Thread클래스 생성
//title 태그의 내용을 저장할 List
ArrayList<String> titleList = new ArrayList<>();
//link 태그의 내용을 저장할 List
ArrayList<String> linkList = new ArrayList<>();
//데이터를 다운로드 받아서 파싱할 스레드 클래
class ThreadEx extends Thread{
String xml;
public void run(){
//웹 서버에서 문자열 다운로드 받기
try{
//다운로드 받을 URL 생성
URL url = new URL("http://www.hani.co.kr/rss/");
//연결 객체 생성
HttpURLConnection con =
(HttpURLConnection)url.openConnection();
//연결 옵션을 설정
con.setRequestMethod("GET");
con.setConnectTimeout(30000);
con.setUseCaches(false);
con.setDoOutput(true);
con.setDoInput(true);
//파일을 업로드하는 코드가 있으면 설정을 추가
//파라미터를 추가 - GET 일 때는 url에 바로 추가해도 됩니다.
//다운로드 받기 - 문자열 : BufferedReader, 파일 : BuffredInputStream
BufferedReader br =
new BufferedReader(
new InputStreamReader(
con.getInputStream()));
//문자열을 가지고 + 연산을 하면 메모리 낭비가 발생할 수 있어서
//StringBuilder를 이용
//문자열은 + 연산을 하면 현재 객체에 하는 것이 아니고 복사해서 수행
StringBuilder sb = new StringBuilder();
while(true){
String line = br.readLine();
if(line == null){
break;
}
//출력할 때 보기좋게 하기 위해서 \n을 추가
//실제 서비스를 할 때는 \n은 제거
sb.append(line + "\n");
}
//정리
br.close();
con.disconnect();
//다운로드 받은 내용을 문자열로 변환
xml = sb.toString();
Log.e("xml", xml);
}catch(Exception e){
//이 예외가 보이면 권한 설정 부분과 URL을 확인
Log.e("다운로드 예외", e.getMessage());
}
//파싱하는 부분
try{
if(xml != null){
//DOM 파싱을 위한 준비
DocumentBuilderFactory factory =
DocumentBuilderFactory.newInstance();
DocumentBuilder builder =
factory.newDocumentBuilder();
InputStream inputStream =
new ByteArrayInputStream(
xml.getBytes("utf-8"));
Document document = builder.parse(inputStream);
Element root = document.getDocumentElement();
//title 태그 전부 가져오기
NodeList titles = root.getElementsByTagName("title");
NodeList links = root.getElementsByTagName("link");
for(int i=1; i<titles.getLength(); i=i+1){
//각각의 태그에 접근해서 문자열을 추출해서 저장
Node title = titles.item(i);
Node text = title.getFirstChild();
titleList.add(text.getNodeValue());
Node link = links.item(i);
text = link.getFirstChild();
linkList.add(text.getNodeValue());
}
//핸들러에게 출력을 요청
Message message = new Message();
//전송할 데이터가 있으면 message.obj에 대입
handler.sendMessage(message);
}
}catch(Exception e){
//이 예외가 보이면 파싱 알고리즘을 확인
Log.e("파싱 예외", e.getMessage());
}
}
}
6) 다운로드 받아서 파싱한 결과를 출력할 Handler를 생성
=> 여기서 화면 출력하지않으면 handler는 필요 없음
//파싱한 결과를 받아서 출력할 핸들러 객체
Handler handler = new Handler(Looper.getMainLooper()){
public void handleMessage(Message message){
//titleList의 내용을 텍스트 뷰에 출력
StringBuilder sb = new StringBuilder();
for(String title : titleList){
sb.append(title + "\n");
}
haniDisplay.setText(sb.toString());
}
};
7) MainActivity 클래스에 onResume 메소드를 재정의하여 스레드를 생성하고 시작
@Override
public void onResume(){
super.onResume();
//스레드 시작
new ThreadEx().start();
}
**Adapter View
=> 여러개의 데이터를 출력하기 위한 View
=> 3개의 요소를 가지고 데이터를 출력
- Data : 배열이나 List - 출력되는 내용은 기본적으로 각 요소의 toString의 결과
- View : 데이터를 출력하기 위한 view - 기본은 ListView
- Adapter : Data와 View를 연결해주기 위한 Controller
**구동원리를 알아보기 위한 실습
1. 실행가능한 Activity추가 - ListViewActivity
2. 화면 디자인
<?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:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".ListViewActivity">
<ListView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/listview"/>
</LinearLayout>
3. Activity.java 파일에 작성
public class ListViewActivity extends AppCompatActivity {
//출력할 데이터
String [] data;
//출력할 뷰
ListView listview;
//연결할 Adapter
ArrayAdapter<String> adapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_list_view);
//데이터 생성
data = new String[4];
data[0] = "SI";
data[1] = "SM";
data[2] = "QA";
data[3] = "DevOps";
//출력할 View 생성
listview = (ListView)findViewById(R.id.listview);
//adapter 생성
//첫번째양는 출력을 위한 Context
//두번째는 ListView의 행 모양
//android.R.layout에 기본 모양이 제공
//세번째는 출력할 데이터
adapter = new ArrayAdapter<>(
this,
android.R.layout.simple_list_item_1,
data);
//뷰에 Adapter를 설정
listview.setAdapter(adapter);
}
}
**배열이나 List 대신에 array.xml 파일에 만든 리소스도 출력 가능
1. res/values 디렉토리에 array.xml 파일을 추가하고 배열을 생성
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string-array name="pl">
<item>Machine Language</item>
<item>Assembly</item>
<item>C&C++</item>
<item>Java</item>
<item>Python</item>
<item>JavaScript</item>
<item>C#</item>
<item>R</item>
<item>Objective-C</item>
<item>Swift</item>
<item>Kotlin</item>
<item>Go</item>
<item>Scala</item>
<item>Ruby</item>
<item>VB</item>
<item>Closure</item>
<item>Haskell</item>
<item>SQL</item>
</string-array>
</resources>
2. Adapter 객체를 생성하는 코드를 변경
- ArrayAdapter.createFromResource(Context context, int resourceId, int 행 모양);
**AdapterView의 종류
- ListView
- GridView
- Spinner
- Gallery
**Adapter
=> Adapter : 항목들의 집합을 관리하는 기본적인 메소드를 소유한 클래스
=> Adapter를 상속받은 ListAdapter : ListView와 연결에 필요한 메소드 정의
=> Adapter를 상속받은 SpinnerAdapter : Spinner와 연결에 필요한 메소드 정의
=> ListAdapter, SpinnerAdapter를 상속받은 BaseAdapter : 앞의 2개의 인터페이스의 메소드 중 기본적인 것들 구현
=> BaseAdapter를 상속받은 클래스 : ArrayAdapter(배열, List연결), CursorAdapter(DB 커서 연결), SimpleAdapter
**ListView
=> BaseAdapter : 모든 종류를 이용하여 데이터를 출력하는 것이 가능
=> ArrayAdapter : 배열, List 인터페이스를 구현한 클래스, array.xml 파일에 만들어진 리소스를 주입 받을 수 있음
=> 행에 표시할 리소스 ID
- android.R.layout.simple_list_item_1 : 하나의 텍스트 뷰로 구성
- android.R.layout.simple_list_item_2 : 두개의 텍스트 뷰로 구성
- android.R.layout.simple_list_item_checked : 체크 표시가 만들어 짐
- android.R.layout.simple_list_item_single_choice : 라디오 버튼을 이용해서 하나의 행만 선택하도록 해줌
- android.R.layout.simple_list_item_multiple_choice : 체크박스를 이용해서 여러개의 행만 선택하도록 해줌
=> adapter 연결 메소드
- setAdapter(Adapter adapter)
=> 선택 모드 설정
- setChoiceMode(int id)
- CHOICE_MODE_NONE, CHOICE_MODE_SINGLE, CHOICE_MODE_MULTIPLE로 설정
- 설정시에는 적절한 행의 모양도 같이 설정해야 함
=> 경계선 모양이나 두께 설정
- 모양을 반드시 먼저 설정
- setDivider(Drawable drawable) : 모양 설정
- setDividerHeight(int height) : 두께 설정
=> 행을 선택했을 때 호출되는 Listener
- AdapterView.OnItemClickListener의 onItemClick이라는 메소드가 존재
: 첫번째 매개변수 - AdapterView가 전달
: 두번째 매개변수 - 선택한 행의 뷰가 리턴
: 세번째 매개변수 - 행의 인덱스가 리턴
: 네번째 매개변수 - 항목의 고유한 ID가 전달
=> 데이터가 변경된 경우 다시 출력을 요청하는 메소드
- AdpaterView가 notifyDataSetChanged()를 호출하면 됨
=> 행의 선택여부를 알려주는 메소드
- ListView의 get?Position()을 이용, 여러개 선택한 경우 getCheckedItemPosition()을 호출하여 SparseBooleanArray로 리턴 가능
: 이 배열은 ListView의 모든 항목의 선택여부를 Boolean 배열로 만들어 준것
**ListView의 항목을 추가할 수 있고 여러개 선택하여 삭제할 수 있는 실습
1. 실행가능한 Activity추가 - MultiActivity
2. 레이아웃에 화면 디자인
<?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:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MultiActivity"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<EditText
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="4"
android:hint="추가할 항목 입력"
android:id="@+id/iteminput"/>
<Button
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="3"
android:text="추가"
android:textSize="30sp"
android:id="@+id/addbtn"/>
<Button
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="3"
android:text="삭제 "
android:textSize="20sp"
android:id="@+id/delbtn"/>
</LinearLayout>
<ListView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/listview" />
</LinearLayout>
3. Activity.java에 데이터 출력
1) 인스턴스 변수 3개 선언 : ListView, List, ArrayAdapter
ListView listView;
ArrayList<String> data;
ArrayAdapter<String> adapter;
2) onCreate 메소드에서 출력하는 코드를 작성
listView = (ListView)findViewById(R.id.listview);
data = new ArrayList<>();
data.add("Oracle");
data.add("MySQL");
data.add("MongoDB");
data.add("MS-SQL Server");
adapter = new ArrayAdapter<>(this, android.R.layout.simple_list_item_1, data);
listView.setAdapter(adapter);
4. 선택 모드와 선 모양 변경
=> Activity.java파일의 onCreate 메소드에서 설정
adapter = new ArrayAdapter<>(
this, android.R.layout.simple_list_item_multiple_choice, data);
listView.setAdapter(adapter);
//선 모양 설정
listView.setDivider(new ColorDrawable(Color.RED));
listView.setDividerHeight(3);
//선택 모드를 변경
listView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
5. EditText에 입력을 하고 추가 버튼을 누르면 데이터가 삽입되는 코드를 작성
1) Activity.java 파일에 2개 뷰에 대한 변수를 선언
EditText iteminput;
Button addbtn;
2) Activity.java 파일의 onCreate 메소드에 작성
iteminput = (EditText)findViewById(R.id.iteminput);
addbtn = (Button)findViewById(R.id.addbtn);
addbtn.setOnClickListener(
new Button.OnClickListener(){
public void onClick(View view){
//유효성 검사를 수행
String item = iteminput.getText().toString().trim();
if(item.length() < 1){
Toast.makeText(MultiActivity.this,
"입력을 하지 않았습니다.",
Toast.LENGTH_LONG).show();
return;
}
data.add(item);
//ListView를 재출력
adapter.notifyDataSetChanged();
//메시지 출력
Toast.makeText(MultiActivity.this,
"데이터 추가 성공",
Toast.LENGTH_LONG).show();
//키보드 숨기기
InputMethodManager imm =
(InputMethodManager)
getSystemService(INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(iteminput.getWindowToken(), 0);
//입력 뷰를 초기화
iteminput.setText("");
}
});
6. 삭제 버튼을 누르면 선택된 항목들을 삭제하는 작업
1) Activity.java 파일에 인스턴스 변수를 추가
=> Button delbtn;
2) Activity.java 파일의 onCreate 메소드에 추가
delbtn = (Button)findViewById(R.id.delbtn);
delbtn.setOnClickListener(new Button.OnClickListener(){
public void onClick(View view){
//listview에서 각 행에 대한 선택여부를 가져오기
SparseBooleanArray sba = listView.getCheckedItemPositions();
//여러 개의 인덱스를 삭제할 때는 뒤에서 부터 삭제
for(int i=listView.getCount()-1; i>=0; i=i-1){
if(sba.get(i) == true){
data.remove(i);
}
}
//선택 해제
listView.clearChoices();
adapter.notifyDataSetChanged();
}
});
7. SimpleAdapter
=> 하나의 행에 여러개의 데이터를 구분해서 출력하고자 할 때 사용하는 Adapter
=> 데이터는 ArrayList<HashMap<String, String>> 타입으로 구성
=> 생성시 : New SimpleAdapter(Context context, List<Map<String, String>> list, int resourceID, String[], int[])
- int resourceID - 모양, String[] - key의 배열, int[] - 출력할 뷰의 모양
8. CursorAdapter
=> SQLite의 검색 결과를 출력하기 위한 Adapter
- New SimpleAdapter(Context context, int resourceID, Cursor cursor, String[], int[])
=> 데이터베이스.rawQuery(String select 구문)의 결과를 데이터로 설정하면 됨
**사용자 정의 항목 뷰 사용
1. Layout Inflation
=> 안드로이드는 뷰를 만드는 방법 중에 XML을 이용하는 방법이 있음
- XML로 만든 뷰를 메모리에 할당하여 화면에 출력하는 것을 인프레이션이라고 함
=> Activity의 전체 뷰로 설정하고자 하는 경우 Activity.setContentView(int id)
=> 일부분으로 사용하는 경우 Context 객체의 getSystemService 메소드를 이용하여 LayoutInflater를 찾아와서 inflate(뷰의 아이디, 부모뷰, 뷰 그룹 여부)를 호출
2. BaseAdapter로 부터 상속받는 클래스를 생성
=> 메소드를 재정의
- getCount : 행의 개수를 설정하는 메소드 - 여기서 리턴한 값이 행의 개수가 됨
- getItem : position위치의 항목을 리턴하는 메소드
- getItemId : position 위치의 항목 뷰에 아이디를 설정하는 메소드 - position을 리턴하는 것이 일반적
- getView(int position, View convertView, ViewGroup parent) : 여기서 리턴한 뷰가 ListView의 각 항목이 됨
-> position : 각 항목의 인덱스
-> convertView : 이전에 출력된 뷰로 처음 메소드가 호출될 때는 null, 두번째 부터는 null이 아님
-> parent : 항목이 놓이게되는 부모 뷰 - AdapterView
**셀의 왼쪽에는 이미지, 가운데는 TextView, 오른쪽에는 버튼 배치, 클릭시 현재 선택한 항목을 선택했다고 Toast 에 출력
=> 데이터 구조 : Map을 이용, image키 - 출력할 이미지 id, title키 - TextView에 출력할 내용, content 키 - 클릭시 출력할 내용 저장
=> Map대신 DTO 클래스를 사용해도 됨
- DTO 클래스를 만들거라면 인스턴스 변수를 public으로 선언하여 사용해도 됨
- 서버는 안정성이나 신뢰성을 추구하고 여러 클라이언트가 동시에 사용하므로 인스턴스 변수를 getter, setter로 작성 데이터에 접근
- 클라이언트는 편의성을 추구하고 여러 클라이언트가 동시에 사용할 이유가 없으므로 대부분의 변수를 public으로 하여 접근
1. 실행 가능한 Activity를 생성 - CustomCellUseActivity
2. 레이아웃 파일에 ListView를 전체 크기로 출력
<?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:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".CustomCellUseActivity">
<ListView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/listview"/>
</LinearLayout>
3. Activity.java 파일에 인스턴스 변수를 추가
private ListView listview;
//출력할 데이터
ArrayList<Map<String, String>> data;
4. Activity.java파일의 onCreate에서 listView를 찾아서 대입하고 데이터 생성 코드 작성
listView = (ListView)findViewById(R.id.listview);
data = new ArrayList<>();
Map<String, Object> map =
new HashMap<>();
map.put("image", R.mipmap.ic_launcher);
map.put("title", "SI");
map.put("content", "시스템 개발");
data.add(map);
map = new HashMap<>();
map.put("image", R.mipmap.ic_launcher);
map.put("title", "SM");
map.put("content", "시스템 운영 - 유지보수 및 관리");
data.add(map);
map = new HashMap<>();
map.put("image", R.mipmap.ic_launcher);
map.put("title", "QA");
map.put("content", "품질관리 및 테스트");
data.add(map);
map = new HashMap<>();
map.put("image", R.mipmap.ic_launcher);
map.put("title", "DevOps");
map.put("content", "개발과 운영환경 구축");
data.add(map);
map = new HashMap<>();
map.put("image", R.mipmap.ic_launcher);
map.put("title", "IoT");
map.put("content",
"인터넷 되는 기기 내장 프로그램 - Embedded");
data.add(map);
5. 하나의 항목으로 사용할 뷰의 모양을 생성
=> 레이아웃 디렉토리에 layout을 추가 - icontext.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="60dp"
android:padding="5dp"
android:orientation="horizontal">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:id="@+id/image"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:textSize="20sp"
android:id="@+id/title"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:textSize="20sp"
android:text="선택"
android:id="@+id/content"
/>
</LinearLayout>
6. Adapter 클래스 만들기
=> BaseAdapter로 부터 상속 받아서 메소드 재정의
public class JobAdapter extends BaseAdapter {
Context context;
List<Map<String, Object>> list;
//생성자
public JobAdapter(
Context context,
List<Map<String, Object>> list){
this.context = context;
this.list = list;
}
//행의 개수를 설정하는 메소드
//이 메소드에서 리턴한 값만큼 아래 메소드들을 호출
@Override
public int getCount() {
return list.size();
}
//행의 항목을 만들어주는 메소드
@Override
public Object getItem(int i) {
Map<String, Object> map =
list.get(i);
return map.get("title").toString();
}
//각 행의 아이디를 설정하는 메소드
@Override
public long getItemId(int i) {
return i;
}
//첫번째 매개변수는 행 번호
//두번째 매개변수가 출력할 뷰
//세번째 매개변수는 항목이 출력되는 AdapterView
@Override
public View getView(
int i, View view, ViewGroup viewGroup) {
final int pos = i;
if(view == null){
//icontext.xml 파일을 전개해서 뷰로 생성
LayoutInflater inflater =
(LayoutInflater)context.getSystemService(
Context.LAYOUT_INFLATER_SERVICE);
view = inflater.inflate(
R.layout.icontext, viewGroup,
false);
}
//이미지 출력
ImageView image =
(ImageView)view.findViewById(R.id.image);
int imageid = (Integer)list.get(i).get("image");
image.setImageResource(imageid);
//텍스트 뷰
TextView title = (TextView)view.findViewById(R.id.title);
String titleText = (String)list.get(i).get("title");
title.setText(titleText);
//버튼
Button btn = (Button)view.findViewById(R.id.content);
btn.setOnClickListener(new Button.OnClickListener(){
public void onClick(View view){
String content = (String)list.get(
pos).get("content");
Toast.makeText(
context, content, Toast.LENGTH_LONG)
.show();
}
});
return view;
}
}
7. Activity.java 파일의 onCreate 수정
//어댑터 생성
JobAdapter adapter =
new JobAdapter(this, data);
listView.setAdapter(adapter);
**사용자 정의 셀 만들기
=> 셀로 사용할 뷰를 레이아웃 파일로 생성
=> 데이터를 받아서 레이아웃에 출력할 Adapter 클래스를 생성
=> ListView에 새로 만든 Adapter 클래스의 객체를 설정
'수업 정리' 카테고리의 다른 글
82일차 수업정리(Android - ActionBar, 데이터 전송) (0) | 2020.07.31 |
---|---|
81일차 수업정리(Android 연동) (0) | 2020.07.30 |
76~78일차 수업정리(MySQL&Hibernate Project) (0) | 2020.07.23 |
75~76일차 수업 정리(Oracle&MyBatis) (0) | 2020.07.23 |
75일차 수업정리(Android - Socket) (0) | 2020.07.22 |