오늘은 HttpURLConnection 에 대해 포스팅 해보겠다. 


포스팅 하게 된 이유는 저번에 잘 사용하던 httpClient(아파치 라이브러리)가 deprecated 되었기 때문이다.


갑자기 사라져서 당황했었다... 아래 내용은 Google Developer 에서 발췌한 android 6.0 변화에서 httpClient에 대한 이야기다. 


Apache HTTP Client Removal


Android 6.0 release removes support for the Apache HTTP client. If your app is using this client and targets Android 2.3 (API level 9) or higher, use the HttpURLConnection class instead. This API is more efficient because it reduces network use through transparent compression and response caching, and minimizes power consumption. To continue using the Apache HTTP APIs, you must first declare the following compile-time dependency in your build.gradle file:

android {
    useLibrary
'org.apache.http.legacy'
}


요약하자면, 위와 같이 gradle에 해당 라이브러리를 추가하면 httpClient 쓸수는 있다. 또 말하기를, httpClient의 기능은 많지만 무겁다, 


그리고 안드로이드에서는 조금 오바(?)스러운 httpClient보다는,


안드로이드에 적합한 API인 HttpURLConnection을 사용하라는 이야기다.(해당 이슈는 예전부터 나오던 이슈긴 하다.)


뭐.. httpClient가 편리하지만 저렇게 권장하지 않는 API를 쓰기에는 유지보수와 기능에 문제가 있다고 판단, 바로 HttpURLConnection으로 옮겼었다.


서론은 여기까지 하고, 시작해 보자. HttpURLConnection도 굉장히 쉽다.


먼저 인터넷 환경이 필요한 작업이므로 AndroidManifest.xml 파일에 


<uses-permission android:name="android.permission.INTERNET"/> 을 작성해 인터넷 환경을 만들어준다.


이제 MainActivity에 네이버의 웹 정보를 받아오는 코드를 작성해보자.


new AsyncTask<Void,Void,Void>(){
@Override
protected void onPreExecute() {
super.onPreExecute();
strUrl = "http://www.naver.com"; //탐색하고 싶은 URL이다.
}

@Override
protected Void doInBackground(Void... voids) {
try{
Url = new URL(strUrl); // URL화 한다.
HttpURLConnection conn = (HttpURLConnection) Url.openConnection(); // URL을 연결한 객체 생성.
conn.setRequestMethod("GET"); // get방식 통신
conn.setDoOutput(true); // 쓰기모드 지정
conn.setDoInput(true); // 읽기모드 지정
conn.setUseCaches(false); // 캐싱데이터를 받을지 안받을지
conn.setDefaultUseCaches(false); // 캐싱데이터 디폴트 값 설정

strCookie = conn.getHeaderField("Set-Cookie"); //쿠키데이터 보관

InputStream is = conn.getInputStream(); //input스트림 개방

StringBuilder builder = new StringBuilder(); //문자열을 담기 위한 객체
BufferedReader reader = new BufferedReader(new InputStreamReader(is,"UTF-8")); //문자열 셋 세팅
String line;

while ((line = reader.readLine()) != null) {
builder.append(line+ "\n");
}

result = builder.toString();

}catch(MalformedURLException | ProtocolException exception) {
exception.printStackTrace();
}catch(IOException io){
io.printStackTrace();
}
return null;
}

@Override
protected void onPostExecute(Void aVoid) {
super.onPostExecute(aVoid);
System.out.println(result);
}
}.execute();

AsynTask는 통신을 할 때 필요한 클래스이다. 이해하면 사용하기 쉽지만, 모르는 사람은 일단 따라 써보기로 하자.


protected void onPreExecute() 메서드 안에는 통신을 하기전 필요한 정보를 셋팅하는 구간이다.


우리가 탐색할 네이버 주소를 적었다.


protected Void doInBackground(Void... voids) 이 메서드가 실제로 통신 할때 작동하는 부분이다.


