仿抖音安卓apk演示:https://pan.baidu.com/s/1WoCU5cUFYC3T4zoV3mh3uQ
視頻可以批量上傳:http://7.wjsou.com
開發環境:ADT (Eclipse) 或Android Studio 導入可以二次開發。
功能:模仿抖音app,可以離線看視頻,批量上傳視頻,調進度,右邊滑動調節聲音,左邊翻頁,自動同步更新遠程上傳視頻,記錄位置
服務器內容:
其中的video_version.txt格式內容:
[{"NO":"1","Name":"model.mp4"},{"NO":"2","Name":"adv.mp4"}]
NO沒有使用。可以不寫。只用把視頻名稱Name加入就行。
使用說明:
把serverupdatefile文件夾下的視頻文件及視頻配置文件video_version.txt放到服務器上。
如果要放在你服務器上,請改寫項目下面路徑:
源碼:
package com.example.video;
import java.io.File;
import android.app.Activity;
import android.content.Context;
import android.content.SharedPreferences;
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.text.format.Time;
import android.util.Log;
import android.view.Display;
import android.view.GestureDetector;
import android.view.GestureDetector.SimpleOnGestureListener;
import android.view.Menu;
import android.view.MenuItem;
import android.view.MotionEvent;
import android.view.View;
import android.widget.LinearLayout;
import android.widget.MediaController;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;
import android.widget.VideoView;
public class PlayActivity extends Activity {
public boolean nextFlag=false;
public float f=0;
public static final String CURRENT="current"; //配置項:當前播放位置
private GestureDetector mGestureDetector;
/** 最大聲音 */
private int mMaxVolume;
/** 當前聲音 */
private int mVolume = -1;
private AudioManager mAudioManager;
private int current=0;
private UpdateManager updateMan;
//private ProgressDialog updateProgressDialog;
private VideoView videoView;
private LinearLayout ll_update_content;
private TextView tv_update_content;
private ProgressBar progressbar_update_content;
private TextView tv_volume;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_play);
videoView = (VideoView) findViewById(R.id.videoView1);
MediaController controller = new MediaController(this);
videoView.setMediaController(controller);
ll_update_content = (LinearLayout) findViewById(R.id.update_content);
tv_update_content = (TextView) findViewById(R.id.textView_update_content);
progressbar_update_content = (ProgressBar) findViewById(R.id.progressBar1);
ll_update_content.setVisibility(View.GONE);
tv_volume= (TextView) this.findViewById(R.id.textViewVolume);
tv_volume.setVisibility(View.GONE);
mAudioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
mMaxVolume = mAudioManager
.getStreamMaxVolume(AudioManager.STREAM_MUSIC);
mGestureDetector = new GestureDetector(this, new MyGestureListener());
//沒有判斷網路是否連接的提示
//檢查是否有更新
//如果有更新提示下載
updateMan = new UpdateManager(PlayActivity.this, appUpdateCb);
//讀取當前播放位置
SharedPreferences sharedata1 = getSharedPreferences(UpdateManager.CONFIG, 0);
current = sharedata1.getInt(CURRENT, 0);
if(current>=updateMan.localSaveName.size())
current=0;
play();
updateMan.checkUpdate();
//limited();
}
public void saveCurrent() // 保存當前播放位置
{
SharedPreferences.Editor sharedata = getSharedPreferences(UpdateManager.CONFIG, 0).edit();
sharedata.putInt(CURRENT, current);
sharedata.commit();
}
public void play()
{
try{
if(updateMan.localSaveName.size()>0)
{
playVideo();
}
else
Toast.makeText(this, "沒有要播放的視頻,請在服務器上更新2", Toast.LENGTH_SHORT).show();
}catch(Exception e){
Toast.makeText(this, "沒有要播放的視頻,請在服務器上更新1", Toast.LENGTH_SHORT).show();
}
}
public void playVideo()
{
//下面android:resource://是固定的,org.dengzh是我的包名,不是.java文件package名稱,R.raw.movie_1是id名稱
//videoView.setVideoURI(Uri.parse("android.resource://com.example.video/"+R.raw.video));
//videoView.setVideoURI(Uri.parse(updateMan.savefolder+updateMan.localSaveName.get(i)));
videoView.setVideoPath(updateMan.savefolder+updateMan.localSaveName.get(current));
//監聽視頻播放完的代碼
videoView.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
@Override
public void onCompletion(MediaPlayer mPlayer) {
// TODO Auto-generated method stub
current++;
if(current>=updateMan.localSaveName.size())
current=0;
videoView.setVideoPath(updateMan.savefolder+updateMan.localSaveName.get(current));
videoView.start();
saveCurrent(); // 保存當前播放位置
// 提示
tv_volume.setText(""+current+" "+updateMan.localSaveName.get(current));
// 顯示
tv_volume.setVisibility(View.VISIBLE);
// 隱藏
mDismissHandler.removeMessages(0);
mDismissHandler.sendEmptyMessageDelayed(0, 500);
}
});
/* 開始播放視頻 */
videoView.start();
/* 請求獲取焦點 */
//videoView.requestFocus();
}
void limited() {
Time t = new Time(); // or Time t=new Time("GMT+8"); 加上Time Zone資料。
t.setToNow(); // 取得系統時間。
String time = t.year + "年 " + (t.month + 1) + "月 " + t.monthDay + "日 "
+ t.hour + "h " + t.minute + "m " + t.second;
Log.e("msg", time);
//if (t.year == 2014 && t.month + 1 == 9 && t.monthDay == 23) 測試
if(t.year!=2017 )//這個月 || (t.month+1)!=11
// if(t.year!=2014 || (t.month+1)!=9||t.monthDay!=23) //今天
{
Toast.makeText(this,"調用版時間到自動退出,請聯繫軟件作者QQ:40078329" ,
Toast.LENGTH_LONG).show();
new Handler().postDelayed(new Runnable(){ //延遲執行
@Override
public void run(){
android.os.Process
.killProcess(android.os.Process
.myPid()); // 終止線程
}
}, 3000);
}
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.play, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
if (id == R.id.action_delete) {
for(int i=0;i<UpdateManager.localSaveName.size();i++)
{
File filefolder = new File(UpdateManager.savefolder);
//判斷文件夾是否存在,如果不存在就創建,否則不創建
if (!filefolder.exists()) {
filefolder.mkdirs();
}
File File = new File(UpdateManager.savefolder,UpdateManager.localSaveName.get(i));
if(File.exists())
{
File.delete();
}
}
SharedPreferences.Editor sharedata = getSharedPreferences(UpdateManager.CONFIG, 0).edit();
sharedata.clear();
sharedata.commit();
UpdateManager.localSaveName.clear();
Toast.makeText(this, "已經刪除所有本地文件", Toast.LENGTH_SHORT).show();
return true;
}
return super.onOptionsItemSelected(item);
}
// 自動更新回調函數
UpdateManager.UpdateCallback appUpdateCb = new UpdateManager.UpdateCallback()
{
public void downloadProgressChanged(int progress) {
progressbar_update_content.setProgress(progress);
}
public void downloadCompleted(Boolean sucess, CharSequence errorMsg) {
ll_update_content.setVisibility(View.GONE);
if (sucess) {
updateMan.update();
if(!videoView.isPlaying())
play(); //播放操作
if(updateMan.needSaveName.size()>0)
updateMan.checkUpdate(); //繼續更新下一個
} else {
tv_update_content.setText("下載出錯,正在重試:");
updateMan.downloadPackage();
}
}
public void downloadCanceled()
{
// TODO Auto-generated method stub
}
public void checkUpdateCompleted(Boolean hasUpdate,
CharSequence updateInfo) {
if (hasUpdate) {
ll_update_content.setVisibility(View.VISIBLE);
tv_update_content.setText("正在更新:"+updateInfo);
progressbar_update_content.setMax(100);
progressbar_update_content.setProgress(0);
updateMan.downloadPackage();
}
}
};
@Override
public boolean onTouchEvent(MotionEvent event) {
if (mGestureDetector.onTouchEvent(event))
return true;
// 處理手勢結束
switch (event.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_UP:
endGesture();
break;
}
return super.onTouchEvent(event);
}
/** 手勢結束 */
private void endGesture() {
if(nextFlag)
{
onNextSlide(f);
nextFlag=false;
}
mVolume = -1;
// 隱藏
mDismissHandler.removeMessages(0);
mDismissHandler.sendEmptyMessageDelayed(0, 500);
}
private class MyGestureListener extends SimpleOnGestureListener {
/** 滑動 */
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2,
float distanceX, float distanceY) {
float mOldX = e1.getX(), mOldY = e1.getY();
int y = (int) e2.getRawY();
Display disp = getWindowManager().getDefaultDisplay();
int windowWidth = disp.getWidth();
int windowHeight = disp.getHeight();
if (mOldX > windowWidth * 4.0 / 5)// 右邊滑動
onVolumeSlide((mOldY - y) / windowHeight);
else if (mOldX < windowWidth / 5.0)// 左邊滑動
{
nextFlag=true;
f=(mOldY - y) / windowHeight;
//onNextSlide((mOldY - y) / windowHeight);
}
return super.onScroll(e1, e2, distanceX, distanceY);
}
}
/** 定時隱藏 */
private Handler mDismissHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
tv_volume.setVisibility(View.GONE);
}
};
private void onNextSlide(float f) {
if(f>0)
current++;
else
current--;
if(current>=updateMan.localSaveName.size())
current=0;
if(current<0)
current=updateMan.localSaveName.size()-1;
play();
// 提示
tv_volume.setText(""+current+" "+updateMan.localSaveName.get(current));
// 顯示
tv_volume.setVisibility(View.VISIBLE);
}
/**
* 滑動改變聲音大小
*
* @param percent
*/
private void onVolumeSlide(float percent) {
if (mVolume == -1) {
mVolume = mAudioManager.getStreamVolume(AudioManager.STREAM_MUSIC);
if (mVolume < 0)
mVolume = 0;
// 顯示
tv_volume.setVisibility(View.VISIBLE);
}
int index = (int) (percent * mMaxVolume) + mVolume;
if (index > mMaxVolume)
index = mMaxVolume;
else if (index < 0)
index = 0;
// 變更聲音
mAudioManager.setStreamVolume(AudioManager.STREAM_MUSIC, index, 0);
// 變更進度條
tv_volume.setText("音量:"+index*100/mMaxVolume+"%");
}
}
package com.example.video;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import org.json.JSONArray;
import org.json.JSONObject;
import com.trinet.util.NetHelper;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager.NameNotFoundException;
import android.net.Uri;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
public class UpdateManager {
private UpdateCallback callback;
private Context ctx;
private int progress;
private Boolean hasNewVersion;
private Boolean canceled;
//存放更新文件的路徑
// public static final String UPDATE_DOWNURL = "http://wjsou.com/dropzone/uploads/BluetoothChatFile.apk";
//存放更新文件相應的版本說明路徑
public static final String UPDATE_CHECKURL = "http://wjsou.com/dropzone/uploads/video_version.txt";
public static final String updateDownUrlPre="http://wjsou.com/dropzone/uploads/";
// public static String saveName;
public List<String> needSaveName= new ArrayList<String>();
public static List<String> localSaveName= new ArrayList<String>();
public static final String CONFIG="config"; //配置文件
//APK文件名
// public static final String UPDATE_SAVENAME = "BluetoothChatFile.apk";
//public static final String UPDATE_APKNAME = "update_test.apk";
//public static final String UPDATE_VERJSON = "ver.txt";
private static final int UPDATE_CHECKCOMPLETED = 1;
private static final int UPDATE_DOWNLOADING = 2;
private static final int UPDATE_DOWNLOAD_ERROR = 3;
private static final int UPDATE_DOWNLOAD_COMPLETED = 4;
private static final int UPDATE_DOWNLOAD_CANCELED = 5;
//從服務器上下載apk存放文件夾
public static String savefolder = "/storage/emulated/0/xiaoying/";
// private String savefolder = "/mnt/innerDisk/";
//private String savefolder = "/sdcard/";
//public static final String SAVE_FOLDER =Storage. // "/mnt/innerDisk";
public UpdateManager(Context context, UpdateCallback updateCallback) {
ctx = context;
callback = updateCallback;
//savefolder = context.getFilesDir();
canceled = false;
readLocalSaveName();
}
private void readLocalSaveName() //讀出所有保存的文件名
{
// 讀取設置數據
SharedPreferences sharedata1 = ctx.getSharedPreferences(CONFIG, 0);
for(int i=0;;i++)
{
String stringName = sharedata1.getString(String.valueOf(i), null);
if(stringName==null)
{
break;
}
localSaveName.add(stringName);
Log.i("localSaveName", stringName+ "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
}
}
public void checkUpdate() {
hasNewVersion = false;
new Thread(){
@Override
public void run() {
Log.i("@@@@@", ">>>>>>>>>>>>>>>>>>>>>>>>>>>getServerVerCode() ");
try {
String verjson = NetHelper.httpStringGet(UPDATE_CHECKURL);
Log.i("@@@@", verjson
+ "**************************************************");
JSONArray array = new JSONArray(verjson);
if(array.length()>0){
for(int i=0;i<array.length();i++) {
JSONObject obj = array.getJSONObject(i);
try {
String name=obj.getString("Name");
Log.i("Name", name+ "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
// if(i<localSaveName.size()&& !localSaveName.get(i).equals(name))
// {
// //更新原位置文件,完成後刪除原位置的不同名文件
// //position=i;
//
// }
if(!localSaveName.contains(name)) //不存在,就需要保存
{
needSaveName.add(name);
Log.i("needSaveName", name+ "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
hasNewVersion = true;
}
} catch (Exception e) {
}
}
}
} catch (Exception e) {
Log.e("update", e.getMessage());
}
updateHandler.sendEmptyMessage(UPDATE_CHECKCOMPLETED);
};
// ***************************************************************
}.start();
}
public void update() { //下載完成一個後,加入保存到本地庫中,刪除需要下載列表的已經下載成功的.
SharedPreferences.Editor sharedata = ctx.getSharedPreferences(CONFIG, 0).edit();
sharedata.putString(String.valueOf(localSaveName.size()),needSaveName.get(0));
sharedata.commit();
localSaveName.add(needSaveName.get(0));
needSaveName.remove(needSaveName.get(0));
}
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
public void downloadPackage()
{
new Thread() {
@Override
public void run() {
try {
URL url = new URL(updateDownUrlPre+needSaveName.get(0));
HttpURLConnection conn = (HttpURLConnection)url.openConnection();
conn.connect();
int length = conn.getContentLength();
InputStream is = conn.getInputStream();
File filefolder = new File(savefolder);
//判斷文件夾是否存在,如果不存在就創建,否則不創建
if (!filefolder.exists()) {
filefolder.mkdirs();
}
File File = new File(savefolder,needSaveName.get(0));
if(File.exists())
{
File.delete();
}
FileOutputStream fos = new FileOutputStream(File);
int count = 0;
byte buf[] = new byte[512];
do{
int numread = is.read(buf);
count += numread;
progress =(int)(((float)count / length) * 100);
updateHandler.sendMessage(updateHandler.obtainMessage(UPDATE_DOWNLOADING));
if(numread <= 0){
updateHandler.sendEmptyMessage(UPDATE_DOWNLOAD_COMPLETED);
break;
}
fos.write(buf,0,numread);
}while(!canceled);
if(canceled)
{
updateHandler.sendEmptyMessage(UPDATE_DOWNLOAD_CANCELED);
}
fos.close();
is.close();
} catch (MalformedURLException e) {
e.printStackTrace();
updateHandler.sendMessage(updateHandler.obtainMessage(UPDATE_DOWNLOAD_ERROR,e.getMessage()));
} catch(IOException e){
e.printStackTrace();
updateHandler.sendMessage(updateHandler.obtainMessage(UPDATE_DOWNLOAD_ERROR,e.getMessage()));
}
}
}.start();
}
public void cancelDownload()
{
canceled = true;
}
Handler updateHandler = new Handler()
{
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case UPDATE_CHECKCOMPLETED:
if(hasNewVersion)
callback.checkUpdateCompleted(hasNewVersion,needSaveName.get(0));
break;
case UPDATE_DOWNLOADING:
callback.downloadProgressChanged(progress);
break;
case UPDATE_DOWNLOAD_ERROR:
callback.downloadCompleted(false, msg.obj.toString());
break;
case UPDATE_DOWNLOAD_COMPLETED:
callback.downloadCompleted(true, "");
break;
case UPDATE_DOWNLOAD_CANCELED:
callback.downloadCanceled();
default:
break;
}
}
};
public interface UpdateCallback {
public void checkUpdateCompleted(Boolean hasUpdate, CharSequence updateInfo);
public void downloadProgressChanged(int progress);
public void downloadCanceled();
public void downloadCompleted(Boolean sucess, CharSequence errorMsg);
}
}