본문 바로가기
Aandroid Studio/Open Api

[android] youtube api를 사용한 썸네일, 제목 추출, 페이징 완성본

by 코끼리똥11 2024. 6. 12.

MainActivity

package com.example.youtube;

import android.app.DownloadManager;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ProgressBar;
import android.widget.Toast;

import androidx.activity.EdgeToEdge;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.graphics.Insets;
import androidx.core.view.ViewCompat;
import androidx.core.view.WindowInsetsCompat;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;

import com.android.volley.Request;
import com.android.volley.RequestQueue;
import com.android.volley.Response;
import com.android.volley.VolleyError;
import com.android.volley.toolbox.JsonObjectRequest;
import com.android.volley.toolbox.Volley;
import com.example.youtube.adapter.PostingAdapter;
import com.example.youtube.model.Posting;
import com.google.android.material.snackbar.Snackbar;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import java.util.ArrayList;

public class MainActivity extends AppCompatActivity {
    // 멤버변수
    Button btn;
    EditText editText;
    ProgressBar progressBar;
    RecyclerView recyclerView;

    ArrayList<Posting> postingArrayList = new ArrayList<>();
    PostingAdapter adapter;

    String text;

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

        btn = findViewById(R.id.btn);
        editText = findViewById(R.id.editText);
        progressBar = findViewById(R.id.progressBar);


        recyclerView = findViewById(R.id.recyclerView);
        recyclerView.setHasFixedSize(true);
        recyclerView.setLayoutManager(new LinearLayoutManager(MainActivity.this));
        // 스크롤 처리를 위한 코드
        recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
            @Override
            public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) {
                super.onScrollStateChanged(recyclerView, newState);
            }

            @Override
            public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) {
                super.onScrolled(recyclerView, dx, dy);

                // 맨 마지막 데이터가 화면에 보이게 되면,
                // 네트워크 통해서 데이터를 추가로 가져오도록 한다.
                int lastpositon=((LinearLayoutManager)recyclerView.getLayoutManager()).findLastCompletelyVisibleItemPosition();
                int totalCount = recyclerView.getAdapter().getItemCount();

                if(lastpositon+1 == totalCount){
                    // 네트워크로부터 데이터를 추가로 받아온다.
                    addNetworkData();
                }

            }

        });
        progressBar.setVisibility(View.GONE);

        btn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                text = editText.getText().toString().trim();

                if(text.isEmpty()){
                    Snackbar.make(btn,
                            "검색어를 입력하세요.",
                            Snackbar.LENGTH_SHORT).show();
                    return;
                }
                // 네트워크 api를 호출한다.
                getNetworkData();

            }
        });

        // 1. 큐를 만든다.


    }

    // 추가로 20개씩 더 호출할때 사용하는 함수
    private void addNetworkData() {
        progressBar.setVisibility(View.VISIBLE);
        RequestQueue queue = Volley.newRequestQueue(MainActivity.this);
        // 2. request 만든다.
        String url = "https://www.googleapis.com/youtube/v3/search?key="+Config.YOUYUBE_KEY+"&part=snippet&maxResults=20&order=date&q="+text+"&type=video"+"&pageToken"+nextPageToken;
        JsonObjectRequest request = new JsonObjectRequest(
                Request.Method.GET,
                url,
                null,
                new Response.Listener<JSONObject>() {
                    @Override
                    public void onResponse(JSONObject response) {
                        progressBar.setVisibility(View.GONE);

                        try {
                            nextPageToken = response.getString("nextPageToken");
                            JSONArray dataArray = response.getJSONArray("items");
                            for (int i = 0; i < dataArray.length(); i++) {
                                JSONObject item = dataArray.getJSONObject(i);
                                JSONObject snippet = item.getJSONObject("snippet");
                                String title = snippet.getString("title");
                                String body = snippet.getString("description");
                                JSONObject thumbnails = snippet.getJSONObject("thumbnails");
                                JSONObject thumbnail = thumbnails.getJSONObject("default");
                                JSONObject high = thumbnails.getJSONObject("high");
                                String url2 = high.getString("url");
                                String url = thumbnail.getString("url");

                                JSONObject ids = item.getJSONObject("id");
                                String id=ids.getString("videoId");




                                Posting posting = new Posting(title, body, url, id, url2);
                                postingArrayList.add(posting);
                                Log.i("MAIN",postingArrayList.toString());

                            }

                            adapter = new PostingAdapter(MainActivity.this, postingArrayList);

                            recyclerView.setAdapter(adapter);



                        } catch (JSONException e) {
                            Toast.makeText(MainActivity.this,
                                    "파싱 에러",
                                    Toast.LENGTH_SHORT).show();
                            Log.i("EMPLOYER MAIN", e.toString());
                            return;
                        }

                    }
                },
                new Response.ErrorListener() {
                    @Override
                    public void onErrorResponse(VolleyError error) {

                        progressBar.setVisibility(View.GONE);

                        Toast.makeText(MainActivity.this,
                                "네트워크 통신 에러",
                                Toast.LENGTH_SHORT).show();
                        Log.i("EMPLOYER MAIN", error.toString());
                    }
                }
        );
        // 3. 네트워크로 API 호출
        queue.add(request);




    }

    // 처음 데이터 20개 가져올떄 호출하는 함수.
    private void getNetworkData() {
        progressBar.setVisibility(View.VISIBLE);
        postingArrayList.clear();

        RequestQueue queue = Volley.newRequestQueue(MainActivity.this);
        // 2. request 만든다.
        JsonObjectRequest request = new JsonObjectRequest(
                Request.Method.GET,
                "https://www.googleapis.com/youtube/v3/search?key="+Config.YOUYUBE_KEY+"&part=snippet&maxResults=20&order=date&q="+text+"&type=video",
                null,
                new Response.Listener<JSONObject>() {
                    @Override
                    public void onResponse(JSONObject response) {
                        progressBar.setVisibility(View.GONE);

                        try {
                            nextPageToken = response.getString("nextPageToken");
                            JSONArray dataArray = response.getJSONArray("items");
                            for (int i = 0; i < dataArray.length(); i++) {
                                JSONObject item = dataArray.getJSONObject(i);
                                JSONObject snippet = item.getJSONObject("snippet");
                                String title = snippet.getString("title");
                                String body = snippet.getString("description");
                                JSONObject thumbnails = snippet.getJSONObject("thumbnails");
                                JSONObject thumbnail = thumbnails.getJSONObject("default");
                                JSONObject high = thumbnails.getJSONObject("high");
                                String url2 = high.getString("url");
                                String url = thumbnail.getString("url");

                                JSONObject ids = item.getJSONObject("id");
                                String id=ids.getString("videoId");




                                Posting posting = new Posting(title, body, url, id, url2);
                                postingArrayList.add(posting);
                                Log.i("MAIN",postingArrayList.toString());

                            }

                            adapter = new PostingAdapter(MainActivity.this, postingArrayList);

                            recyclerView.setAdapter(adapter);



                        } catch (JSONException e) {
                            Toast.makeText(MainActivity.this,
                                    "파싱 에러",
                                    Toast.LENGTH_SHORT).show();
                            Log.i("EMPLOYER MAIN", e.toString());
                            return;
                        }

                    }
                },
                new Response.ErrorListener() {
                    @Override
                    public void onErrorResponse(VolleyError error) {

                        progressBar.setVisibility(View.GONE);

                        Toast.makeText(MainActivity.this,
                                "네트워크 통신 에러",
                                Toast.LENGTH_SHORT).show();
                        Log.i("EMPLOYER MAIN", error.toString());
                    }
                }
        );
        // 3. 네트워크로 API 호출
        queue.add(request);
    }
}

 

