Hướng dẫn làm việc với Rotten Tomatoes Api
Bài hướng dẫn này mục đích tạo ra 1 ứng dụng hiển thị các phim phổ biến bằng cách sử dụng Api của Totten Tomatoes Tổng quan về ứng dụng## Chúng ta sẽ từng bước tạo ra 1 ứng dụng cho phép hiển thị danh sách các phim nổi bật hiện tại và mỗi 1 phim sẽ bao gồm các thông tin như tên phim, ảnh, và ...
Bài hướng dẫn này mục đích tạo ra 1 ứng dụng hiển thị các phim phổ biến bằng cách sử dụng Api của Totten Tomatoes
Tổng quan về ứng dụng##
Chúng ta sẽ từng bước tạo ra 1 ứng dụng cho phép hiển thị danh sách các phim nổi bật hiện tại và mỗi 1 phim sẽ bao gồm các thông tin như tên phim, ảnh, và vài thông tin sơ qua về phim. Giao diện của ứng dụng về cơ bản sẽ như sau: Trình tự của lập trình của ứng dụng này sẽ theo các bước sau:
- Lấy dự liệu phim từ Totten Tomatoes về dưới dạn Json.
- Xử lý dữ liệu đưa vào đối tượng BoxOfficeMovie
- Tạo các mảng đối tượng BoxOfficeMovie và nạp vào mảng ArrayAdapter những phim này.
- Tạo ra phần View cho đối tượng BoxOfficeMovie.
- Truyền dữ liệu từ đối tượng BoxOfficeMovie vào lớp View vừa tạo ở trên.
Để thực hiện được ứng dụng này, ta cần phải có các phần tách biệt sau:
- RottenTomatoesClient: Để gửi và lấy dữ liệu tử Toten Tomatoes.
- BoxOfficeMovie: Lớp Model cho từng phim.
- BoxOfficeMoviesAdapter: Adapter cho đối tượng 2
- BoxOfficeActivity: là phần xử lý dữ liệu của phần 1 và đưa dữ liệu vào Adapter của 3
Thực hiện##
Thiết lập API###
Rotten Tomatoes cung cấp sẵn API cho việc tìm kiếm phim, danh sách hay phân loại các phim, hay còn nhiều hơn nữa. Trong bài này chúng ta sẽ sử dụng một phương thức nhỏ để dùng trong ứng dụng của Android. Để gửi và lấy được dữ liệu từ Rotten Tomatoes thì ta cần phải có Api Key để có thể xác thực quyền được truy cập đến API. Chúng ta không thể tự tạo được Api Key này mà cần phải đăng ký hoặc nếu có rồi thì đăng nhâp để tạo ra Api Key cho mình.
Tìm hiểu về dữ liệu API trả về###
Trong bài này, chúng ta sẽ sử dụng API của phần Box Office Movie để lấy những thông tin phim chiếu trên rạp. Link site để lấy được thông tin phim đang chiếu ở rạp như sau: http://api.rottentomatoes.com/api/public/v1.0/lists/movies/box_office.json?apikey=<api-key-here>. Và dữ liệu trả về có dạng
"movies": [ { "id": "771321699", "title": "Star Wars: Episode VII - The Force Awakens", "year": 2015, "mpaa_rating": "PG-13", "runtime": 136, "critics_consensus": "", "release_dates": { "theater": "2015-12-18" }, "ratings": { "critics_rating": "Certified Fresh", "critics_score": 94, "audience_rating": "Upright", "audience_score": 91 }, "synopsis": "The Star Wars saga continues with this seventh entry -- the first under the Walt Disney Co. umbrella. The film will act as the start of a new trilogy set after the events of Return of the Jedi. J.J. Abrams directs from a script by Michael Arndt. ~ Jeremy Wheeler, Rovi", "posters": { "thumbnail": "http://resizing.flixster.com/6xF9PyshnlqT6g4OU9xVQFLnr9g=/54x80/dkpu1ddg7pbsk.cloudfront.net/movie/11/20/33/11203306_ori.jpg", "profile": "http://resizing.flixster.com/6xF9PyshnlqT6g4OU9xVQFLnr9g=/54x80/dkpu1ddg7pbsk.cloudfront.net/movie/11/20/33/11203306_ori.jpg", "detailed": "http://resizing.flixster.com/6xF9PyshnlqT6g4OU9xVQFLnr9g=/54x80/dkpu1ddg7pbsk.cloudfront.net/movie/11/20/33/11203306_ori.jpg", "original": "http://resizing.flixster.com/6xF9PyshnlqT6g4OU9xVQFLnr9g=/54x80/dkpu1ddg7pbsk.cloudfront.net/movie/11/20/33/11203306_ori.jpg" }, "abridged_cast": [ { "name": "Harrison Ford", "id": "162661579", "characters": [ "Han Solo" ] }, { "name": "Domhnall Gleeson", "id": "770702167", "characters": [ "Gen. Hux" ] }, { "name": "Daisy Ridley", "id": "771488369", "characters": [ "Rey" ] }, { "name": "John Boyega", "id": "771099376", "characters": [ "Finn" ] }, { "name": "Carrie Fisher", "id": "162663355", "characters": [ "Leia" ] } ], "alternate_ids": { "imdb": "2488496" }, "links": { "self": "http://api.rottentomatoes.com/api/public/v1.0/movies/771321699.json", "alternate": "http://www.rottentomatoes.com/m/star_wars_episode_vii_the_force_awakens/", "cast": "http://api.rottentomatoes.com/api/public/v1.0/movies/771321699/cast.json", "reviews": "http://api.rottentomatoes.com/api/public/v1.0/movies/771321699/reviews.json", "similar": "http://api.rottentomatoes.com/api/public/v1.0/movies/771321699/similar.json" } }, { "id": "771367711", "title": "Alvin and the Chipmunks: The Road Chip", "year": 2015, "mpaa_rating": "G", "runtime": 86, "critics_consensus": "", "release_dates": { "theater": "2015-12-18" }, "ratings": { "critics_rating": "Rotten", "critics_score": 16, "audience_rating": "Spilled", "audience_score": 59 }, "synopsis": "Through a series of misunderstandings, Alvin, Simon and Theodore come to believe that Dave is going to propose to his new girlfriend in Miami...and dump them. They have three days to get to him and stop the proposal, saving themselves not only from losing Dave but possibly from gaining a terrible stepbrother. (C) Fox", "posters": { "thumbnail": "http://resizing.flixster.com/HtMKMXfXTtInmIMmTCo-0q6N59s=/54x80/dkpu1ddg7pbsk.cloudfront.net/movie/11/20/27/11202773_ori.jpg", "profile": "http://resizing.flixster.com/HtMKMXfXTtInmIMmTCo-0q6N59s=/54x80/dkpu1ddg7pbsk.cloudfront.net/movie/11/20/27/11202773_ori.jpg", "detailed": "http://resizing.flixster.com/HtMKMXfXTtInmIMmTCo-0q6N59s=/54x80/dkpu1ddg7pbsk.cloudfront.net/movie/11/20/27/11202773_ori.jpg", "original": "http://resizing.flixster.com/HtMKMXfXTtInmIMmTCo-0q6N59s=/54x80/dkpu1ddg7pbsk.cloudfront.net/movie/11/20/27/11202773_ori.jpg" }, "abridged_cast": [ { "name": "Justin Long", "id": "162652679", "characters": [ "Alvin" ] }, { "name": "Matthew Gray Gubler", "id": "770692119", "characters": [ "Simon" ] }, { "name": "Jesse McCartney", "id": "519390858", "characters": [ "Theodore" ] }, { "name": "Kaley Cuoco-Sweeting", "id": "771514334", "characters": [ "Eleanor" ] }, { "name": "Christina Applegate", "id": "162663389", "characters": [ "Brittany" ] } ], "alternate_ids": { "imdb": "2974918" }, "links": { "self": "http://api.rottentomatoes.com/api/public/v1.0/movies/771367711.json", "alternate": "http://www.rottentomatoes.com/m/alvin_and_the_chipmunks_the_road_chip/", "cast": "http://api.rottentomatoes.com/api/public/v1.0/movies/771367711/cast.json", "reviews": "http://api.rottentomatoes.com/api/public/v1.0/movies/771367711/reviews.json", "similar": "http://api.rottentomatoes.com/api/public/v1.0/movies/771367711/similar.json" } },
Dữ liệu API trả về được lưu trong mảng movies và có nhiều các thông tin liên quan đến phim như tiêu đề, năm, và các hình ảnh,.... Ở ví dụ trên tôi đưa ra có 2 file là Star Wars: Episode VII - The Force Awakens và Alvin and the Chipmunks: The Road Chip được đánh giá khác nhau và các thông tin cũng khác nhau
Thiết lập thông số cho Android Studio###
Ở đây chúng ta sẽ sử dụng Android Studio để lập ra ứng dụng này, và đầu tiên ta cần thêm các thư viện bằng cách thêm vào file app/build.gradle
repositories { jcenter() } dependencies { // ... compile 'com.squareup.picasso:picasso:2.5.2' compile 'com.loopj.android:android-async-http:1.4.6' }
Tiếp đến ta cần xin quyền truy cập Internet để có thể lấy dữ liệu bằng cách sửa file AndroidManifest.xml ở phần manifest
<uses-permission android:name="android.permission.INTERNET" />
Sau đó tạo nên 1 App cơ bản ban đầu với giao diện là các list item.
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_awidth="match_parent" android:layout_height="match_parent" tools:context=".BoxOfficeActivity" > <ListView android:id="@+id/lvMovies" android:layout_awidth="match_parent" android:layout_height="wrap_content" android:layout_alignParentBottom="true" android:layout_alignParentLeft="true" android:layout_alignParentRight="true" android:layout_alignParentTop="true" > </ListView> </RelativeLayout>
Và sau khi build file sẽ ra giao diện đơn giản của ứng dụng như dưới
Gửi và lấy dữ liệu từ Rotten Tomatoes###
Như đã nói ở trên thì để lấy dữ liệu các phim trên rạp ta cần lấy từ link Api với Api Key đã tạo ra. Và để gọi đến Api này ta tạo ra 1 lớp RottenTomatoesClient để thực hiện điều này. Và nội dung file đó như sau:
public class RottenTomatoesClient { private final String API_KEY = "...getkey..."; private final String API_BASE_URL = "http://api.rottentomatoes.com/api/public/v1.0/"; private AsyncHttpClient client; public RottenTomatoesClient() { this.client = new AsyncHttpClient(); } private String getApiUrl(String relativeUrl) { return API_BASE_URL + relativeUrl; } public void getBoxOfficeMovies(JsonHttpResponseHandler handler) { String url = getApiUrl("lists/movies/box_office.json"); RequestParams params = new RequestParams("apikey", API_KEY); client.get(url, params, handler); } }
Tạo đối tượng Box Office Video
Như ta đã biết dữ liệu từ API trả về có rất nhiều thông tin khác nhau, trong ứng dụng này ta chỉ cần đến các thông tin cơ bản như title, year, synopsis, posters.thumbnail, ratings.critics_score và abridged_cast Class này có vai trò là 1 model của Box Office Video, ngoài việc nhận các biến đồng thời có hàm xử lý dữ liệu json và đưa dữ liệu vào các tham số tương ứng
public class BoxOfficeMovie { private String title; private int year; private String synopsis; private String posterUrl; private int criticsScore; private ArrayList<String> castList; public String getTitle() { return title; } public int getYear() { return year; } public String getSynopsis() { return synopsis; } public String getPosterUrl() { return posterUrl; } public int getCriticsScore() { return criticsScore; } public String getCastList() { return TextUtils.join(", ", castList); } public static BoxOfficeMovie fromJson(JSONObject jsonObject) { BoxOfficeMovie b = new BoxOfficeMovie(); try { b.title = jsonObject.getString("title"); b.year = jsonObject.getInt("year"); b.synopsis = jsonObject.getString("synopsis"); b.posterUrl = jsonObject.getJSONObject("posters").getString("thumbnail"); b.criticsScore = jsonObject.getJSONObject("ratings").getInt("critics_score"); b.castList = new ArrayList<String>(); JSONArray abridgedCast = jsonObject.getJSONArray("abridged_cast"); for (int i = 0; i < abridgedCast.length(); i++) { b.castList.add(abridgedCast.getJSONObject(i).getString("name")); } } catch (JSONException e) { e.printStackTrace(); return null; } // Return new object return b; } public static ArrayList<BoxOfficeMovie> fromJson(JSONArray jsonArray) { ArrayList<BoxOfficeMovie> movies = new ArrayList<BoxOfficeMovie>(jsonArray.length()); for (int i = 0; i < jsonArray.length(); i++) { JSONObject moviesJson = null; try { moviesJson = jsonArray.getJSONObject(i); } catch (Exception e) { e.printStackTrace(); continue; } BoxOfficeMovie movie = BoxOfficeMovie.fromJson(moviesJson); if (movie != null) { movies.add(movie); } } return movies; } }
Tạo adapter để nhập dữ liệu movie vào###
Sau khi đã lấy được dữ liệu từ API và gán vào model BoxOfficeVideo thì ta cần đưa từng video lấy được vào adapter rồi từ đó đưa vào lớp View. Đầu tiên cần khởi tạo adapter này:
public class BoxOfficeMoviesAdapter extends ArrayAdapter<BoxOfficeMovie> { public BoxOfficeMoviesAdapter(Context context, ArrayList<BoxOfficeMovie> aMovies) { super(context, 0, aMovies); } @Override public View getView(int position, View convertView, ViewGroup parent) { // TODO: Complete the definition of the view for each movie return null; } }
Đồng thời ta tạo file View để thể hiện bố cục của từng movie trong app
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_awidth="match_parent" android:layout_height="match_parent" android:padding="5dp" > <ImageView android:id="@+id/ivPosterImage" android:layout_awidth="wrap_content" android:layout_height="wrap_content" android:layout_centerVertical="true" android:maxHeight="70dp" android:scaleType="fitXY" android:adjustViewBounds="true" android:src="@drawable/small_movie_poster" /> <RelativeLayout android:layout_awidth="match_parent" android:layout_toRightOf="@+id/ivPosterImage" android:layout_centerVertical="true" android:gravity="center_vertical" android:layout_marginLeft="10dp" android:layout_height="match_parent"> <TextView android:id="@+id/tvTitle" android:layout_awidth="wrap_content" android:layout_height="wrap_content" android:layout_alignParentTop="true" android:textStyle="bold" android:hint="The Dark Knight" android:textSize="12sp" /> <TextView android:id="@+id/tvCriticsScore" android:layout_awidth="wrap_content" android:layout_height="wrap_content" android:layout_alignLeft="@+id/tvTitle" android:layout_below="@+id/tvTitle" android:hint="91%" android:textSize="12sp" /> <TextView android:id="@+id/tvCast" android:layout_awidth="wrap_content" android:layout_height="wrap_content" android:layout_below="@+id/tvCriticsScore" android:maxLines="1" android:ellipsize="end" android:hint="Christian Bale, Joseph-Gordon Levitt, Heath Ledger, Maggie Gylenhall" android:textSize="12sp" /> </RelativeLayout> </RelativeLayout>
Sau khi có View rồi, tiếp theo là việc nhập dữ liệu vào từng id mà đã thiết lập ở file view trên
public class BoxOfficeMoviesAdapter extends ArrayAdapter<BoxOfficeMovie> { @Override public View getView(int position, View convertView, ViewGroup parent) { // Get the data item for this position BoxOfficeMovie movie = getItem(position); // Check if an existing view is being reused, otherwise inflate the view if (convertView == null) { LayoutInflater inflater = LayoutInflater.from(getContext()); convertView = inflater.inflate(R.layout.item_box_office_movie, parent, false); } TextView tvTitle = (TextView) convertView.findViewById(R.id.tvTitle); TextView tvCriticsScore = (TextView) convertView.findViewById(R.id.tvCriticsScore); TextView tvCast = (TextView) convertView.findViewById(R.id.tvCast); ImageView ivPosterImage = (ImageView) convertView.findViewById(R.id.ivPosterImage); tvTitle.setText(movie.getTitle()); tvCriticsScore.setText("Score: " + movie.