안드로이드 스튜디오 뉴스앱 만들기 (NEWS API, Fresco, Volley, JSon )

2019. 12. 21. 23:112020/Android App Develop

NEWS API홈페이지에서 RecyclerView의 각 항목들에 넣은 데이터들을 가져온다.

이 때, Volley를 통한 HTTP통신으로 Emulator와 Web을 연결, JSon형식의 데이터를 가져오며 Fresco를 이용해 이미지 관리

 

 

<1> build.gradle (Module: app) - Fresco, Volley ( *디자인을 위한 CardView )

dependencies{

    implementation "androidx.cardview:cardview:1.0.0"
    implementation 'com.facebook.fresco:fresco:1.11.0'
    implementation 'com.android.volley:volley:1.1.0'

}

 

 

<2> 데이터를 얻어오는 getNews()함수를 생성 ( NewsActivity.java )

=> 사용자가 앱 실행 시 activity_news.xml과 NewsActivity.java가 실행되고 이 때 데이터를 얻어와 화면에 뿌린다

 

먼저 NewsData클래스를 생성해서 뉴스의 제목, 이미지 주소, 뉴스의 내용을 담을 수 있는 변수들을 선언

<NewsData.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
package com.example.myapplication;
 
 
public class NewsData implements Serializable {
 
    private String title;
    private String urlToImage;
    private String content;
 
    public NewsData(){
 
    }
 
    public String getTitle() {
        return title;
    }
    public String getUrlToImage() {
        return urlToImage;
    }
    public String getContent() {
        return content;
    }
 
    public void setTitle(String title) {
        this.title = title;
    }
    public void setUrlToImage(String urlToImage) {
        this.urlToImage = urlToImage;
    }
 
    public void setContent(String content) {
        this.content = content;
    }
 
}
http://colorscripter.com/info#e" target="_blank" style="color:#e5e5e5text-decoration:none">Colored by Color Scripter

 

<NewsActivity> - getNews()함수 추가

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
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
package com.example.myapplication;
 
 
 
 
 
 
 
 
public class NewsActivity extends AppCompatActivity {
 
    private RecyclerView mRecyclerView;
    private RecyclerView.Adapter mAdapter;
    private RecyclerView.LayoutManager mLayoutManager;
 
    RequestQueue queue;
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_news);
        mRecyclerView =  findViewById(R.id.my_recycler_view);
       mRecyclerView.setHasFixedSize(true);
        mLayoutManager = new LinearLayoutManager(this);
        mRecyclerView.setLayoutManager(mLayoutManager);
 
        queue = Volley.newRequestQueue(this);
        getNews();
    }
 
    public void getNews() {
 
 
        // Request a string response from the provided URL.
        StringRequest stringRequest = new StringRequest(Request.Method.GET, url,
                new Response.Listener<String>() {
                    @Override
                    public void onResponse(String response) {
 
                        Log.d("NEWS", response);
 
                        try {
                            /*
                            response
                               "{key1:"--",key2:"--",
                                articles:[{title:"--",author:"--",urlToImage:"--",content:"--"...},{...},...]
                                }"
                            */
                            // JSonString => JSon
                            JSONObject jsonObj = new JSONObject(response);
 
                            // JSon 객체 안 의 JSon객체들을 담고있는 JSonArray 객체 get (key값으로 가져옴)
                            JSONArray arrayArticles = jsonObj.getJSONArray("articles");
 
                            /* articles 배열 요소(JSon 객체) 는 많은 키와 데이터를 가지고 있기에 필요한
                               3가지만 사용하기 위해서 NewsData클래스를 생성
                            */
                            List<NewsData> news = new ArrayList<>();
 
                            for(int i = 0, j = arrayArticles.length(); i < j; i++) {
                                // articles배열 내의 각 요소(JSon 객체)들을 가져옴
                                JSONObject obj = arrayArticles.getJSONObject(i);
 
                                Log.d("NEWS", obj.toString());
 
                                NewsData newsData = new NewsData();
                                newsData.setTitle(obj.getString("title"));
                                newsData.setUrlToImage(obj.getString("urlToImage"));
                                newsData.setContent(obj.getString("content"));
 
                                // ArraryList(news) : 각 뉴스들의 제목,이미지주소,내용들이 포함된 NewsData객체들의 배열
                                news.add(newsData);
 
                            }
 
                            // Adapter 연결 ! (*context는 Freso를 위해서 인자에 추가)
                            mAdapter = new MyAdapter(news,NewsActivity.this);
                            mRecyclerView.setAdapter(mAdapter);
 
 
 
                        } catch (JSONException e) {
                            e.printStackTrace();
                        }
 
 
 
                    }
                }, new Response.ErrorListener() {
            @Override
            public void onErrorResponse(VolleyError error) {
 
            }
        });
 
        // Add the request to the RequestQueue.
        queue.add(stringRequest);
 
    }
 
}
http://colorscripter.com/info#e" target="_blank" style="color:#e5e5e5text-decoration:none">Colored by Color Scripter

 