PostringAdapter

package com.example.youtube.adapter;

import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;

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

import com.bumptech.glide.Glide;
import com.example.youtube.R;
import com.example.youtube.model.Posting;
import com.example.youtube.model.imgActivity;

import java.util.ArrayList;

public class PostingAdapter extends RecyclerView.Adapter<PostingAdapter.ViewHolder> {

    Context context;
    ArrayList<Posting> postingArrayList;

    public PostingAdapter(Context context, ArrayList<Posting> postingArrayList) {
        this.context = context;
        this.postingArrayList = postingArrayList;
    }

    @NonNull
    @Override
    public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(parent.getContext())
                .inflate(R.layout.posting_row, parent, false);
        return new PostingAdapter.ViewHolder(view);
    }

    @Override
    public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
        Posting posting = postingArrayList.get(position);

        holder.txtTitle.setText(posting.getTitle());
        holder.txtBody.setText(posting.getBody());

        Glide.with(context)
                .load(posting.getUrl())
                .into(holder.img);
    }

    @Override
    public int getItemCount() {
        return postingArrayList.size();
    }

    public class ViewHolder extends RecyclerView.ViewHolder {

        TextView txtTitle;
        TextView txtBody;
        ImageView img;
        CardView cardView;

        public ViewHolder(@NonNull View itemView) {
            super(itemView);

            txtTitle = itemView.findViewById(R.id.txtTitle);
            txtBody = itemView.findViewById(R.id.txtBody);
            img = itemView.findViewById(R.id.img);
            cardView = itemView.findViewById(R.id.cardView);

            cardView.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    int index = getAdapterPosition();
                    if (index != RecyclerView.NO_POSITION) {
                        Posting posting = postingArrayList.get(index);
                        openWebPage("https://www.youtube.com/watch?v="+posting.getId());
                    }
                }
            });

            img.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    Intent intent = new Intent(context, imgActivity.class);
                    int index= getAdapterPosition();
                    Posting posting=postingArrayList.get(index);
                    intent.putExtra("Posting",posting);
                    context.startActivity(intent);
                }
            });
        }

    }

    private void openWebPage(String url) {
        Uri uri = Uri.parse(url);
        Intent intent = new Intent(Intent.ACTION_VIEW, uri);
        context.startActivity(intent);
    }
}

 

