본문 바로가기
안드로이드 웹앱 콘테츠 개발자 양성(국비지원)/Android 기능

Android Studio(기능) ExoPlayer이용 json 파싱 및 영상 보여주기1-1

by 차누감 2019. 11. 6.

⊙ PlyaerView

SimpleExoPlayer

PlayerControlView

 

 

이번 예제는 ExoPlayer를 이용해서 json 파일을 파싱해서 보여줄 것이다.

<최종 실행 화면>

json으로 읽어온 비디오들을 RecyclerView로 보여줬다.

 

json file을 만들기 위해 새로운 폴더와 json 파일을 만들어 주자.

 

assets 폴더가 만들어 졌을 것이다.
json 파일들을 보관할 폴더니 jsons라 임의로 폴더명을 만들었다.

 

그리고 이제 json 파일의 내용은 인터넷에서 임의로 가져왔다.

아래 주소는 제공받은 주소이다.

https://gist.github.com/jsturgis/3b19447b304616f18657

 

마지막 ;(세미콜론)은 필요 없다.

만든 json 파일에 복붙한다.

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
{ "categories" : [ { "name" : "Movies",
  "videos" : [
    { "description" : "Big Buck Bunny tells the story of a giant rabbit with a heart bigger than himself. When one sunny day three rodents rudely harass him, something snaps... and the rabbit ain't no bunny anymore! In the typical cartoon tradition he prepares the nasty rodents a comical revenge.\n\nLicensed under the Creative Commons Attribution license\nhttp://www.bigbuckbunny.org",
      "subtitle" : "By Blender Foundation",
      "thumb" : "images/BigBuckBunny.jpg",
      "title" : "Big Buck Bunny"
    },
    { "description" : "The first Blender Open Movie from 2006",
      "subtitle" : "By Blender Foundation",
      "thumb" : "images/ElephantsDream.jpg",
      "title" : "Elephant Dream"
    },
    { "description" : "HBO GO now works with Chromecast -- the easiest way to enjoy online video on your TV. For when you want to settle into your Iron Throne to watch the latest episodes. For $35.\nLearn how to use Chromecast with HBO GO and more at google.com/chromecast.",
      "subtitle" : "By Google",
      "thumb" : "images/ForBiggerBlazes.jpg",
      "title" : "For Bigger Blazes"
    },
    { "description" : "Introducing Chromecast. The easiest way to enjoy online video and music on your TV—for when Batman's escapes aren't quite big enough. For $35. Learn how to use Chromecast with Google Play Movies and more at google.com/chromecast.",
      "subtitle" : "By Google",
      "thumb" : "images/ForBiggerEscapes.jpg",
      "title" : "For Bigger Escape"
    },
    { "description" : "Introducing Chromecast. The easiest way to enjoy online video and music on your TV. For $35.  Find out more at google.com/chromecast.",
      "subtitle" : "By Google",
      "thumb" : "images/ForBiggerFun.jpg",
      "title" : "For Bigger Fun"
    },
    { "description" : "Introducing Chromecast. The easiest way to enjoy online video and music on your TV—for the times that call for bigger joyrides. For $35. Learn how to use Chromecast with YouTube and more at google.com/chromecast.",
      "subtitle" : "By Google",
      "thumb" : "images/ForBiggerJoyrides.jpg",
      "title" : "For Bigger Joyrides"
    },
    { "description" :"Introducing Chromecast. The easiest way to enjoy online video and music on your TV—for when you want to make Buster's big meltdowns even bigger. For $35. Learn how to use Chromecast with Netflix and more at google.com/chromecast.",
      "subtitle" : "By Google",
      "thumb" : "images/ForBiggerMeltdowns.jpg",
      "title" : "For Bigger Meltdowns"
    },
    { "description" : "Sintel is an independently produced short film, initiated by the Blender Foundation as a means to further improve and validate the free/open source 3D creation suite Blender. With initial funding provided by 1000s of donations via the internet community, it has again proven to be a viable development model for both open 3D technology as for independent animation film.\nThis 15 minute film has been realized in the studio of the Amsterdam Blender Institute, by an international team of artists and developers. In addition to that, several crucial technical and creative targets have been realized online, by developers and artists and teams all over the world.\nwww.sintel.org",
      "subtitle" : "By Blender Foundation",
      "thumb" : "images/Sintel.jpg",
      "title" : "Sintel"
    },
    { "description" : "Smoking Tire takes the all-new Subaru Outback to the highest point we can find in hopes our customer-appreciation Balloon Launch will get some free T-shirts into the hands of our viewers.",
      "subtitle" : "By Garage419",
      "thumb" : "images/SubaruOutbackOnStreetAndDirt.jpg",
      "title" : "Subaru Outback On Street And Dirt"
    },
    { "description" : "Tears of Steel was realized with crowd-funding by users of the open source 3D creation tool Blender. Target was to improve and test a complete open and free pipeline for visual effects in film - and to make a compelling sci-fi film in Amsterdam, the Netherlands.  The film itself, and all raw material used for making it, have been released under the Creatieve Commons 3.0 Attribution license. Visit the tearsofsteel.org website to find out more about this, or to purchase the 4-DVD box with a lot of extras.  (CC) Blender Foundation - http://www.tearsofsteel.org",
      "subtitle" : "By Blender Foundation",
      "thumb" : "images/TearsOfSteel.jpg",
      "title" : "Tears of Steel"
    },
    { "description" : "The Smoking Tire heads out to Adams Motorsports Park in Riverside, CA to test the most requested car of 2010, the Volkswagen GTI. Will it beat the Mazdaspeed3's standard-setting lap time? Watch and see...",
      "subtitle" : "By Garage419",
      "thumb" : "images/VolkswagenGTIReview.jpg",
      "title" : "Volkswagen GTI Review"
    },
    { "description" : "The Smoking Tire is going on the 2010 Bullrun Live Rally in a 2011 Shelby GT500, and posting a video from the road every single day! The only place to watch them is by subscribing to The Smoking Tire or watching at BlackMagicShine.com",
      "subtitle" : "By Garage419",
      "thumb" : "images/WeAreGoingOnBullrun.jpg",
      "title" : "We Are Going On Bullrun"
    },
      "subtitle" : "By Garage419",
      "thumb" : "images/WhatCarCanYouGetForAGrand.jpg",
      "title" : "What care can you get for a grand?"
    }
  ]}]}
