Working with System Permissions

안드로이드 6.0 권한 변경
Declaring Permissions
Learn how to declare the permissions you need in your app manifest.
Requesting Permissions at Run Time
Learn how to request permissions from the user while the app is running. This lesson only applies to apps on devices running Android 6.0 (API level 23) and higher.
Permissions Best Practices
Guidelines for creating the best user experience in requesting and using permissions.


네이버 D2

http://d2.naver.com/home 


Android의 HTTP 클라이언트 라이브러리

Android 애플리케이션에서는 HTTP 통신을 다루는 부분의 비중이 크다. 데이터를 조회하거나 저장하기 위해 서버와 통신하는 모듈은 대부분 HTTP API를 사용하고 있기 때문이다.

TCP/UDP의 낮은 레벨의 통신은 송수신을 위해 개발자가 직접 처리해야됨, 잔 작업도 많고 NAT문제에 자유롭지 않다


사용자가 보는 화면 개발을 제외한다면 HTTP 클라이언트가 애플리케이션 개발의 중심이라고도 할 만하다.

Android 환경에서 HTTP 클라이언트를 개발하는 방식은 다양하다. Android SDK에서 제공하는 기능을 직접 사용하기도 하고, 이를 좀 더 편하게 사용하도록 도와주는 유틸리티 클래스를 프로젝트마다 개발하기도 한다. 오픈 소스 라이브러리를 활용한 애플리케이션도 있다.


SDK에서 제공하는 HTTP 클라이언트의 허점과 변경 사항

Android는 표준 JRE의 클래스와 동일한 형태인 HTTPURLConnection 클래스를 제공한다. 

그리고 오픈 소스로 유명한 Apache HttpComponents의 HttpClient도 SDK에 포함되어 있다. (6.0부터 x)


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
public class NaverBookSearchService {
    //요청을 하기 위한 ID와 SECRET
    private static final String CLIENT_ID = "";
    private static final String CLIENT_SECRET = "";
    
    //요청할 URL
    private static final String URL
    ="https://openapi.naver.com/v1/search/book.xml";
    
    //한번의 요청에서 받아올 아이템 갯수
    private static final int DISPLAY_ITEM_COUNT = 10;
    
    //현재 페이지를 알기 위한 상태값
    private int currentSkip = 1;
    
    //검색할 키워드
    private String keyword;
    