왠만한 설명은 주석처리 해놨다. 좀더, 정리를 해주자면..


Url = new URL(strUrl); // URL화 한다.
HttpURLConnection conn = (HttpURLConnection) Url.openConnection(); // URL을 연결한 객체 생성.


이 부분이 해당 URL(예시는 네이버)의 정보를 담고 있는 객체를 생성하는 부분이다.


conn.setRequestMethod("GET"); // get방식 통신
conn.setDoOutput(true); // 쓰기모드 지정
conn.setDoInput(true); // 읽기모드 지정
conn.setUseCaches(false); // 캐싱데이터를 받을지 안받을지
conn.setDefaultUseCaches(false); // 캐싱데이터 디폴트 값 설정


이 부분이 해당 통신을 위한 셋팅 부분이다. HttpURLConnection은 스트림 기반이라 셋팅 할 것이 많다.


strCookie = conn.getHeaderField("Set-Cookie"); //쿠키데이터 보관

이 부분은 세션지정을 위한 쿠키값 저장을 하는 부분이다.


httpClient는 쿠키값을 알아서 저장해줬지만 HttpURLConnection은 따로 저장 관리를 해줘야한다.


InputStream is = conn.getInputStream(); //input스트림 개방

StringBuilder builder = new StringBuilder(); //문자열을 담기 위한 객체
BufferedReader reader = new BufferedReader(new InputStreamReader(is,"UTF-8")); //문자열 셋 세팅
String line;

while ((line = reader.readLine()) != null) {
    builder.append(line+ "\n");
}

 이 부분은 웹 정보를 파싱하는 부분이다. 중요한 점은 웹 정보 마다 다른 문자열 셋일 수 있으므로 맞는 문자열 셋팅을 해줘야 한다.


protected void onPostExecute(Void aVoid)

이 메서드 부분이 해당 통신이 끝난 후 통신작업이 아닌 마무리 작업(UI작업, 사용자 정의 작업 등)을 하는 부분이다.


예시에서는 콘솔에 출력하는 메서드를 썻다.


실행해보면 네이버의 정보를 콘솔에 출력하는 것을 볼 수 있다.


oRTK : { "t": "2015-11-17T12:25Z", "s": "2015.11.17. (화) 12:25 PM", "d": [ { "k": "오마이비너스", "c": "up", "a": "상승", "n": "72" }, 

{ "k": "신민아", "c": "up", "a": "상승", "n": "99" }, { "k": "진세연", "c": "up", "a": "상승", "n": "225" }, 

{ "k": "이정재", "c": "up", "a": "상승", "n": "216" }, { "k": "육룡이 나르샤 결방", "c": "up", "a": "상승", "n": "174" }, 

{ "k": "다이나믹듀오", "c": "up", "a": "상승", "n": "216" }, { "k": "풍선껌", "c": "up", "a": "상승", "n": "63" }, 

{ "k": "첼시 리", "c": "up", "a": "상승", "n": "348" }, { "k": "먹는존재", "c": "up", "a": "상승", "n": "150" }, 

{ "k": "명지전문대", "c": "up", "a": "상승", "n": "93" } ] },


콘솔에 찍힌 정보 중간에 실시간 검색어 정보를 발견했다. (실시간 정보는 네이버에서 제공하는 API가 있다.)


시간대가 틀려 찍히는 정보가 틀리겠지만... 무튼 성공 한걸 알 수 있다.


해당 예시는 get 방식으로 웹 정보를 받아오는 방식이다.


추후에 post방식으로 웹 정보를 이용하는 방법도 포스팅 하겠다.



해당 프로젝트는 https://github.com/Mommoo/ExampleCode/tree/master/HttpURLConnection 에서 받을 수 있다.






포스팅이 도움 되셨다면, 커피 한잔 후원해주세요!
더 좋은 포스팅 작성에 큰 힘이 됩니다.