http://colorscripter.com/info#e" target="_blank" style="color:#e5e5e5text-decoration:none">Colored by Color Scripter
http://colorscripter.com/info#e" target="_blank" style="text-decoration:none;color:white">cs

이제 엑소 플레이어를 추가해야한다.

( 방법은 인터넷을 검색하여 찾았다. 안드로이드스튜디오에서 라이브러리 검색하면 안나옴.)

 

아래 페이지에 Hello world 목록에 들어가서 차근 차근 따라해보자. 추가할 것은 두개이다.

1
2
3
compileOptions {
  targetCompatibility JavaVersion.VERSION_1_8
}
 
1
implementation 'com.google.android.exoplayer:exoplayer:2.10.6'

recyclerView를 이용해서 보여줄 것이기 때문에 material 라이브러리를 추가하자.

추가할 작업은 끝났다.  코드 작성만 하면 된다.  화면 구성은 RecyclerView만 추가하여 보여줄 것이다.

activity_main.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">
 
        android:id="@+id/recycler"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
        android:orientation="vertical">
 
 
</RelativeLayout>
 
 

RecyclerView에 보여줄 대량의 데이터를 만들자. ( json 파싱한 값을 저장할 데이터 )

VideoItem.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
61
62
 
public class VideoItem {
 
    String title;
    String subTitle;
    String desc;
    String videoUrl;
    String thumb;
 
    public VideoItem(String title, String subTitle, String desc, String videoUrl, String thumb) {
        this.title = title;
        this.subTitle = subTitle;
        this.desc = desc;
        this.videoUrl = videoUrl;
        this.thumb = thumb;
    }
 
    public VideoItem() {
    }
 
    public String getTitle() {
        return title;
    }
 
    public void setTitle(String title) {
        this.title = title;
    }
 
    public String getSubTitle() {
        return subTitle;
    }
 
    public void setSubTitle(String subTitle) {
        this.subTitle = subTitle;
    }
 
    public String getDesc() {
        return desc;
    }
 
    public void setDesc(String desc) {
        this.desc = desc;
    }
 
    public String getVideoUrl() {
        return videoUrl;
    }
 
    public void setVideoUrl(String videoUrl) {
        this.videoUrl = videoUrl;
    }
 
    public String getThumb() {
        return thumb;
    }
 
    public void setThumb(String thumb) {
        this.thumb = thumb;
    }
}
 
 
 

 

