仿抖音安卓apk演示:链接:https://pan.baidu.com/s/13vk9JSfDohX1To34lz2YMw 提取码:nr15
视频可以批量上传:http://6.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) //今天
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);
}
}