Android video client design and implementation

Source: Internet
Author: User

1. Preface
Recently, I am developing an android mobile client for the website video module. Through the mobile client, I can easily browse the video content of the website. Most of the video content of the website is in flv and mp4 formats, the following are the parts of the mobile client:

The following describes the development process and precautions of the author.

2. Development Tools
The project is built based on Android Studio IDE. Android Studio was launched at the 2013 google I/O developer conference. It is built based on IntelliJ idea and android studio has been updated and improved. Today it has reached the 0.4.6 preview version, I estimate that this year's 2014 google I/O conference will reach the 1.0 stable version. Some people are worried that the migration from Eclipse to Android Studio is not adaptive, unstable, and affects the development progress. Here, the author's personal experience tells you that Android Studio is really easy to use, in addition, the development progress is greatly improved. Android Studio is the future direction! Android Studio also integrates the advanced Gradle build system. This project is also built based on the Gradle project. It is very convenient for Android projects to rely on Library projects, you can see google official documentation http://tools.android.com/tech-docs/new-build-system/user-guide,Android Studio also integrated VCS version control system, the author can easily submit the source code to github.

3. Build an Android client project
The establishment of this project refers to AnimeTaste designed by the coders. Thank you for your open source! The following describes the implementation method: the mobile client sends an http request to the server, the server api returns json data, the mobile client parses json data, and then displays the data in listview.
(1) directory structure of the project