Buy me a coffeeBuy me a coffee




리눅스 서버를 구축한 후, Mysql 데이터베이스 환경을 만들었다.


Java로 서버연동을 해보려고 했지만, 잘 되지 않았다.


이유는 간단 했다. 데이터베이스를 초기에 만들때 접근 사용자 셋팅은 외부접근을 허용하지 않기 때문이다.


이유를 알았으니, 해결해보자.


GRANT ALL PRIVILEGES ON *.* TO 'root'@'%';


위의 명령어를 실행 했을 경우, root 사용자는 모든호스트(%)에게 모든 권한을 허용하겠다는 의미이다.


조금더 응용해서 특정 IP 대역만을 허용하고 싶다 하면,


GRANT ALL PRIVILEGES ON *.* TO 'root'@'192.168.%';


이런식으로 명령어를 써주면 되겠다. 192.168로 시작하는 IP대역의 외부접근을 허용하겠다는 의미이다.


권한설정후 Java로 연동해보니 잘 되었다.



포스팅이 도움 되셨다면, 커피 한잔 후원해주세요!
더 좋은 포스팅 작성에 큰 힘이 됩니다.

Buy me a coffeeBuy me a coffee



이번 포스팅은 자바의 생성자(constructor)에 관해 알아보자.


생성자는 자바뿐만 아니라 객체지향언어의 중요한 구조이기 때문에, 자바에 국한짓지 말고, 크게 이해하면 좋다.


생상자의 구조를 자바언어를 통해 설명하고자 한다.


먼저, 하나의 변수를 사용한다고 가정 해보자.


 int a; 



위의 선언한 int형 변수 a는 의미가 있는가? 


답은 No이다. 이유는 초기화를 하지 않았기 때문이다.


int a=10;


위와 같이 초기화 해야 비로소 변수 a는 상수 10을 가리키는 변수가 된 것이다. 


이렇게 의미있는 데이터를 넣는것 을 자바에서는 초기화라고 명명한다.


그렇다면, 하나의 클래스(class)를 사용 한다고 가정 해보자. 


위의 예시 처럼 의미있는 클래스를 만들기 위해 서는 초기화 작업을 거쳐야 할 것이다.


그렇다면 무엇을 초기화 해야할까? 라는 질문에 봉착한다.


클래스는 크게 나누자면 멤버변수 와 메서드 이다.


class Test{

    public int num;
    public String str;
    
    public Test(int num,String str){
        this.num = num;
        this.str = str;    
    }

    public void print(){
        System.out.println("num은"+num+"입니다. , str은"+str"입니다.");
    }
}

     위의 예시는 3번,4번이 멤버변수 , 6~9번,11~13번 까지가 메서드 이다. 


이러한 클래스를 초기화 하려고 한다. 예시 클래스에서 초기화 하는 메서는 Test 메서드이다.


매개변수로 num 과 str 을 받아 클래스의 멤버변수에 값을 넣는 메서드이다. 앞에 this 를 붙여주면 클래스 안의 멤버변수 str을


안붙여주면 매개변수로 받는 str을 의미한다.( 변수의 이름이 같을 경우 구분짓기 위해 this를 쓴다.)


이 메서드는 특이하게 Test 클래스의 이름과 똑같은 Test이름을 가지는 메서드인데,


이러한 메서드를 우리는 생성자라고 부른다.


생성자는 특이하게 함수의 리턴형이 존재 하지 않고 앞서 쓴 예시와 같이 클래스의 이름과 같다.


클래스는 이러한 생성자를 토데로 초기화를 한다. 물론 꼭 생성자를 통해서 멤버변수를 초기화하지 않아도 된다.


하지만, 보통은 생성자를 통해 클래스의 필요한 정보를 초기화 한다 정도만 알면 되겠다.





다음 포스팅은 생성자를 어떻게 사용하는지, 생성자에 관해 좀더 자세히 다루겠다.




