Android

์œ ํŠœ๋ธŒ API ํ‚ค์›Œ๋“œ ๊ฒ€์ƒ‰ํ•˜๋ฉด ํ‚ค์›Œ๋“œ์— ๋งž๋Š” ๊ฒŒ์‹œ๋ฌผ์„ ๊ฐ€์ ธ์˜ค๋Š” app๊ฐœ๋ฐœ

567Rabbit 2024. 6. 12. 15:45

https://codebunny99.tistory.com/163

 

์œ ํŠœ๋ธŒ ๋ฐ์ดํ„ฐ API๋ฅผ Postman(ํฌ์ŠคํŠธ๋งจ)์œผ๋กœ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•

https://console.cloud.google.com/welcome/new?hl=ko&project=eastern-surface-426200-r0&supportedpurview=project Google ํด๋ผ์šฐ๋“œ ํ”Œ๋žซํผ๋กœ๊ทธ์ธ Google ํด๋ผ์šฐ๋“œ ํ”Œ๋žซํผ์œผ๋กœ ์ด๋™accounts.google.com  youtube data ๊ฒ€์ƒ‰ํ•ด์„œ ์‚ฌ์šฉ ๋ˆ„๋ฅด

codebunny99.tistory.com

 

ํ‚ค(key) ๊ฐ’์„ ์œ„์˜ ํฌ์ŠคํŒ…์„ ๋จผ์ € ์ฐธ๊ณ ํ•ด ๊ฐ€์ ธ์˜จ๋‹ค.

 

 

 

์œ ํŠœ๋ธŒ API๋ฅผ Postman์œผ๋กœ ์‹คํ–‰์‹œํ‚ค๋ฉด, ๋‹ค์Œ๊ณผ ๊ฐ™์ด Json ํŒŒ์ผ์„ ์ค€๋‹ค.

 

 

 

 

 

 

 

 

MainActivity

 