<MyAdapter> - NewsActivity에서 데이터를 MyAdapter로 전달 -> MyAdapter에서 RecyclerView와 그 데이터를 관리

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
package com.example.myapplication;
 
import android.content.Context;
 
 
 
 
 
public class MyAdapter extends RecyclerView.Adapter<MyAdapter.MyViewHolder> {
    private List<NewsData> mDataset;
 
    /* 리스트 내의 각 항목들을 관리하는 ViewHolder class*/
 
    public static class MyViewHolder extends RecyclerView.ViewHolder {
        // each data item is just a string in this case
        public TextView TextView_title;
        public TextView TextView_content;
        // Fresco에서 사용하는 전용 이미지 component
        public SimpleDraweeView ImageView_news;
 
 
        /* 가져오는 layout에서 id값을 통해 해당 Component를 가져와 변수에 저장 */
        public MyViewHolder(View v) {
            super(v);
            TextView_title = v.findViewById(R.id.TextView_title);
            TextView_content = v.findViewById(R.id.TextView_content);
            ImageView_news = v.findViewById(R.id.ImageView_news);
        }
    }
 
    // Provide a suitable constructor (depends on the kind of dataset)
    /* NewsActivity에서 Adapter와 매칭시 사용하는 사용자이다
       이 때 NewsActivity의 데이터들이 데이터배열을 통해 전달되어진다
    */
 
    public MyAdapter(List<NewsData> myDataset,Context context) {
 
        mDataset = myDataset;
        Fresco.initialize(context);     // Fresco 사용을 위한 초기화
    }
    /*
          mAdapter = new MyAdapter(news,NewsActivity.this);
          mRecyclerView.setAdapter(mAdapter);
           => news에 대한 데이터들은 mDataset에 저장되고 RecyclerView와 Adapter매칭 
    */
    
    
    @Override
    public MyAdapter.MyViewHolder onCreateViewHolder(ViewGroup parent,
                                                     int viewType) {
        /* 리스트의 각 항목에 입혀줄 디자인을 생성한다 즉, create a new view
           setContentView(R.layout.xxx) 처럼 xml 매칭, 하지만 RecycleView의 특정 부분만 변경시킬 때는
           효율성을 위해 inflate함수를 사용
           사용할 xml(row_news)의 최상위 layout을 이용
         * */
        androidx.constraintlayout.widget.ConstraintLayout v
                = (androidx.constraintlayout.widget.ConstraintLayout) LayoutInflater.from(parent.getContext())
                .inflate(R.layout.row_news, parent, false);
 
/* row_news에서 components를 가져와 MyViewHolder객체의 변수들에 저장된다*/
        MyViewHolder vh = new MyViewHolder(v); 
        return vh;
    }
 
    @Override
    public void onBindViewHolder(MyViewHolder holder, int position) {
        
        NewsData news = mDataset.get(position);     // mDataset리스트에서 순서대로 NewsData객체 가져옴
 
// newsData클래스의 getter로 값 획득 후 row_news.xml의 component에 값 셋팅
        holder.TextView_title.setText(news.getTitle());         
        holder.TextView_content.setText(news.getContent());
 
        Uri uri = Uri.parse(news.getUrlToImage());      // Fresco 
        holder.ImageView_news.setImageURI(uri);         // 이미지 셋팅
    }
 
    // Return the size of your dataset (invoked by the layout manager)
    @Override
    public int getItemCount() {
        return mDataset.size();
    }
 
}
http://colorscripter.com/info#e" target="_blank" style="color:#e5e5e5text-decoration:none">Colored by Color Scripter

 