각 아이템의 모양을 만들어주자.

recycler_item.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
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
<?xml version="1.0" encoding="utf-8"?>
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    app:cardCornerRadius="4dp"
    app:cardElevation="4dp"
    android:layout_margin="16dp">
 
    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">
 
        <TextView
            android:id="@+id/tv_title"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textSize="24sp"
            android:textStyle="bold"
            android:text="TITLE"
            android:padding="8dp"/>
        <TextView
            android:id="@+id/tv_subtitle"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_below="@id/tv_title"
            android:padding="8dp"
            android:text="sub title"/>
            android:id="@+id/pv"
            android:layout_width="match_parent"
            android:layout_height="300dp"
            android:layout_below="@+id/tv_subtitle"/>
        <TextView
            android:id="@+id/tv_desc"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_below="@id/pv"
            android:text="This is decription"
            android:padding="8dp"/>
 
    </RelativeLayout>
 
 
 
 

이제 대량의 데이터와 화면에 보여주도록 recycleView를 이어주는 Adapter를 만들자.

VideoAdapter.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
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
 
import android.content.Context;
 
import androidx.annotation.NonNull;
 
 
 
 
public class VideoAdapter extends RecyclerView.Adapter {
 
    Context context;
    ArrayList<VideoItem> videoItems;
 
    DataSource.Factory factory;
    ProgressiveMediaSource.Factory mediaFactory;
 
    public VideoAdapter(Context context, ArrayList<VideoItem> videoItems) {
        this.context = context;
        this.videoItems = videoItems;
 
        factory= new DefaultDataSourceFactory(context,"Ex90ExoPlayer"); // 매개 두번째는 임의로 그냥 적음
        mediaFactory= new ProgressiveMediaSource.Factory(factory);
    }
 
    @NonNull
    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        VH holder= new VH(itemView);
        return holder;
    }
 
    @Override
    public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
        VH vh= (VH)holder;
 
       VideoItem videoItem=videoItems.get(position);
       vh.tvTitle.setText(videoItem.getTitle());
       vh.tvSubTitle.setText(videoItem.getSubTitle());
 
       //플레이어가 실행할 비디오데이터 소스 객체 생성( CD or LP ) 미디어 팩토리로부터..
        ProgressiveMediaSource mediaSource= mediaFactory.createMediaSource(Uri.parse(videoItem.videoUrl));
        //위에서 만든 비디오 데이터 소스를 플레이어에게 로딩하도록....
    }
 
    @Override
    public int getItemCount() {
        return videoItems.size();
    }
 
    //inner class..
    class VH extends RecyclerView.ViewHolder{
 
        TextView tvTitle;
        TextView tvSubTitle;
        TextView tvDesc;
 
        PlayerView pv;
        SimpleExoPlayer player;
 
        public VH(@NonNull View itemView) {
            super(itemView);
 
            tvTitle=itemView.findViewById(R.id.tv_title);
            tvSubTitle=itemView.findViewById(R.id.tv_subtitle);
            tvDesc=itemView.findViewById(R.id.tv_desc);
            pv=itemView.findViewById(R.id.pv);
 
            player= ExoPlayerFactory.newSimpleInstance(context, new DefaultTrackSelector());
            pv.setPlayer(player);
        }
    }
}
 
 
 

 

이제 MainActivity.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
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
 
 
 
 
 
public class MainActivity extends AppCompatActivity {
 
    RecyclerView recyclerView;
    ArrayList<VideoItem> videoItems=new ArrayList<>();
    VideoAdapter adapter;
 
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
 
        recyclerView=findViewById(R.id.recycler);
        adapter= new VideoAdapter(this,videoItems);
        recyclerView.setAdapter(adapter);
 
        //대량의 비디오 정보들을 로딩해오기!!
        loadData();
    }//onCreate() ..
 
    void loadData(){
 
        new Thread(){       //보통 AsyncTask를 많이 쓴다. 예제라서 Tread를 그냥 씀.
            @Override
            public void run() {
 
                //assets폴더에 있는 파일을 읽어오기 위해 매니저 소환
                AssetManager assetManager= getAssets();
 
                //assets/jsons/videoUri.json파일을 읽기위한 Inputstream
                try {
                    InputStream is= assetManager.open("jsons/videoUrl.json");
                    InputStreamReader isr= new InputStreamReader(is);
                    BufferedReader reader= new BufferedReader(isr);
 
                    StringBuffer buffer= new StringBuffer();
                    String line= reader.readLine();
                    while (line!=null){
                        buffer.append(line+"\n");
                        line= reader.readLine();
                    }
 
                    final String jsonData= buffer.toString();
 
                    json 파일을 잘 읽었는지 확인하기 위한 코드
                    runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            new AlertDialog.Builder(MainActivity.this).setMessage(jsonData).create().show();
                        }
                    });
}catch (IOException e) {
e.printStackTrace();
}
            }
        }.start();
 
    }//loadData()..
}
 
 
 
 
   