    public NaverBookSearchService(String keyword)
    {
        this.keyword = keyword;
    }
    public void nextPage()
    {
        currentSkip += DISPLAY_ITEM_COUNT;
    }
cs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
public List<Book> search(){
        List<Book> list = null;
        try {
            URL url;
            url = new URL(URL + "?query="
                    + URLEncoder.encode(keyword, "UTF-8")
                    + "&display=" + DISPLAY_ITEM_COUNT
                    + "&start="+ currentSkip);
 
            URLConnection urlConn = url.openConnection();
            urlConn.setRequestProperty("X-Naver-Client-Id", CLIENT_ID);
            urlConn.setRequestProperty("X-Naver-Client-Secret", CLIENT_SECRET);
             
            XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
            XmlPullParser parser = factory.newPullParser();
            parser.setInput(
                    new InputStreamReader(urlConn.getInputStream()));
             
             
             
            int eventType = parser.getEventType();
            Book b = null;
            while (eventType != XmlPullParser.END_DOCUMENT) {
                switch (eventType) {
                case XmlPullParser.END_DOCUMENT: // 문서의 끝
                    break;
                case XmlPullParser.START_DOCUMENT:
                    list = new ArrayList<Book>();
                    break;
                case XmlPullParser.END_TAG: {
                    String tag = parser.getName();
                    if(tag.equals("item"))
                    {
                        list.add(b);
                        b = null;
                    }
                }
                case XmlPullParser.START_TAG: {
                    String tag = parser.getName();
                    switch (tag) {
                    case "item":
                        b = new Book();
                        break;
                    case "title":
                        if(b != null)
                            b.setTitle(parser.nextText());
                        break;
                    case "link":
                        if(b != null)
                            b.setLink(parser.nextText());
                        break;
                    case "image":
                        if(b != null)
                            b.setImage(parser.nextText());
                        break;
                    case "author":
                        if(b != null)
                            b.setAuthor(parser.nextText());
                        break;
                    case "price":
                        if(b != null)
                            b.setPrice(parser.nextText());
                        break;
                    case "discount":
                        if(b != null)
                            b.setDiscount(parser.nextText());
                        break;
                    case "publisher":
                        if(b != null)
                            b.setPublisher(parser.nextText());
                        break;
                    case "pubdate":
                        if(b != null)
                            b.setPubdate(parser.nextText());
                        break;
                    case "isbn":
                        if(b != null)
                            b.setIsbn(parser.nextText());
                        break;
                    case "description":
                        if(b != null)
                            b.setDescription(parser.nextText());
                        break;
                    }
                     
                }
                }
                eventType = parser.next();
            }
             
             
             
             
        } catch (MalformedURLException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (UnsupportedEncodingException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (XmlPullParserException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return list;
    }
cs

1
2
NaverBookSearchService service = new NaverBookSearchService(keyword);
service.search();
cs

search메소드는 네트워크 통신을 사용하기 때문에 UI쓰레드에서 직접 호출할 수 없음, 파생쓰레드를 만들어서 호출해야 하고 파생쓰레드가 얻어낸 데이터를 UI쓰레드로 가져오려면 UI(메인)쓰레드의 핸들러가 필요하다.

UI(메인)쓰레드는 파생쓰레드가 받아온 데이터를 전달 받았을 때 UI에 반영하는 코드를 Handler클래스를 상속받아 handleMessage에 구현, 파생쓰레드는 네트워크 통신을 통해 얻은 데이터를 UI쓰레드에게 전달해주기 위해서 UI(메인)쓰레드의 Handler객체에 대한 참조 필요

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
    private Handler handler =  new Handler(){
 
        @Override
        public void handleMessage(Message msg) {
            // TODO Auto-generated method stub
            super.handleMessage(msg);
            //what이 1이면 NaverBookSearchThread가 보내는 데이터 인걸로
            if(msg.what == 1)
            {
                //arg1이 100이면 처음 검색에 대한 결과를 갖다 준걸로
                if(msg.arg1 == 10)
                {
                    String result = "";
                    List<Book> data = (List<Book>)msg.obj;
                    for(Book b : data)
                        result += b + "\n";
                    Toast.makeText(MainActivity.this, result, 0).show();
                }
                //arg1이 20이면 검색했던 결과에 대해 추가 아이템을 요청한걸로
                else if(msg.arg1 == 20)
                {
                    
                }
            }
        }
        
    };
cs


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class NaverBookSerachThread extends Thread{
    private NaverBookSearchService service;
    private Handler handler;
    
    public NaverBookSerachThread(NaverBookSearchService service, Handler handler)
    {
        this.service = service;
        this.handler = handler;
    }
 
    @Override
    public void run() {
        // TODO Auto-generated method stub
        super.run();
        
        //service의 search메소드를 수행하고 결과를 핸들러를 통해 메인에게 전달
        List<Book> data = service.search();
    }
    
}
cs

1
2
3
4
5
    public int getCurrentSkip(){
        return currentSkip;
        //nextPage함수가 한번이상 불려서 currentSkip이 1이 아니면
        //처음 검색이 아니고 아이템 추가
    }

c
s

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
    public void run() {
        // TODO Auto-generated method stub
        super.run();
        
        //service의 search메소드를 수행하고 결과를 핸들러를 통해 메인에게 전달
        List<Book> data = service.search();
        
        Message msg = handler.obtainMessage();
        msg.what = 1;
        msg.obj = data;
        if(service.getCurrentSkip() == 1)
            msg.arg1 = 10;
        else                //첫 검색인지 아닌지 구분
            msg.arg1 = 20;
        handler.sendMessage(msg);
    }
cs

1
2
3
4
5
6
7
8
9
10
            public void onClick(View v) {
                // TODO Auto-generated method stub
                String keyword = keywordEdt.getText().toString();
                NaverBookSearchService service = new NaverBookSearchService(keyword);
//                service.search();
                NaverBookSerachThread thread = new NaverBookSerachThread(service, handler);
                thread.start();    
 
            }
        });
cs


리스트뷰 작성

getView할일

1. 껍데기 인플레이션하기(convertView가 null이 아니면 재사용 가능)

2. 껍데기 내부의 위젯들 객체 얻어오기 (findViewByid)

3. 각 위젯에 데이터 바인딩하기

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
public class BookAdapter extends ArrayAdapter<Book>{
    private Context context;
    private int resource;
    private List<Book> bookList;
    
    public BookAdapter(Context context, int resource, List<Book> bookList) {
        super(context, resource, bookList);
        this.context = context;
        this.resource = resource;
        this.bookList = bookList;
    }
 
    static class BookViewHolder{
        public ImageView imageView;
        public TextView titleTv;
        public TextView priceNpub;
        public TextView authorNpubDate;
    }
    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        // TODO Auto-generated method stub
//        return super.getView(position, convertView, parent);
 
        //getView메소드는 리스트뷰의 한줄의 아이템을 그리기 위한 뷰를 만들어내는 함수이고
        //한줄의 아이템에 대해서 UI를 인플레이션하고 그 객체를 리턴하면됨
        BookViewHolder holder;
        if(convertView == null)
        {
            //이미 인플레이션 한 뷰가 있다면 매개변수 convertView에 들어와 재사용 가능하닌까
            //convertView가 null일때만 인플레이션 해줌
            LayoutInflater inflater
            = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            convertView = inflater.inflate(R.layout.list_item, parent, false);
            //처음 인플레이션 될 때 홀더객체를 만들어서 홀더 셋트의 위젯 참조변수들에 findViewById
            holder = new BookViewHolder();
            holder.imageView = (ImageView) convertView.findViewById(R.id.list_img);
            holder.titleTv = (TextView) convertView.findViewById(R.id.list_tv_title);
            holder.priceNpub = (TextView) convertView.findViewById(R.id.list_tv_price_and_publisher);
            holder.authorNpubDate = (TextView) convertView.findViewById(R.id.list_tv_author_and_pubdate);
            
            //holder객체는 각 위젯들의 findViewById한 결과들 집합이다.
            convertView.setTag(holder);
        }
        else
        {
            holder = (BookViewHolder) convertView.getTag();
        }
        Book book = bookList.get(position);
        //여기까지 이제 홀더객체 안의 각 위젯에 book객체의 각 멤버변수값들이랑 바인딩하면 된다.
        holder.imageView.setImageResource(R.drawable.ic_launcher);
        holder.titleTv.setText(book.getTitle());
        holder.priceNpub.setText(book.getPrice() +"원\t출판사 : "+book.getPublisher());
        holder.authorNpubDate.setText("저자 : "+ book.getAuthor() + "\t출판일 : " + book.getPubdate());
        return convertView;
    }
}
 
cs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class MainActivity extends Activity {
    private EditText keywordEdt;
    private Button searchBtn;
    private ListView listView;
    private BookAdapter adapter;
    private List<Book> bookList;
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        keywordEdt = (EditText) findViewById(R.id.main_edt_search);
        searchBtn = (Button) findViewById(R.id.main_btn_search);
        listView = (ListView) findViewById(R.id.main_listView);
        bookList = new ArrayList<Book>();
        adapter = new BookAdapter(this, R.layout.list_item,bookList);
        
        listView.setAdapter(adapter);
cs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
    private Handler handler =  new Handler(){
 
        @Override
        public void handleMessage(Message msg) {
            // TODO Auto-generated method stub
            super.handleMessage(msg);
            //what이 1이면 NaverBookSearchThread가 보내는 데이터 인걸로
            if(msg.what == 1)
            {
                //arg1이 10이면 처음 검색에 대한 결과를 갖다 준걸로
                if(msg.arg1 == 10)
                {
//                    String result = "";
//                    List<Book> data = (List<Book>)msg.obj;
//                    for(Book b : data)
//                        result += b.getTitle() + "\n";
//                    Toast.makeText(MainActivity.this, result, 0).show();
                    bookList.clear();
                    bookList.addAll((List<Book>) msg.obj);
                    adapter.notifyDataSetChanged();
                }
                //arg1이 20이면 검색했던 결과에 대해 추가 아이템을 요청한걸로
                else if(msg.arg1 == 20)
                {
                    
                }
            }
        }
        
    };
cs




1
    <uses-permission android:name="android.permission.INTERNET"/>
cs

' IOT 기반 응용 SW과정 > Android, Arduino' 카테고리의 다른 글

Day103  (0) 2016.08.17
Day102 안드로이드  (0) 2016.08.11
Day99 안드로이드 파일 복사  (0) 2016.08.08
Day98_2 안드로이드 OpenHelper  (0) 2016.08.05
Day98 안드로이드 db Select문  (0) 2016.08.05

액티비티 만들기

1. 액티비티를 상속받는 자바클래스 작성

2. MainFest에 액티비티를 등록

3. 액티비티가 사용할 레이아웃xml파일 작성(옵션)

4. 1의 onCreate메소드에서 3파일을 뷰로 연결.


R.java -> 안드로이드에서 사용하는 자원들을 자바코드에서 참조할 수 있도록 참조값을 갖는 연결고리

R.java는 어플리케이션의 패키지명으로 지정된 패키지 경로에 자동생성됨 (자원등록 중 에러가 발생하면 생성되지 않음)


액티비티가 속한 패키지명도 어플리케이션의 패키지명과 동일하게 한다

[장점]

1. R.java랑 같은 패키지에 위치해서 R클래스를 따로 임포트 해주지 않아도 됨

2. Manifest에 액티비티 등록할때 패키지명 생략가능

3. 1,2는 패키지 구조 복잡도가 올라가면 다시 분리 되겠지만 코드관리를 위해



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="패키지명"
    android:versionCode="1"
    android:versionName="1.0" >
 
    <uses-sdk
        android:minSdkVersion="16"
        android:targetSdkVersion="20" />
 
    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity android:name=".MainActivity"></activity>
                              .으로 시작하면 앞에 어플의 패키지명 
    </application>
 
</manifest>
cs

activity태그는 필수로 name속성을 가져야하고 name속성의 값에는 사용할 자바 클래스 파일(Activity를 상속받은)을 지정해야 됨

엑티비티는 어플리케이션의 구성요소이자 하나의 화면단위이고 명령처리흐름을 갖음

어플리케이션은 최소 하나의 메인엑티비티를 가져야하고 메인엑티비티가 되는 녀석을 Intent-filter에 메인속성과 런처 속성을 가져야됨


1
2
3
4
            <intent-filter >
                <action android:name="android.intent.action.MAIN"/>
                <category android:name="android.intent.category.LAUNCHER"/>
            </intent-filter>
cs



7
8
9
10
public class MainActivity extends Activity{
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        // TODO Auto-generated method stub
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }
}
 
cs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<?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="match_parent"
    android:orientation="vertical" >
    <TextView 
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="안녕 안드로이도"
        android:id="@+id/tv"
        /> id 만들어놓기
    <button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="버튼이닷"
        android:id="@+id/btn"
        />
</LinearLayout>
cs

1
2
   TextView tv =(TextView) findViewById(R.id.tv);
   Button btn = (Button) findViewById(R.id.btn);
cs

xml에 정의한 UI 위젯의 참조값 얻기

1
2
3
4
5
6
7
8
9
        btn.setOnClickListener(new View.OnClickListener() {
            
            @Override
            public void onClick(View v) {
                // TODO Auto-generated method stub
                tv.setText("Bye Android");
                
            }
        });        
cs


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
    <TextView
        android:id="@+id/tv"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="나이를 입력하세요" />
 
    <EditText
        android:id="@+id/num"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:ems="10"
        android:inputType="numberSigned" />
 
    <Button
        android:id="@+id/btn"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="버튼" />
 
    <TextView
        android:id="@+id/age"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />
cs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class MainActivity extends Activity{
    private EditText inputAge;
    private Button btn;
    private TextView result;
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        // TODO Auto-generated method stub
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        
        inputAge = (EditText) findViewById(R.id.num);
        btn = (Button) findViewById(R.id.btn);
        result = (TextView) findViewById(R.id.age);
        //지금은 이름을 대충 지었는데 id값들은 신중하게 잘 지어야됨 
        //모든 xml파일에서 하나의 id 네임스페이스를 사용함
        
cs


' IOT 기반 응용 SW과정 > Android, Arduino' 카테고리의 다른 글

Day89 안드로이드 엑티비티 전환  (0) 2016.07.25
Day88  (0) 2016.07.22
Day87  (0) 2016.07.21
Day86  (0) 2016.07.20
Day84 안드로이드  (0) 2016.07.18

+ Recent posts