๋””์ž์ธ(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:id="@+id/main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent">

        <LinearLayout
            android:id="@+id/topLayout"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_alignParentTop="true"
            android:layout_margin="10dp"
            android:orientation="horizontal">

            <EditText
                android:id="@+id/editSearch"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginRight="5dp"
                android:layout_weight="5"
                android:ems="10"
                android:hint="๊ฒ€์ƒ‰์–ด ์ž…๋ ฅ..."
                android:inputType="text"
                android:textSize="22sp" />

            <ImageView
                android:id="@+id/imgSearch"
                android:layout_width="45dp"
                android:layout_height="45dp"
                app:srcCompat="@drawable/search_24dp" />
        </LinearLayout>

        <androidx.recyclerview.widget.RecyclerView
            android:id="@+id/recyclerView"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_below="@id/topLayout" />

        <ProgressBar
            android:id="@+id/progressBar"
            style="?android:attr/progressBarStyle"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerInParent="true" />
    </RelativeLayout>
</androidx.constraintlayout.widget.ConstraintLayout>

 

 

 

 

 

MainActivity.java (ํŒŒ์‹ฑํ•˜๊ธฐ)

package com.~.youtube;

import android.os.Bundle;
import android.view.View;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.ProgressBar;
import android.widget.Toast;

import androidx.appcompat.app.AppCompatActivity;
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.google.android.material.snackbar.Snackbar;
import com.~.youtube.adapter.YoutubeAdapter;
import com.~.youtube.config.Config;
import com.~.youtube.model.Youtube;

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

import java.util.ArrayList;

public class MainActivity extends AppCompatActivity {

    ProgressBar progressBar;
    ImageView imgSearch;
    EditText editSearch;

    // ๋ฆฌ์‚ฌ์ดํด๋Ÿฌ๋ทฐ๋Š” ๊ด€๋ จ๋œ ๋ฉค๋ฒ„๋ณ€์ˆ˜ 2๊ฐœ ๋” ์ž‘์„ฑํ•ด์•ผ ํ•œ๋‹ค
    RecyclerView recyclerView;
    ArrayList<Youtube> YoutubeArrayList = new ArrayList<>();
    YoutubeAdapter adapter;

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

        getSupportActionBar().setTitle("YoutubeApp");

        // ๋‹ค์Œ ์ฝ”๋“œ๋Š” ์Œ์œผ๋กœ ๋ฌด์กฐ๊ฑด ๊ฐ™์ด ์ž‘์„ฑ
        recyclerView = findViewById(R.id.recyclerView);
        recyclerView.setHasFixedSize(true);
        recyclerView.setLayoutManager(new LinearLayoutManager(MainActivity.this));

        progressBar = findViewById(R.id.progressBar);
        imgSearch = findViewById(R.id.imgSearch);
        editSearch = findViewById(R.id.editSearch);

        // ํ”„๋กœ๊ทธ๋ ˆ์Šค ๋ฐ”๋ฅผ ์œ ์ €์˜ ๋ˆˆ์—์„œ ์‚ฌ๋ผ์ง€๊ฒŒ ํ•˜๋Š” ์ฝ”๋“œ
        progressBar.setVisibility(View.GONE);

        imgSearch.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                String keyword = editSearch.getText().toString().trim();

                if(keyword.isEmpty()){
                    Snackbar.make(imgSearch, "๊ฒ€์ƒ‰์–ด๋ฅผ ์ž…๋ ฅํ•˜์„ธ์š”.", Snackbar.LENGTH_SHORT).show();
                    return;
                }

                // ํ”„๋กœ๊ทธ๋ ˆ์Šค ๋ฐ”๋ฅผ ์œ ์ €์˜ ๋ˆˆ์— ๋ณด์ด๊ฒŒ ํ•˜๋Š” ์ฝ”๋“œ
                progressBar.setVisibility(View.VISIBLE);

                // 1. request queue ๋ฅผ ๋งŒ๋“ ๋‹ค
                RequestQueue queue = Volley.newRequestQueue(MainActivity.this);

                // 2. request(์š”์ฒญ)์„ ๋งŒ๋“ ๋‹ค.
                // ๋ฐ์ดํ„ฐ ํƒ€์ž…์€, ์‘๋‹ต์˜ json ํ˜•์‹์„ ๋ณด๊ณ  ๊ฒฐ์ •ํ•œ๋‹ค.
                JsonObjectRequest request = new JsonObjectRequest(
                        Request.Method.GET,
                        "https://www.googleapis.com/youtube/v3/search?key=" + Config.YoutubeKey + "&part=snippet&maxResults=20&order=date&q=" + keyword + "&type=video",
                        null,
                        new Response.Listener<JSONObject>() {
                            @Override
                            public void onResponse(JSONObject response) {

                                // ํ”„๋กœ๊ทธ๋ ˆ์Šค ๋ฐ”๋ฅผ ์œ ์ €์˜ ๋ˆˆ์—์„œ ์‚ฌ๋ผ์ง€๊ฒŒ ํ•˜๋Š” ์ฝ”๋“œ
                                progressBar.setVisibility(View.GONE);

                                try {
                                    JSONArray items = response.getJSONArray("items");
                                    YoutubeArrayList.clear();  // ๊ธฐ์กด ๋ฐ์ดํ„ฐ ์ดˆ๊ธฐํ™”

                                    for (int i = 0; i < items.length(); i++) {
                                        JSONObject data = items.getJSONObject(i);
                                        JSONObject id = data.getJSONObject("id");
                                        String videoId = id.getString("videoId");
                                        JSONObject snippet = data.getJSONObject("snippet");
                                        String title = snippet.getString("title");
                                        String description = snippet.getString("description");

                                        JSONObject thumbnails = snippet.getJSONObject("thumbnails");
                                        JSONObject medium = thumbnails.getJSONObject("medium");
                                        String thumbUrl = medium.getString("url");

                                        JSONObject high = thumbnails.getJSONObject("high");
                                        String url = high.getString("url");

                                        Youtube youtube = new Youtube(videoId, title, description, thumbUrl, url);
                                        YoutubeArrayList.add(youtube);
                                    }

                                    // ์–ด๋Œ‘ํ„ฐ๋ฅผ ๋งŒ๋“ค๊ณ 
                                    adapter = new YoutubeAdapter(MainActivity.this, YoutubeArrayList);
                                    // ๋ฆฌ์‚ฌ์ดํด๋Ÿฌ๋ทฐ์— ์–ด๋Œ‘ํ„ฐ๋ฅผ ์ ์šฉํ•˜๋ฉด ํ™”๋ฉด์— ๋‚˜์˜จ๋‹ค
                                    recyclerView.setAdapter(adapter);

                                } catch (JSONException e) {
                                    Toast.makeText(MainActivity.this, "ํŒŒ์‹ฑ ์—๋Ÿฌ", Toast.LENGTH_SHORT).show();
                                    e.printStackTrace();
                                }
                            }
                        },
                        new Response.ErrorListener() {
                            @Override
                            public void onErrorResponse(VolleyError volleyError) {
                                // ํ”„๋กœ๊ทธ๋ ˆ์Šค ๋ฐ”๋ฅผ ์œ ์ €์˜ ๋ˆˆ์—์„œ ์‚ฌ๋ผ์ง€๊ฒŒ ํ•˜๋Š” ์ฝ”๋“œ
                                progressBar.setVisibility(View.GONE);

                                Toast.makeText(MainActivity.this, "๋„คํŠธ์›Œํฌ ํ†ต์‹  ์—๋Ÿฌ", Toast.LENGTH_SHORT).show();
                            }
                        }
                );

                // 3. ๋„คํŠธ์›Œํฌ๋กœ ๋ณด๋‚ธ๋‹ค.
                queue.add(request);
            }
        });
    }
}

 

 

 

 

 

Config ํด๋ž˜์Šค

 

package com.~.youtube.config;

public class Config {
    public static final String YoutubeKey = "์ž์‹ ์˜ ํ‚ค๊ฐ’ ์ž…๋ ฅ";

}

 

 

 

 

 