'Java' 카테고리의 다른 글

JAVA Static이란?  (2) 2016.03.29
자바 enum 열거형  (0) 2016.01.27
JAVA - 익명클래스(Anonymous class)란?  (3) 2016.01.20
JAVA의 삼항연산자  (4) 2015.12.11
JAVA의 생성자 (2)  (2) 2015.11.17

포스팅이 도움 되셨다면, 커피 한잔 후원해주세요!
더 좋은 포스팅 작성에 큰 힘이 됩니다.

Buy me a coffeeBuy me a coffee




http://mommoo.tistory.com/1 ( RecyclerView , CardView 사용하기.(1) )




2편이다. 처음 읽는 독자는 위의 경로의 포스팅을 먼저 읽기를 권한다.


RecyclerView에 필요한 Adpater를 선언할 것이다.

참조한 구글 문서는 단순히 TextView만을 이용한 예제이다.


본 게시물은 추가적으로 image를 넣어 image와 text로 구성된 예제임을 밝힌다.



MyAdapter.java


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
public class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder> {
    private ArrayList<MyData> mDataset;
 
    // Provide a reference to the views for each data item
    // Complex data items may need more than one view per item, and
    // you provide access to all the views for a data item in a view holder
    public static class ViewHolder extends RecyclerView.ViewHolder {
        // each data item is just a string in this case 
        public ImageView mImageView;
        public TextView mTextView;
 
        public ViewHolder(View view) {
            super(view);
            mImageView = (ImageView)view.findViewById(R.id.image);
            mTextView = (TextView)view.findViewById(R.id.textview);
        }
    }
 
    // Provide a suitable constructor (depends on the kind of dataset)
    public MyAdapter(ArrayList<MyData> myDataset) {
        mDataset = myDataset;
    }
 
    // Create new views (invoked by the layout manager)
    @Override
    public MyAdapter.ViewHolder onCreateViewHolder(ViewGroup parent,
                                                   int viewType) {
        // create a new view
        View v = LayoutInflater.from(parent.getContext())
                               .inflate(R.layout.my_view, parent, false);
        // set the view's size, margins, paddings and layout parameters
        ...
        ViewHolder vh = new ViewHolder(v);
        return vh;
    }
 
    // Replace the contents of a view (invoked by the layout manager)
    @Override
    public void onBindViewHolder(ViewHolder holder, int position) {
        // - get element from your dataset at this position
        // - replace the contents of the view with that element
        holder.mTextView.setText(mDataset.get(position).text);
        holder.mImageView.setImageResource(mDataset.get(position).img);
    }
 
    // Return the size of your dataset (invoked by the layout manager)
    @Override
    public int getItemCount() {
        return mDataset.size();
    }
}
 
class MyData{
    public String text;
    public int img;
    public MyData(String text, int img){
        this.text = text;
        this.img = img;
    }
}
cs



MyAdpater.class를 선언하고, RecyclerView.Adapter를 상속 받았다.


MyAdpater안에 직접 구현한 ViewHolder 클래스를 제네릭으로 받는 구조이다.  물론 직접 만드는 ViewHolder도 


ReclerView.ViewHolder를 상속받아야 한다.


(ViewHolder는 ListView를 사용할 당시, RecylerView처럼 View를 효율적으로 쓰기 위한 디자인 패턴중 하나였다. 

리소스를 제법 잡어먹는 findViewById()를 적게 호출하기 위함이다. RecyclerView 에서는 적극적으로 ViewHolder 패턴을 사용하라고 권장한다. )


ViewHolder 클래스는 RecyclerView의 item에 들어갈 view를 받은후 그 view 안에 있는 ImageView와 TextView를 초기화 한다.


그다음은 MyAdapter 생성자가 보이는데, 매개변수로 ArrayList<MyData> 객체를 받는다. MyData 클래스는 data-set을 위한 클래스로