json 파일 내용을 읽어오는 것을 확인 할 수 있다.

 이제 읽어온 내용으로 화면에 보여주자. MainActivity.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
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
 
 
 
 
 
public class MainActivity extends AppCompatActivity {
 
    RecyclerView recyclerView;
    ArrayList<VideoItem> videoItems=new ArrayList<>();
    VideoAdapter adapter;
 
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
 
        recyclerView=findViewById(R.id.recycler);
        adapter= new VideoAdapter(this,videoItems);
        recyclerView.setAdapter(adapter);
 
        //대량의 비디오 정보들을 로딩해오기!!
        loadData();
    }//onCreate() ..
 
    void loadData(){
 
        new Thread(){       //보통 AsyncTask를 많이 쓴다. 예제라서 Tread를 그냥 씀.
            @Override
            public void run() {
 
                //assets폴더에 있는 파일을 읽어오기 위해 매니저 소환
                AssetManager assetManager= getAssets();
 
                //assets/jsons/videoUri.json파일을 읽기위한 Inputstream
                try {
                    InputStream is= assetManager.open("jsons/videoUrl.json");
                    InputStreamReader isr= new InputStreamReader(is);
                    BufferedReader reader= new BufferedReader(isr);
 
                    StringBuffer buffer= new StringBuffer();
                    String line= reader.readLine();
                    while (line!=null){
                        buffer.append(line+"\n");
                        line= reader.readLine();
                    }
 
                    final String jsonData= buffer.toString();
 
//                    json 파일을 잘 읽었는지 확인하기 위한 코드
//                    runOnUiThread(new Runnable() {
//                        @Override
//                        public void run() {
//                            new AlertDialog.Builder(MainActivity.this).setMessage(jsonData).create().show();
//                        }
//                    });
 
                    //JSON parsing..
                    JSONObject jsonObject= new JSONObject(jsonData);
                    JSONArray categoriesArray= jsonObject.getJSONArray("categories");   //json 파일을 보면 객체는 {},  []는 배열
                    JSONObject object= categoriesArray.getJSONObject(0);
                    JSONArray videosArray= object.getJSONArray("videos");
 
                    for(int i=0; i<videosArray.length();i++){
                        JSONObject videoData= videosArray.getJSONObject(i);
 
                        final String title= videoData.getString("title");     // 매개변수 값은 json 파일을 보고 복붙
                        final String subTitle= videoData.getString("subtitle");
                        final String desc= videoData.getString("description");
                       String sources= videoData.getString("sources");        //파싱할때 값이 []로도 들어가 있다..
                        sources= sources.replace("[\""""); // [ -> 공백으로 바꾸기
                        sources= sources.replace("\"]"""); //
                        sources= sources.replace("\\/""/"); //
 
                        final String videoUrl= sources;
                        final String thumb= videoData.getString("thumb");
 
                        //리사이클러에 보여줄 대량의 데이터(videoItems)에 추가하기!!
                        runOnUiThread(new Runnable() {
                            @Override
                            public void run() {
                                videoItems.add(new VideoItem(title,subTitle,desc,videoUrl,thumb));      //이너 클래스 안에는 지역 변수를 사용할 수 없어서 final로
                                adapter.notifyItemInserted(videoItems.size()-1);
                            }
                        });
                    }
 
                } catch (IOException e) {
                    e.printStackTrace();
                } catch (JSONException e) {
                    e.printStackTrace();
                }
            }
        }.start();
 
    }//loadData()..
}
 
 
 

영상을 인터넷에서 가져오는 것이기 때문에 퍼미션이 필요하고 http라 Traffic도 해줘야 한다.

<최종 실행 화면>

json으로 읽어온 비디오들을 RecyclerView로 보여줬다.


복붙용 코드

activity_main.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">
 
        android:id="@+id/recycler"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
        android:orientation="vertical">
 
 