Youtube ํด๋ž˜์Šค

 

package com.~.youtube.model;

import java.io.Serializable;

public class Youtube implements Serializable {

    public String videoId;
    public String thumbUrl;
    public String url;
    public String title;
    public String description;


    public Youtube(){

    }

    public Youtube(String videoId, String title, String description, String thumbUrl, String url) {
        this.videoId = videoId;
        this.thumbUrl = thumbUrl;
        this.url = url;
        this.title = title;
        this.description = description;
    }
}

 

 

 

 

 

activity_row .xml ๋งŒ๋“ค๊ธฐ

 

๋””์ž์ธ(xml ํŒŒ์ผ)

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical">

    <androidx.cardview.widget.CardView
        android:id="@+id/cardView"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_marginLeft="15dp"
        android:layout_marginTop="7dp"
        android:layout_marginRight="15dp"
        android:layout_marginBottom="7dp">

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_margin="10dp"
            android:orientation="vertical">

            <TextView
                android:id="@+id/txtTitle"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:ellipsize="end"
                android:maxLines="1"
                android:text="TextView"
                android:textSize="24sp" />

            <TextView
                android:id="@+id/txtDescription"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_marginLeft="20dp"
                android:layout_marginTop="7dp"
                android:layout_marginBottom="10dp"
                android:ellipsize="end"
                android:maxLines="2"
                android:text="TextView"
                android:textSize="20sp" />

            <ImageView
                android:id="@+id/imgThumb"
                android:layout_width="320dp"
                android:layout_height="180dp"
                android:layout_gravity="center"
                android:src="@drawable/image_24dp" />
        </LinearLayout>
    </androidx.cardview.widget.CardView>
</LinearLayout>

 

 

 

 

 

Adapter ๋งŒ๋“ค๊ธฐ

package com.~.youtube.adapter;

import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.webkit.WebView;
import android.widget.ImageView;
import android.widget.TextView;

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

import com.~.youtube.R;
import com.~.youtube.model.Youtube;
import com.bumptech.glide.Glide;

import java.util.ArrayList;

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

    Context context;
    ArrayList<Youtube> YoutubeArrayList;

    public YoutubeAdapter(Context context, ArrayList<Youtube> YoutubeArrayList) {
        this.context = context;
        this.YoutubeArrayList = YoutubeArrayList;
    }

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

    @Override
    public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
        Youtube youtube = YoutubeArrayList.get(position);

        holder.txtTitle.setText( youtube.title );
        holder.txtDescription.setText( youtube.description );
        Glide.with(context).load( youtube.thumbUrl ).into( holder.imgThumb );
    }

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

    public class ViewHolder extends RecyclerView.ViewHolder {

        TextView txtTitle;
        TextView txtDescription;
        ImageView imgThumb;

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

            txtTitle = itemView.findViewById(R.id.txtTitle);
            txtDescription = itemView.findViewById(R.id.txtDescription);
            imgThumb = itemView.findViewById(R.id.imgThumb);

        }
    }
}

 

 

 

 

 

 

์นด๋“œ๋ทฐ ์„ ํƒํ•˜๋ฉด ์œ ํŠœ๋ธŒ๋กœ ์ด๋™ํ•˜๊ฒŒ ํ•˜๊ธฐ

 

- Adapter์—์„œ ์ถ”๊ฐ€ํ•œ๋‹ค.

 

 

์นด๋“œ๋ทฐ๋ฅผ ํด๋ฆญํ•˜๋ฉด ์œ ํŠœ๋ธŒ๋กœ ์ด๋™ํ•˜๋Š” ๊ฒƒ๋„ ์ถ”๊ฐ€ํ•ด์ค€๋‹ค.

 

 

 

public class ViewHolder extends RecyclerView.ViewHolder {

        TextView txtTitle;
        TextView txtDescription;
        ImageView imgThumb;
        CardView cardView;
        
        public ViewHolder(@NonNull View itemView) {
            super(itemView);

            txtTitle = itemView.findViewById(R.id.txtTitle);
            txtDescription = itemView.findViewById(R.id.txtDescription);
            imgThumb = itemView.findViewById(R.id.imgThumb);
            cardView = itemView.findViewById(R.id.cardView);

            cardView.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    int index = getAdapterPosition();
                    Youtube youtube = YoutubeArrayList.get(index);
                    String url = "https://www.youtube.com/watch?v=" + youtube.videoId;
                    openWebPage(url);
                }
            });
        }

        // ์›น๋ธŒ๋ผ์šฐ์ € ์•กํ‹ฐ๋น„ํ‹ฐ๋ฅผ ์‹คํ–‰์‹œํ‚ค๋Š” ํ•จ์ˆ˜
        void openWebPage(String url){
            Uri uri = Uri.parse(url);
            Intent intent = new Intent(Intent.ACTION_VIEW, uri);
            context.startActivity(intent);
        }
    }