imgActivity

package com.example.youtube.model;

import android.os.Bundle;
import android.widget.ImageView;

import androidx.activity.EdgeToEdge;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.graphics.Insets;
import androidx.core.view.ViewCompat;
import androidx.core.view.WindowInsetsCompat;

import com.bumptech.glide.Glide;
import com.example.youtube.R;

public class imgActivity extends AppCompatActivity {
    ImageView img2;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_img);

        Posting posting = (Posting) getIntent().getSerializableExtra("Posting");

        img2 = findViewById(R.id.img2);

        Glide.with(imgActivity.this).load(posting.getUrl2()).into(img2);
    }
}

 

Posting

package com.example.youtube.model;

import java.io.Serializable;

public class Posting implements Serializable {
    private String title;
    private String body;
    private String url;
    private String id;

    private String url2;


    public Posting(String title, String body, String url, String id, String url2) {
        this.title = title;
        this.body = body;
        this.url = url;
        this.id = id;
        this.url2 = url2;
    }

    public String getTitle() {
        return title;
    }

    public String getBody() {
        return body;
    }

    public String getUrl() {
        return url;
    }

    public  String getId(){
        return id;
    }

    public String getUrl2() {
        return url2;
    }


}

 

 

xml 파일

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

    <RelativeLayout
        android:layout_width="409dp"
        android:layout_height="729dp"
        android:layout_marginStart="1dp"
        android:layout_marginTop="1dp"
        android:layout_marginEnd="1dp"
        android:layout_marginBottom="1dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent">

        <LinearLayout
            android:id="@+id/search_layout"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="30dp"
            android:orientation="horizontal">

            <EditText
                android:id="@+id/editText"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginLeft="30dp"
                android:ems="10"
                android:hint="검색"
                android:inputType="text" />

            <Button
                android:id="@+id/btn"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginLeft="0dp"
                android:layout_marginTop="0dp"
                android:layout_marginRight="0dp"
                android:backgroundTint="#FF0000"
                android:text="검색"
                android:textColor="#000000"
                android:textSize="30sp" />

        </LinearLayout>

        <ProgressBar
            android:id="@+id/progressBar"
            style="?android:attr/progressBarStyle"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerInParent="true"
            android:visibility="visible" />

        <androidx.recyclerview.widget.RecyclerView
            android:id="@+id/recyclerView"
            android:layout_width="match_parent"
            android:layout_height="0dp"
            android:layout_below="@id/search_layout"
            android:layout_alignParentBottom="true"
            android:layout_marginTop="16dp"
            android:layout_marginBottom="16dp"/>
    </RelativeLayout>
</androidx.constraintlayout.widget.ConstraintLayout>

 

<?xml version="1.0" encoding="utf-8"?>
<androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:card_view="http://schemas.android.com/apk/res-auto"
    android:id="@+id/cardView"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_margin="8dp"
    card_view:cardCornerRadius="15dp"
    card_view:cardElevation="4dp">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        android:padding="8dp">

        <ImageView
            android:id="@+id/img"
            android:layout_width="100dp"
            android:layout_height="100dp"
            android:scaleType="centerCrop"
            android:src="@drawable/ic_launcher_background" />

        <LinearLayout
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:orientation="vertical"
            android:paddingStart="8dp"
            android:paddingLeft="8dp">

            <TextView
                android:id="@+id/txtTitle"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginBottom="4dp"
                android:text="Title"
                android:textSize="18sp"
                android:textStyle="bold" />

            <TextView
                android:id="@+id/txtBody"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="Content"
                android:textSize="14sp" />

        </LinearLayout>
    </LinearLayout>
</androidx.cardview.widget.CardView>