[ Toy Project ] 현재 상영 영화 순위를 알아보자 (feat.Retrofit2) - Android Studio

ma.caron_g·2022년 8월 8일
0

Toy Project

목록 보기
1/3
post-thumbnail

참고한 사이트

[ API 키 발급 ]

최근에 영화를 보고
영화 API를 이용하여서 영화 순위를 볼 수 있는 App 만들어 API 연습을하면 좋겠다고 생각하여 만들어보았다.

우선,

영화진흥위원회에 접속을 하여

회원가입 후

"키 발급/관리" 창을 들어가 Key값을 받아준다.

그럼 위와 같은 KEY값이 발급되었다.

API를 호출하여 데이터를 다루는 안내는 아래 링크에 걸어두겠다.
(링크가 아닌 경우 파일을 다운 받으면 파일 안에 정보가 적혀있다.)

[ API 안내 ]


[ 안드로이드 스튜디오 ]

안드로이드 스튜디오에서 프로젝트를 하나 생성해준다.

우선 액티비티에 RecyclerView를 통해 데이터들을 표현해주어야하므로 activity_main.xmlRecyclerView를 선언해주고 Button 뷰를 하나 배치해준다.

준비

RecyclerViewRetrofit2를 사용하기 위해서는 Gradle에 아래 코드를 추가해준다.

implementation 'com.android.support:recyclerview-v7:28.0.0' //recyclerview

implementation 'com.squareup.retrofit2:retrofit:2.7.2' //retrofit2
implementation 'com.squareup.retrofit2:converter-gson:2.7.2'

서버에 통신하여 정보를 받아 사용할 것이므로 AndroidManifest.xml인터넷 접근 권한 허용을 해주어야한다.
아래 코드를 추가해준다.

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

<application
  android:usesCleartextTraffic="true" ...>

[ activity_main.xml ]

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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=".MainActivity">

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/rv_recyclerview"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
        android:orientation="horizontal"
        app:layout_constraintBottom_toTopOf="@+id/button"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <Button
        android:id="@+id/button"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="RecyclerView show"
        android:onClick="click_btn"
        app:layout_constraintBottom_toBottomOf="parent"
        tools:layout_editor_absoluteX="111dp" />

</androidx.constraintlayout.widget.ConstraintLayout>

위 와 같은 액티비티 화면이 만들어진다.

테마 색상은 여담으로
한 때 메가박스 아르바이트를 했었고 지금도 자주 애용해서 메가박스의 로고 색으로 테마색을 맞췄다.
(위에 타이틀은 보통 넣지 않지만 포트폴리오를 작성해야하므로 넣었습니다.)

이제 RecyclerView에 표시될 데이터들을 하나씩 어떻게 표현해줄지 recyclerview_item을 생성하여 만들어줄 것이다.

지금 만드는 건 데이터 하나를 어떤식으로 표현해줄지를 만드는 것이다.

[ recyclerview_item.xml ]

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="500dp"
    xmlns:tools="http://schemas.android.com/tools">

    <TextView
        android:id="@+id/tv_rank"
        android:layout_width="30dp"
        android:layout_height="30dp"
        android:background="#332666"
        android:gravity="center"
        android:textColor="#FFFFFF"
        android:textSize="24sp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.498"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintVertical_bias="0.429" />

    <TextView
        android:id="@+id/tv_movieNm"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textSize="20sp"
        android:textStyle="bold"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.498"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/tv_rank"
        app:layout_constraintVertical_bias="0.598"
        tools:text="movieName" />

    <TextView
        android:id="@+id/tv_openDt"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textSize="14sp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.498"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/tv_movieNm"
        app:layout_constraintVertical_bias="0.736"
        tools:text="2020-01-01" />
</androidx.constraintlayout.widget.ConstraintLayout>

포스터를 넣어주고 싶었지만 포스터를 담은 API를 찾지 못해 뷰 안에 순위를 넣기로 했다.
TextView는 위에서부터 [ 순위, 영화 제목, 개봉 날짜 ]를 표시해줄 것이다.

[ MyAdapter.java ]

RecyclerView와 앞에 만든 recyclerview_item의 뷰들을 연결해주기 위해 어댑터를 만들어준다.

package my.app.moviemovie;

import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;

import java.util.ArrayList;
import java.util.Map;

public class MyAdapter extends RecyclerView.Adapter<MyAdapter.MyViewHolder> {

	// 받은 딕셔너리 리스트들을 담을 배열 변수 선언
    private ArrayList<Map<String, Object>> items= new ArrayList<Map<String, Object>>();

	// 받은 데이터를 옮겨 담아준다.
    public MyAdapter(ArrayList<Map<String, Object>> resultList){
        this.items=resultList;
    }