</RelativeLayout>
 
 

VideoItem.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
61
62
 
public class VideoItem {
 
    String title;
    String subTitle;
    String desc;
    String videoUrl;
    String thumb;
 
    public VideoItem(String title, String subTitle, String desc, String videoUrl, String thumb) {
        this.title = title;
        this.subTitle = subTitle;
        this.desc = desc;
        this.videoUrl = videoUrl;
        this.thumb = thumb;
    }
 
    public VideoItem() {
    }
 
    public String getTitle() {
        return title;
    }
 
    public void setTitle(String title) {
        this.title = title;
    }
 
    public String getSubTitle() {
        return subTitle;
    }
 
    public void setSubTitle(String subTitle) {
        this.subTitle = subTitle;
    }
 
    public String getDesc() {
        return desc;
    }
 
    public void setDesc(String desc) {
        this.desc = desc;
    }
 
    public String getVideoUrl() {
        return videoUrl;
    }
 
    public void setVideoUrl(String videoUrl) {
        this.videoUrl = videoUrl;
    }
 
    public String getThumb() {
        return thumb;
    }
 
    public void setThumb(String thumb) {
        this.thumb = thumb;
    }
}
 
 
 

recycler_item.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
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
<?xml version="1.0" encoding="utf-8"?>
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    app:cardCornerRadius="4dp"
    app:cardElevation="4dp"
    android:layout_margin="16dp">
 
    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">
 
        <TextView
            android:id="@+id/tv_title"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textSize="24sp"
            android:textStyle="bold"
            android:text="TITLE"
            android:padding="8dp"/>
        <TextView
            android:id="@+id/tv_subtitle"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_below="@id/tv_title"
            android:padding="8dp"
            android:text="sub title"/>
            android:id="@+id/pv"
            android:layout_width="match_parent"
            android:layout_height="300dp"
            android:layout_below="@+id/tv_subtitle"/>
        <TextView
            android:id="@+id/tv_desc"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_below="@id/pv"
            android:text="This is decription"
            android:padding="8dp"/>
 
    </RelativeLayout>
 
 
 
 