해당 예제에 맨 아래에 생성했다.




중요한 내용은 지금부터이다.


onCreateViewHolder 메서드안의 내용을 잘 바꾸어야 내가 원하는 결과물이 나온다.


첫번째로, View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.my_view, parent, false); 는


앞서 말한 ViewHolder에 넣어줄 view를 찾는 과정이다. my_view라는 xml에는 cardview가 들어갈 예정이다.


이 view를 넣기위한 ViewHolder를 다음과 같이 선언한 후 넣는다.


 ViewHolder vh = new ViewHolder(v);


그다음 onBindViewHolder 메서드를 보자. 이 메서드는 RecyclerView의 item의 셋팅과 사용자가 스크롤링 할때, 호출되는 메서드이다.


우리가 원하는 데이터가 포지션별로 ArrayList<MyData>에 저장되어 있다. 이러한 데이터를 포지션별로 보여주는 것을 보장해준다.


마지막으로 MyData 클래스이다. 우리가 원하는 image와 text 데이터를 보관하기 위한 데이터 저장소 개념으로 보면 된다.



다음은 위에서 소개한 my_view.xml을 코딩 해보자.



my_view.xml


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
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:card="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <android.support.v7.widget.CardView
        android:id="@+id/cardview"
        card:cardCornerRadius="3dp"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">
 
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical">
        <ImageView
            android:scaleType="fitXY"
            android:layout_width="match_parent"
            android:layout_height="200dp"
            android:id="@+id/image"/>
        <TextView
            android:id="@+id/textview"
            android:gravity="center|left"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:padding="10dp"/>
        </LinearLayout>
    </android.support.v7.widget.CardView>
</RelativeLayout>
cs



위의 CardView 위젯을 보면 android: 대신 card: 인자가 보이는데, 


이 인자는 부모뷰에 xmlns:card="http://schemas.android.com/apk/res-auto"


등록을 해주면 된다. cardCornerRadius 값은 모서리 둥근 정도를 결정한다.


해당 카드뷰 view 아래는 데이터를 보여줄(image,text) 하위 view들을 지정했다.


cardview 자체는 FrameLayout를 상속 받기 때문에 따로 LinearLayout을 선언하여 수직 정렬 하였다.


다 끝났다. 이제 MyActivity로 돌아가 데이터를 넣어본다.



MyActivity.java


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
public class MyActivity extends Activity {
    private RecyclerView mRecyclerView;
    private RecyclerView.Adapter mAdapter;
    private RecyclerView.LayoutManager mLayoutManager;
    private ArrayList<MyData> myDataset;    
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.my_activity);
        mRecyclerView = (RecyclerView) findViewById(R.id.my_recycler_view);
 
        // use this setting to improve performance if you know that changes
        // in content do not change the layout size of the RecyclerView
        mRecyclerView.setHasFixedSize(true);
 
        // use a linear layout manager
        mLayoutManager = new LinearLayoutManager(this);
        mRecyclerView.setLayoutManager(mLayoutManager);
 
        // specify an adapter (see also next example)
        myDataset = new ArrayList<>();
        mAdapter = new MyAdapter(myDataset);
        mRecyclerView.setAdapter(mAdapter);
        
        myDataset.add(new MyData("#InsideOut", R.mipmap.insideout));
        myDataset.add(new MyData("#Mini", R.mipmap.mini));
        myDataset.add(new MyData("#ToyStroy", R.mipmap.toystory));
 
    }
    ...
}
cs


컴파일을 해보면...




멋진 카드효과와 함께 잘 나온다.


해당 프로젝트는 https://github.com/Mommoo/ExampleCode/tree/master/RecyclerView  에서 받을 수 있다.




포스팅이 도움 되셨다면, 커피 한잔 후원해주세요!
더 좋은 포스팅 작성에 큰 힘이 됩니다.

Buy me a coffeeBuy me a coffee

+ Recent posts