	//데이터가 연결 된 리스트를 반환.
    @NonNull
    @Override
    public MyAdapter.MyViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        View itemView = LayoutInflater.from(parent.getContext()).inflate(R.layout.recyclerview_item , parent, false);
        return new MyViewHolder(itemView);
    }


	// 데이터들의 순서(position)에 맞는 데이터들끼리 `MyViewHolder`로 전달
    @Override
    public void onBindViewHolder(@NonNull MyViewHolder holder, int position) {
        Map<String, Object> item = items.get(position);
        holder.setItem(item);
    }

	// 받은 데이터들의 갯수를 반환.
    @Override
    public int getItemCount() {
        return items.size();
    }

	// `MyViewHolder` ->`RecyclerView`에 있는 뷰들을 연결.
    // `onBindViewHolder`에서 받은 값을 뷰들에 연결.
    public static class MyViewHolder extends RecyclerView.ViewHolder {
        public TextView tvRank, tvMovieNm, tvOpenDt;
        public MyViewHolder(View itemView) {
            super(itemView);
            tvRank=itemView.findViewById(R.id.tv_rank);
            tvMovieNm=itemView.findViewById(R.id.tv_movieNm);
            tvOpenDt=itemView.findViewById(R.id.tv_openDt);

        }
        public void setItem(Map<String, Object> item){

			//정보들을 확인하기 위해 로그를 찍어봄.
            Log.d("json Info. " , item.toString());
            //"rank", "movieNm", "openDt"은 Json파일에 저장되어 있던 key값
            tvRank.setText(item.get("rank").toString());
            tvMovieNm.setText(item.get("movieNm").toString());
            tvOpenDt.setText(item.get("openDt").toString());

        }
    }
}

[ RetrofitInterface.java ]

package my.app.moviemovie;

import java.util.Map;

import retrofit2.Call;
import retrofit2.http.GET;
import retrofit2.http.Header;
import retrofit2.http.Path;
import retrofit2.http.Query;

public interface RetrofitInterface {
 // @GET은 Http Method로, [ GET / POST / PUT / DELETE / HEAD ] 중 무슨 작업인지 표현
 // ()안에는  URI에서 URL을 제외한 End Point(URI)
@GET("/kobisopenapi/webservice/rest/boxoffice/searchDailyBoxOfficeList.json")
    Call<Map<String,Object>>
    //메소드명
    getBoxOffice
    	//@Query에서 String key에 해당하는 부분이 key에 값을 대입.
          (@Query("key") String key,
           @Query("targetDt") String targetDt);
  }
}

[ MainActivity.java ]

package my.app.moviemovie;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.RecyclerView;

import android.content.Context;
import android.os.Bundle;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import android.widget.Button;

import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Date;
import java.util.Map;

import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;

public class MainActivity extends AppCompatActivity
{
    private final String TAG = this.getClass().getSimpleName();

    private RecyclerView recyclerView;
    private RecyclerView.Adapter mAdapter;
    private String baseUrl = "http://www.kobis.or.kr";
    private String API_KEY = "발급받은 API키 값을 넣어주세요.";
    Retrofit retrofit;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

		// 입력한 날짜를 기준으로 현재 상영작 중 순위를 알려주는데, 입력한 날짜를 자동으로 현재 날짜로 맞춰놓으려고 선언
        LocalDate now = LocalDate.now();
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMdd");
        String formatedNow = Integer.toString(Integer.parseInt(now.format(formatter))-1);

		// 로그에 날짜 찍어보기
        Log.d("current-Date :", formatedNow);
        recyclerView = findViewById(R.id.rv_recyclerview);

		// 자바 객체를  json으로 표현해주기 위해 GSON 사용
        retrofit = new Retrofit.Builder()
                .baseUrl(baseUrl)
                .addConverterFactory(GsonConverterFactory.create())
                .build();
        RetrofitInterface retrofitInterface = retrofit.create(RetrofitInterface.class);

        retrofitInterface.getBoxOffice(API_KEY, formatedNow).enqueue(new Callback<Map<String, Object>>() {
            public void onResponse(Call<Map<String, Object>> call, Response<Map<String, Object>> response) {

				//'boxOfficeResult'에서 딕셔너리를 가져와 저장.
                Map<String, Object> boxOfficeResult = (Map<String, Object>) response.body().get("boxOfficeResult");
                //'boxOfficeResult'중 'dailyBoxOfficeList'라는 키를 가진 딕셔너리를 리스트로 저장 후, 그 리스트들을 어댑터에 보내 어댑터와 연관된 값을 가지는 값들을 뽑아준다.
                ArrayList<Map<String, Object>> jsonList = (ArrayList) boxOfficeResult.get("dailyBoxOfficeList");
                mAdapter = new MyAdapter(jsonList);

            }

            @Override
            public void onFailure(Call<Map<String, Object>> call, Throwable throwable) {

            }
        });

    }
    //버튼을 누르면 값들이 `recyclerview`에 뿌려지도록한다.
    public void click_btn(View view) {
        recyclerView.setAdapter(mAdapter);
    }

}

사이트에서 제공해주는 정보를 살펴보면,
'boxOfficeResult'를 KEY값으로 하여 그 안에 또 딕셔너리가 들어있다. 그 안에서 'dailyBoxOfficeList'를 키로 가지는 딕셔너리들 중 원하는 값들을 뽑으면 된다.

나는 RecyclerViewHorizontal 값으로 설정하여 리스트들을 수평으로 넘기면서 볼 수 있다.

profile
다른 사람이 만든 것을 소비하는 활동보다, 내가 생산적인 활동을 하는 시간이 더 많도록 생활화 하자.

0개의 댓글