videoUrl.json

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
{ "categories" : [ { "name" : "Movies",
  "videos" : [
    { "description" : "Big Buck Bunny tells the story of a giant rabbit with a heart bigger than himself. When one sunny day three rodents rudely harass him, something snaps... and the rabbit ain't no bunny anymore! In the typical cartoon tradition he prepares the nasty rodents a comical revenge.\n\nLicensed under the Creative Commons Attribution license\nhttp://www.bigbuckbunny.org",
      "subtitle" : "By Blender Foundation",
      "thumb" : "images/BigBuckBunny.jpg",
      "title" : "Big Buck Bunny"
    },
    { "description" : "The first Blender Open Movie from 2006",
      "subtitle" : "By Blender Foundation",
      "thumb" : "images/ElephantsDream.jpg",
      "title" : "Elephant Dream"
    },
    { "description" : "HBO GO now works with Chromecast -- the easiest way to enjoy online video on your TV. For when you want to settle into your Iron Throne to watch the latest episodes. For $35.\nLearn how to use Chromecast with HBO GO and more at google.com/chromecast.",
      "subtitle" : "By Google",
      "thumb" : "images/ForBiggerBlazes.jpg",
      "title" : "For Bigger Blazes"
    },
    { "description" : "Introducing Chromecast. The easiest way to enjoy online video and music on your TV—for when Batman's escapes aren't quite big enough. For $35. Learn how to use Chromecast with Google Play Movies and more at google.com/chromecast.",
      "subtitle" : "By Google",
      "thumb" : "images/ForBiggerEscapes.jpg",
      "title" : "For Bigger Escape"
    },
    { "description" : "Introducing Chromecast. The easiest way to enjoy online video and music on your TV. For $35.  Find out more at google.com/chromecast.",
      "subtitle" : "By Google",
      "thumb" : "images/ForBiggerFun.jpg",
      "title" : "For Bigger Fun"
    },
    { "description" : "Introducing Chromecast. The easiest way to enjoy online video and music on your TV—for the times that call for bigger joyrides. For $35. Learn how to use Chromecast with YouTube and more at google.com/chromecast.",
      "subtitle" : "By Google",
      "thumb" : "images/ForBiggerJoyrides.jpg",
      "title" : "For Bigger Joyrides"
    },
    { "description" :"Introducing Chromecast. The easiest way to enjoy online video and music on your TV—for when you want to make Buster's big meltdowns even bigger. For $35. Learn how to use Chromecast with Netflix and more at google.com/chromecast.",
      "subtitle" : "By Google",
      "thumb" : "images/ForBiggerMeltdowns.jpg",
      "title" : "For Bigger Meltdowns"
    },
    { "description" : "Sintel is an independently produced short film, initiated by the Blender Foundation as a means to further improve and validate the free/open source 3D creation suite Blender. With initial funding provided by 1000s of donations via the internet community, it has again proven to be a viable development model for both open 3D technology as for independent animation film.\nThis 15 minute film has been realized in the studio of the Amsterdam Blender Institute, by an international team of artists and developers. In addition to that, several crucial technical and creative targets have been realized online, by developers and artists and teams all over the world.\nwww.sintel.org",
      "subtitle" : "By Blender Foundation",
      "thumb" : "images/Sintel.jpg",
      "title" : "Sintel"
    },
    { "description" : "Smoking Tire takes the all-new Subaru Outback to the highest point we can find in hopes our customer-appreciation Balloon Launch will get some free T-shirts into the hands of our viewers.",
      "subtitle" : "By Garage419",
      "thumb" : "images/SubaruOutbackOnStreetAndDirt.jpg",
      "title" : "Subaru Outback On Street And Dirt"
    },
    { "description" : "Tears of Steel was realized with crowd-funding by users of the open source 3D creation tool Blender. Target was to improve and test a complete open and free pipeline for visual effects in film - and to make a compelling sci-fi film in Amsterdam, the Netherlands.  The film itself, and all raw material used for making it, have been released under the Creatieve Commons 3.0 Attribution license. Visit the tearsofsteel.org website to find out more about this, or to purchase the 4-DVD box with a lot of extras.  (CC) Blender Foundation - http://www.tearsofsteel.org",
      "subtitle" : "By Blender Foundation",
      "thumb" : "images/TearsOfSteel.jpg",
      "title" : "Tears of Steel"
    },
    { "description" : "The Smoking Tire heads out to Adams Motorsports Park in Riverside, CA to test the most requested car of 2010, the Volkswagen GTI. Will it beat the Mazdaspeed3's standard-setting lap time? Watch and see...",
      "subtitle" : "By Garage419",
      "thumb" : "images/VolkswagenGTIReview.jpg",
      "title" : "Volkswagen GTI Review"
    },
    { "description" : "The Smoking Tire is going on the 2010 Bullrun Live Rally in a 2011 Shelby GT500, and posting a video from the road every single day! The only place to watch them is by subscribing to The Smoking Tire or watching at BlackMagicShine.com",
      "subtitle" : "By Garage419",
      "thumb" : "images/WeAreGoingOnBullrun.jpg",
      "title" : "We Are Going On Bullrun"
    },
      "subtitle" : "By Garage419",
      "thumb" : "images/WhatCarCanYouGetForAGrand.jpg",
      "title" : "What care can you get for a grand?"
    }
  ]}]}
http://colorscripter.com/info#e" target="_blank" style="color:#e5e5e5text-decoration:none">Colored by Color Scripter
http://colorscripter.com/info#e" target="_blank" style="text-decoration:none;color:white">cs

VideoAdapter.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
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
 
import android.content.Context;
 
import androidx.annotation.NonNull;
 
 
 
 
public class VideoAdapter extends RecyclerView.Adapter {
 
    Context context;
    ArrayList<VideoItem> videoItems;
 
    DataSource.Factory factory;
    ProgressiveMediaSource.Factory mediaFactory;
 
    public VideoAdapter(Context context, ArrayList<VideoItem> videoItems) {
        this.context = context;
        this.videoItems = videoItems;
 
        factory= new DefaultDataSourceFactory(context,"Ex90ExoPlayer"); // 매개 두번째는 임의로 그냥 적음
        mediaFactory= new ProgressiveMediaSource.Factory(factory);
    }
 
