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
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class PersonAdapter extends ArrayAdapter<Person>{
 
    //BaseAdapter가 리스트뷰의 어뎁터가 되기 위한 기본 부모클래스이지만 
    //관리하는 데이터가 배열에 특화되있는 어레이어뎁터를 상속받는게 작업이 쉽다.
    
    private Context context;
    private int resource;
    private List<Person> personList;
    
    public PersonAdapter(Context context, int resource, List<Person> objects) {
        super(context, resource, objects);
        // TODO Auto-generated constructor stub
        this.context = context;
        this.resource = resource;
        this.personList = objects;
    }
        
}
cs


1
2
 //BaseAdapter는 추상클래스, 어뎁터로서의 동작에 대한 템플릿은 구현되 있지만
 //getView, getItem, getItemPosition등등.. 핵심동작은 사용자가 상속받아서 정의해야됨
cs

ArrayAdapter는 바로 사용가능한 완성폼

getView만 우리 뷰에 맞게 재정의하면됨

1
2
3
4
5
6
7
8
9
10
11
    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        // TODO Auto-generated method stub
//        return super.getView(position, convertView, parent);
        if(convertView == null)
        {
            LayoutInflater inflater =(LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            convertView = inflater.inflate(resource, parent, false);
        }
        return convertView;
    }
cs


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
        callIv.setOnClickListener(new View.OnClickListener() {
            
            @Override
            public void onClick(View v) {
                // TODO Auto-generated method stub
                Intent intent = new Intent(Intent.ACTION_CALL,Uri.parse("tel:" + person.getPhoneNum()));
                //<uses-permission android:name="android.permission.CALL_PHONE"/>
                //manifest에서 권한추가
                context.startActivity(intent);   전화걸기
            }
        });
        smsIv.setOnClickListener(new View.OnClickListener() {
            
            @Override
            public void onClick(View v) {                 문자 창으로 가기
                // TODO Auto-generated method stub
                Intent sendIntent = new Intent(Intent.ACTION_VIEW);
                sendIntent.putExtra("address", person.getPhoneNum());//받는사람
                sendIntent.setType("vnd.android-dir/mms-sms");
                context.startActivity(sendIntent);
            }
        });
cs


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

Day98 안드로이드 db Select문  (0) 2016.08.05
Day97  (0) 2016.08.04
Day94 안드로이드 listview  (0) 2016.08.02
Day93 AlertDialog  (0) 2016.07.29
Day92  (0) 2016.07.28

+ Recent posts