<row_news.xml> Fresco사용을 위해 약간의 변화가 있음

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
<?xml version="1.0" encoding="utf-8"?>
    xmlns:tools="http://schemas.android.com/tools"
    xmlns:fresco="http://schemas.android.com/apk/res-auto" // for fresco
 
    android:layout_width="match_parent"
    android:layout_height="200dp"
    android:orientation="vertical"
    tools:context=".MainActivity"
    >
 
 
// RecyclerView리스트의 요소들의 디자인
       <androidx.cardview.widget.CardView
            xmlns:card_view="http://schemas.android.com/apk/res-auto"
            android:id="@+id/card_view"
            android:layout_gravity="center"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_margin="20dp"
            card_view:cardCornerRadius="4dp">
 
            <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:orientation="vertical">
                <RelativeLayout
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content">
                    <!--뉴스 이미지를 넣을 것-->
 
// 이미지를 받는 component
                    <com.facebook.drawee.view.SimpleDraweeView
                        android:id="@+id/ImageView_news"
                        android:layout_width="match_parent"
                        android:layout_height="130dp"
 
                    ></com.facebook.drawee.view.SimpleDraweeView>
 
 
                    <TextView
                        android:id="@+id/TextView_title"
                        android:layout_width="match_parent"
                        android:layout_height="wrap_content"
                        android:text="Hello, this is example of RecycleView"
                        android:layout_alignBottom="@+id/ImageView_news"
                        android:textSize="20dp"
                        android:textStyle="bold"
                        android:background="#70000000"
                        android:paddingLeft="6dp"
                        android:paddingRight="6dp"
                        ></TextView>
                </RelativeLayout>
 
                <!--뉴스의 내용 일부를 적을 공간-->
                <TextView
                    android:id="@+id/TextView_content"
                    android:layout_width="match_parent"
                    android:layout_height="match_parent"
                    android:text="Contents part"
                    android:textSize="20dp"
                    android:paddingLeft="6dp"
                    android:paddingRight="6dp"
                    android:maxLines="2"
                    android:ellipsize="end"
                    android:gravity="center_vertical"
                    ></TextView>
            </LinearLayout>
        </androidx.cardview.widget.CardView>
</androidx.constraintlayout.widget.ConstraintLayout>

 

<앱 실행 결과>

- RelativeLayout에 있는 두 개의 components( Image와 Text )들이 겹쳐서 보임을 확인할 수 있고 아래에는 뉴스의 내용을 보여주는 TextView를 확인할 수 있고 아래에는 더 많은 뉴스들이 존재하며 RecyclerView의 기능 중 하나인 드래그를 통해서 아래 내용들을 확인할 수 있다

 

 

< JSON > - 키-값 쌍으로 이루어진 데이터 오브젝트를 전달하기 위한 개방형 표준 포맷

* JSonObect객체 JSonObject JSonObj = { Key_1: Data_1 , Key_2: Data_2 ... }   *키를통해서 해당 데이터로 접근한다

  String str = JSonObj.getString( Key ) 메서드를 통해 데이터 획득 가능.

 

* 하나의 키에 배열(articles)을 저장할 수 있다. 그 배열안에 JSonObject를 저장할 수 도 있다.

  JSonObejct JSonObj = { Key_1:Data_1, articles: [ {title: "", urlToImage: "", content}, { the same }, { the same } ] } 

  JSonArrary ArraryArticles = JSonObj.getJSonArrary( name:"articles" ) ( * JSon객체내의 배열 관리 )

  List<NewsData> news = new ArraryList<>();

  for( int i =0; i<ArraryArticles.length(); i++){

    NewsData newsData = new NewsData();

    JSonObject JSonObj = ArraryArticles.getJSonObject(i);

 

    newsData.setTitle( JSonObj.getString(name:"title") );

    newsData.setUrlToImage( JSonObj.getString(name:"urlToImage") );

    newsData.setContent( JSonObj.getString(name:"content") );

 

    news.add( newsData );

  }

* NewsData 클래스 객체를 가지는 ArraryList객체(news ) 각 요소들은 뉴스의 제목, 이미지, 내용을 가지고있다