    @NonNull
    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        VH holder= new VH(itemView);
        return holder;
    }
 
    @Override
    public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
        VH vh= (VH)holder;
 
       VideoItem videoItem=videoItems.get(position);
       vh.tvTitle.setText(videoItem.getTitle());
       vh.tvSubTitle.setText(videoItem.getSubTitle());
 
       //플레이어가 실행할 비디오데이터 소스 객체 생성( CD or LP ) 미디어 팩토리로부터..
        ProgressiveMediaSource mediaSource= mediaFactory.createMediaSource(Uri.parse(videoItem.videoUrl));
        //위에서 만든 비디오 데이터 소스를 플레이어에게 로딩하도록....
    }
 
    @Override
    public int getItemCount() {
        return videoItems.size();
    }
 
    //inner class..
    class VH extends RecyclerView.ViewHolder{
 
        TextView tvTitle;
        TextView tvSubTitle;
        TextView tvDesc;
 
        PlayerView pv;
        SimpleExoPlayer player;
 
        public VH(@NonNull View itemView) {
            super(itemView);
 
            tvTitle=itemView.findViewById(R.id.tv_title);
            tvSubTitle=itemView.findViewById(R.id.tv_subtitle);
            tvDesc=itemView.findViewById(R.id.tv_desc);
            pv=itemView.findViewById(R.id.pv);
 
            player= ExoPlayerFactory.newSimpleInstance(context, new DefaultTrackSelector());
            pv.setPlayer(player);
        }
    }
}
 
 
 

MainActivity.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
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
 
 
 
 
 
public class MainActivity extends AppCompatActivity {
 
    RecyclerView recyclerView;
    ArrayList<VideoItem> videoItems=new ArrayList<>();
    VideoAdapter adapter;
 
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
 
        recyclerView=findViewById(R.id.recycler);
        adapter= new VideoAdapter(this,videoItems);
        recyclerView.setAdapter(adapter);
 
        //대량의 비디오 정보들을 로딩해오기!!
        loadData();
    }//onCreate() ..
 
    void loadData(){
 
        new Thread(){       //보통 AsyncTask를 많이 쓴다. 예제라서 Tread를 그냥 씀.
            @Override
            public void run() {
 
                //assets폴더에 있는 파일을 읽어오기 위해 매니저 소환
                AssetManager assetManager= getAssets();
 
                //assets/jsons/videoUri.json파일을 읽기위한 Inputstream
                try {
                    InputStream is= assetManager.open("jsons/videoUrl.json");
                    InputStreamReader isr= new InputStreamReader(is);
                    BufferedReader reader= new BufferedReader(isr);
 
                    StringBuffer buffer= new StringBuffer();
                    String line= reader.readLine();
                    while (line!=null){
                        buffer.append(line+"\n");
                        line= reader.readLine();
                    }
 
                    final String jsonData= buffer.toString();
 
//                    json 파일을 잘 읽었는지 확인하기 위한 코드
//                    runOnUiThread(new Runnable() {
//                        @Override
//                        public void run() {
//                            new AlertDialog.Builder(MainActivity.this).setMessage(jsonData).create().show();
//                        }
//                    });
 
                    //JSON parsing..
                    JSONObject jsonObject= new JSONObject(jsonData);
                    JSONArray categoriesArray= jsonObject.getJSONArray("categories");   //json 파일을 보면 객체는 {},  []는 배열
                    JSONObject object= categoriesArray.getJSONObject(0);
                    JSONArray videosArray= object.getJSONArray("videos");
 
                    for(int i=0; i<videosArray.length();i++){
                        JSONObject videoData= videosArray.getJSONObject(i);
 
                        final String title= videoData.getString("title");     // 매개변수 값은 json 파일을 보고 복붙
                        final String subTitle= videoData.getString("subtitle");
                        final String desc= videoData.getString("description");
                       String sources= videoData.getString("sources");        //파싱할때 값이 []로도 들어가 있다..
                        sources= sources.replace("[\""""); // [ -> 공백으로 바꾸기
                        sources= sources.replace("\"]"""); //
                        sources= sources.replace("\\/""/"); //
 
                        final String videoUrl= sources;
                        final String thumb= videoData.getString("thumb");
 
                        //리사이클러에 보여줄 대량의 데이터(videoItems)에 추가하기!!
                        runOnUiThread(new Runnable() {
                            @Override
                            public void run() {
                                videoItems.add(new VideoItem(title,subTitle,desc,videoUrl,thumb));      //이너 클래스 안에는 지역 변수를 사용할 수 없어서 final로
                                adapter.notifyItemInserted(videoItems.size()-1);
                            }
                        });
                    }
 
                } catch (IOException e) {
                    e.printStackTrace();
                } catch (JSONException e) {
                    e.printStackTrace();
                }
            }
        }.start();
 
    }//loadData()..
}
 
 
 

 

댓글