(2) The LoadActivity of the project is the main Activity startup interface of the app. The init () method mainly obtains data from the server for initialization, and the data returned by the server is in JSONArray format, that is, the variable response, through intent. putExtra ("LoadData", response. toString () puts the data in the intent to pass the data to StartActivity.

Package com. zyy360.app; import android. app. alertDialog; import android. content. context; import android. content. dialogInterface; import android. content. dialogInterface. onClickListener; import android. content. intent; import android. support. v7.app. actionBarActivity; import com. loopj. android. http. jsonHttpResponseHandler; import com. zyy360.app. core. dataVideoFetcher; import com. zyy360.app. ui. startActivity; import Android. OS. bundle; import android. util. log; import android. widget. toast; import org. json. JSONArray;/*** @ author daimajia * @ modified Foxhu * @ version 1.0 */public class LoadActivity extends ActionBarActivity {private Context mContext; @ Override protected void onCreate (Bundle savedInstanceState) {super. onCreate (savedInstanceState); if (getsuppactionactionbar ()! = Null) {getSupportActionBar (). hide ();} mContext = this; setContentView (R. layout. activity_load); if (NetworkUtils. isWifi (mContext) = false) {AlertDialog. builder builder = new AlertDialog. builder (mContext ). setTitle (R. string. only_wifi_title ). setMessage (R. string. only_wifi_body); builder. setCancelable (false); // if user click OK then init data builder. setPositiveButton (R. string. only_wifi_ OK, new OnCl IckListener () {@ Override public void onClick (DialogInterface dialog, int which) {dialog. dismiss (); init () ;}}); // if user click quit then finish () builder. setNegativeButton (R. string. only_wifi_cancel, new OnClickListener () {@ Override public void onClick (DialogInterface dialog, int which) {finish () ;}}); builder. create (). show () ;}else {init () ;}/ *** init data */private void init () {DataVi DeoFetcher. instance (). getList (0, new JsonHttpResponseHandler () {/*** The server returns data format like * [{"name": "cordyceps", "path ": "_ 152747_61dP.flv", "video_pic": "20131025/second", "video_thumbpic": "20131025/IMG_BjTA_25_s.jpg", "introduce": "cordyceps effect. "," ___ Key_id ": 25}, * {" name ":" windproof? "," Path ":" 2013/10/25 _ 152557_pmYc.flv "," video_pic ":" 20131025/Hangzhou "," video_thumbpic ":" 20131025/IMG_3b76_24_s.jpg "," introduce ": "extract table medicine, qufeng medicine", "___ key_id": 24}] * reference effecnets * http://loopj.com/android-async-http/doc/com/loopj/android/http/JsonHttpResponseHandler.html * @ param statusCode * @ param response */@ Override public void onSuccess (int statusCode, JSONArray response) {super. onSuccess (statusCode, response); System. out. println ("jsonArray->" + response); Intent intent = new Intent (LoadActivity. this, StartActivity. class); if (statusCode = 200 & response. length ()> 0) {try {intent. putExtra ("LoadData", response. toString (); startActivity (intent); finish ();} catch (Exception e) {e. printStackTrace () ;}} else {}}@ Override public void onFailure (Throwable e, JSONArray errorResponse) {super. onFailure (e, errorResponse); System. out. println ("jsonArray->" + errorResponse); Toast. makeText (getApplicationContext (), R. string. error_load, Toast. LENGTH_SHORT ). show (); startActivity (new Intent (mContext, StartActivity. class); finish () ;}}) ;}@ Override protected void onResume () {super. onResume () ;}@ Override protected void onPause () {super. onPause ();}}
(3) DataVideoFetcher is through the use of android-async-http this library to achieve the server side to send post or get requests, for android-async-http use, please refer to my previous blog http://blog.csdn.net/hil2000/article/details/13949513
package com.zyy360.app.core;import com.loopj.android.http.AsyncHttpClient;import com.loopj.android.http.JsonHttpResponseHandler;/** * @author daimajia * @modified Foxhu * @version 1.0 */public class DataVideoFetcher {    private static DataVideoFetcher mInstance;    //request url with parameter page    private static final String mRequestListUrl = "http://192.168.0.101:8080/action/api/videoList?page=%d";    private DataVideoFetcher() {    }    public static DataVideoFetcher instance() {        if (mInstance == null) {            mInstance = new DataVideoFetcher();        }        return mInstance;    }    /**     * get data from server by AsyncHttpClient     * @param page     * @param handler     */    public void getList(int page,JsonHttpResponseHandler handler){        AsyncHttpClient client = new AsyncHttpClient();        String request = String.format(mRequestListUrl,page);        //get json data from server        client.get(request,null,handler);    }}
The new JsonHttpResponseHandler () in the DataVideoFetcher. instance (). getList () of LoadActivity overwrites onSuccess and onFailure.
(4) StartActivity get getIntent (). hasExtra ("LoadData") to get the passed data
if (getIntent().hasExtra("LoadData")) {            init(getIntent().getStringExtra("LoadData"));        } else {            init();        }
Init indicates the initialization data.
public void init(String data) {        try {            JSONArray videoList = new JSONArray(data);            if (videoList != null) {                new AddToDBThread(videoList).start();            }            mVideoAdapter = VideoListAdapter.build(mContext, videoList, true);            mVideoList.setAdapter(mVideoAdapter);        } catch (JSONException e) {            e.printStackTrace();        }    }
Among them, mVideoAdapter = VideoListAdapter. build (mContext, videoList, true); build Based on JsonArray data. Let's take a look at the builde method build of VideoListAdapter (Context context, JSONArray data, Boolean checkIsWatched)
public static VideoListAdapter build(Context context, JSONArray data,                                         Boolean checkIsWatched) throws JSONException {        ArrayList
 
   videos = new ArrayList
  
   ();        for (int i = 0; i < data.length(); i++) {            videos.add(VideoDataFormat.build(data.getJSONObject(i)));        }        return new VideoListAdapter(context, videos, checkIsWatched);    }
  
 
Videos. add (VideoDataFormat. build (data. getJSONObject (I); parse the JSONObjec object using the build method of VideoDataFormat. The VideoDataFormat class is as follows:
Package com. zyy360.app. model; import android. database. cursor; import org. json. JSONObject; import org. json. JSONException; import java. io. serializable;/*** @ author Foxhu * @ version 1.0 */public class VideoDataFormat implements Serializable {public Integer id; public String name; // video name public String path; // video address public String video_pic; // video image public String video_thumbpic; // video thumbnail public String introduce; // video description public String create_time; // thumbnail address http: // 192.168.0.101: 8080/uploads/videopics/20131025/IMG_BjTA_25_s.jpg // large image address http: // 192.168.0.101: 8080/uploads/videopics/20131025/IMG_BjTA_25_ B .jpg/video address http: /// 192.168.0.101: 8080/uploads/videofiles/2013/10/25 _ Empty private boolean IsWatched; private final String VideoUrlFormat = "http: // 192.168.0.101: 8080/uploads/videofiles/% s "; private final String PicUrlFormat = "http: // 192.168.0.101: 8080/uploads/videopics/% s"; public static final String NONE_VALUE = "-1"; private VideoDataFormat (Integer id, string name, String path, String video_pic, String video_thumbPic, String introduce, String create_time) {super (); this. id = id; this. name = name; this. path = String. format (VideoUrlFormat, path); // construct the complete url address this. video_pic = String. format (PicUrlFormat, video_pic); this. video_thumbpic = String. format (PicUrlFormat, video_thumbPic); this. introduce = introduce; this. create_time = create_time;} private VideoDataFormat (JSONObject object) {id = Integer. valueOf (getValue (object, "___ key_id"); name = getValue (object, "name"); path = String. format (VideoUrlFormat, getValue (object, "path"); video_pic = String. format (PicUrlFormat, getValue (object, "video_pic"); video_thumbpic = String. format (PicUrlFormat, getValue (object, "video_thumbpic"); introduce = getValue (object, "introduce"); create_time = getValue (object, "create_time "); isWatched = false;} private static String getValue (JSONObject object, String key) {try {return object. getString (key);} catch (JSONException e) {e. printStackTrace ();} return NONE_VALUE;} public boolean isWatched () {return IsWatched;} public void setWatched (Boolean watch) {IsWatched = watch;} public static VideoDataFormat build (JSONObject object) {return new VideoDataFormat (object);} public static VideoDataFormat build (Cursor cursor) {int id = cursor. getInt (cursor. getColumnIndex ("id"); String name = cursor. getString (cursor. getColumnIndex ("name"); String path = cursor. getString (cursor. getColumnIndex ("path"); String video_pic = cursor. getString (cursor. getColumnIndex ("video_pic"); String video_thumbPic = cursor. getString (cursor. getColumnIndex ("video_thumbpic"); String introduce = cursor. getString (cursor. getColumnIndex ("introduce"); String create_time = cursor. getString (cursor. getColumnIndex ("create_time"); return new VideoDataFormat (id, name, path, video_pic, video_thumbPic, introduce, create_time );}}
(5) getView () method in VideoListAdapter

@ Override public View getView (int position, View convertView, ViewGroup parent) {TextView titleTextView; TextView contentTextView; ImageView thumbImageView; ViewHolder holder; if (convertView = null) {convertView = callback. inflate (R. layout. video_item, parent, false); titleTextView = (TextView) convertView. findViewById (R. id. title); contentTextView = (TextView) convertView. findViewById (R. id. content); thumbImageView = (ImageView) convertView. findViewById (R. id. thumb); holder = new ViewHolder (titleTextView, contentTextView, thumbImageView); convertView. setTag (holder);} else {holder = (ViewHolder) convertView. getTag (); titleTextView = holder. titleText; contentTextView = holder. contentText; thumbImageView = holder. thumbImageView;} VideoDataFormat video = (VideoDataFormat) getItem (position); Picasso. with (mContext ). load (video. video_thumbpic ). placeholder (R. drawable. placeholder_thumb ). error (R. drawable. placeholder_fail ). into (thumbImageView); titleTextView. setText (video. name); contentTextView. setText (video. introduce); convertView. setOnClickListener (new VideoListItemListener (mContext, this, video); convertView. setOnLongClickListener (new View. onLongClickListener () {// ensure that long-pressed events are passed @ Override public boolean onLongClick (View v) {return false ;}}); if (video. isWatched () = true) {titleTextView. setTextColor (mWatchedTitleColor);} else {titleTextView. setTextColor (mUnWatchedTitleColor);} return convertView ;}
This function is used to load data to view controls. The image data is loaded using a third-party image cache library Picasso (picasso is an open-source Android image cache library of Square. The address is http://square.github.io/picasso/, which can download and save real ), set the listener convertView for view entries. setOnClickListener (new VideoListItemListener (mContext, this, video );
(6) VideoListItemListener: Click the listener class to start PlayActivity when you click an entry.
@Override    public void onClick(View v) {        Intent intent = new Intent(mContext, PlayActivity.class);        intent.putExtra("VideoInfo", mData);        mContext.startActivity(intent);        mVideoDB.insertWatched(mData);        if (mAdapter != null) {            if (mData.isWatched() == false)                mAdapter.setWatched(mData);        }    }
(7) PlayActivity class. This class uses a third-party Video Player Library vitamio for video playback. For more information about vitamio, see https://github.com/yixia/vitamiobundle. for more information about playactivity, see the githubsource. This section describes how to introduce a third-party library project to the Android project. Because Android Studio projects are built using Gradle, the introduction of library projects is different from that of Eclipse. The main steps are as follows. Here we take vitamio as an example:
① Create the libraries folder in the root directory
② Copy vitamio to the libraries folder
③ Modify settings. gradle
include ':app'include(':libraries:vitamio')
④. Modify the build. gradle file of the app
dependencies {    compile 'com.android.support:support-v4:19.0.+'    compile 'com.android.support:appcompat-v7:+'    compile fileTree(dir: 'libs', include: '*.jar')    compile project(':libraries:vitamio')}
After the above modifications, remember to Sync project with Gradle Files

4. server-side API design
The server receives http requests from users, obtains parameters through ctx. param, queries data from the database, and converts list data into JSONArray data and returns it to the client using google's GSON library.

Package com. cmsis. action; import java. io. IOException; import java. util. list; import javax. servlet. servletException; import com. cmsis. beans. video; import com. google. gson. gson;/***** @ author Foxhu **/public class ApiAction extends BaseAction {private static final String homeIds = "order by id desc "; /*** website video client api. The returned data format is JsonArray * @ param ctx * @ throws IOException */public void videoList (RequestContex T ctx) throws IOException {int pageno = ctx. param ("page", 1); // obtain the page number of the mobile client request pageno = pageno <= 0? 1: pageno; List
 
  
Ids = Video. INSTANCE. IDs (homeIds); // obtain the loaded data from the cache. idint size = ids. size (); int beginIndex = (pageno-1) * 10; // 10 records per page int toIndex = pageno * 10; List
  
   
ReturnIds = ids. subList (beginIndex> size? Size: beginIndex), (toIndex> size? Size: toIndex); List
   
    
List = Video. INSTANCE. loadList (returnIds); // load data according to id Gson gson = new Gson (); String jsonList = gson. toJson (list. toArray (); System. out. println ("json->" + jsonList); ctx. print (jsonList );}}
   
  
 
Github Source Code address: https://github.com/puma007/Zyy360


Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.