内容比较简单,仅用作笔记,所以就不过多解释,有一些地方代码思路不是很清晰,有点乱,日后会进行修改的。
1、新建一个SoundPool管理器,实现soundpool的创建,加载以及播放音频等功能
package com.example.myexplorer;
import java.util.Random;
import android.annotation.SuppressLint;
import android.content.Context;
import android.media.AudioAttributes;
import android.media.SoundPool;
import android.media.SoundPool.OnLoadCompleteListener;
import android.os.Build;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.util.SparseArray;
public class SoundPoolManager implements OnLoadCompleteListener{
Context context;
SoundPool soundPool;
MyHandler myHandler;
private final int SOUND_LOAD_OK=1;
//创建一个SpareseArray对象来存放管理音频资源
private SparseArray<Object> soundMap=new SparseArray<>();
//实现构造函数,传递context
public SoundPoolManager(Context context) {
// TODO Auto-generated constructor stub
this.context=context;
}
/*
* 创建一个SoundPool池,回调时需要指定创建的池的最大可容纳数量,声音类型以及音频品质
*/
@SuppressLint("NewApi")
@SuppressWarnings("deprecation")
protected void creatSounPool(int maxStreams,int streamType,int srcQuality) {
if(Build.VERSION.SDK_INT>=21) { //判断为安卓5以上时使用该方法创建,否则5.0以上系统不会播放
AudioAttributes abs = new AudioAttributes.Builder()
.setUsage(AudioAttributes.USAGE_MEDIA)
.setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
.build() ;
soundPool=new SoundPool.Builder()
.setMaxStreams(5)
.setAudioAttributes(abs)
.build(); //创建一个SoundPool对象,该对象可以容纳5个音频流
}
else
soundPool=new SoundPool(maxStreams,streamType,srcQuality); //安卓5以下的soundpool创建方法
Log.i("SoundPoolCreat","successfull");
}
/*
* 加载资源到创建好的SoundPool里面,需要提供音频资源名称以及优先级
*/
protected void load(String[] ResourcesName,int priority) {
for(int i=0;i<ResourcesName.length;i++) {
soundMap.put(i,soundPool.load(context,context.getResources().
getIdentifier("com.example.myexplorer:raw/"+ResourcesName[i]
,null,null) ,priority));
Log.i("SoundPoolLoad"+i,"successfull");
}
soundPool.setOnLoadCompleteListener(this);
}
/*
* 开始播放,要求提供左声道音量leftVolume,右声道音量rightVolume,播放优先级priority,是否循环loop(0为不循环,1为循环)
* 播放速率rate
*/
protected void play(float leftVolume,
float rightVolume,int priority,int loop,float rate) {
int i=0;
//随机播放加载的三个背景音乐
soundPool.play((int)soundMap.get((int)(new Random().nextInt(3))), //产生等概率0-2的随机数
leftVolume, rightVolume, priority, loop, rate);
Log.i("SoundPoolPlay"+(i++),"successfull");
}
/*
* 设置加载完成监听,防止未加载完成就播放
*/
@SuppressLint("HandlerLeak")
@Override
public void onLoadComplete(SoundPool soundPool, int sampleId, int status) {
// TODO Auto-generated method stub
Log.i("Load","Complete");
myHandler=new MyHandler();
Message message=myHandler.obtainMessage();
message.what=SOUND_LOAD_OK;
myHandler.sendMessage(message);
}
@SuppressLint("HandlerLeak")
public class MyHandler extends Handler{
private final int SOUND_LOAD_OK=1;
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case SOUND_LOAD_OK:
//这里添加加载完成后需要做的事
//play(1, 1, 0, 0, 1);
break;
default:
break;
}
}
}
}
需要注意的是,代码中出现了这么一个判断API的代码段:
if(Build.VERSION.SDK_INT>=21)
这是因为安卓5以上不再支持直接new一个SoundPool的方法来创建soundpool池,而是提供了利用SoundPool.Builedr以及
AudioAttributes.Builder来创建,如下:
AudioAttributes abs = new AudioAttributes.Builder()
.setUsage(AudioAttributes.USAGE_MEDIA)
.setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
.build() ;
soundPool=new SoundPool.Builder()
.setMaxStreams(5)
.setAudioAttributes(abs)
.build(); //创建一个SoundPool对象,该对象可以容纳5个音频流
2、MainActivity的代码:
package com.example.myexplorer;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import com.example.myexplorer.R;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.Intent;
import android.media.AudioManager;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;
import android.view.Window;
import android.webkit.DownloadListener;
import android.webkit.WebChromeClient;
import android.webkit.WebSettings;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.widget.ProgressBar;
import android.widget.Toast;
@SuppressLint({ "InlinedApi", "ClickableViewAccessibility", "SetJavaScriptEnabled" })
public class MainActivity extends Activity implements OnTouchListener{
private WebView webView;
int width,height,keyBack=0;
View decorView;
Thread thread;
private ThreadPoolExecutor poolExecutor;
SoundPoolManager soundPoolManager; //获取音频播放管理器
String[] musicName= {"music","music1","music3"};//定义一个String数组来存放需要加载的音乐的名称
float Y;
private float downX,downY;
private ProgressBar pg1;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
this.requestWindowFeature(Window.FEATURE_NO_TITLE);//隐藏标题
setContentView(R.layout.activity_main);
/*
* 初始化控件
*/
webView=(WebView)findViewById(R.id.webview); //实例化一个webview浏览组件
pg1=(ProgressBar) findViewById(R.id.progressbar);
soundPoolManager=new SoundPoolManager(this); //实例化音频管理器
// 获得decorView
decorView = getWindow().getDecorView();
webView.setOnTouchListener(this); //为webview添加触摸事件监控
// 获得手机屏幕的宽度和高度,单位像素
DisplayMetrics metrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(metrics);
width = metrics.widthPixels;
height = metrics.heightPixels;
creatMyWebView(webView); //创建currentWebView
webView.loadUrl("https://w.heiyan.com/"); //传递需要加载的网页
//从线程池中拿出一个线程来播放音乐,线程池具体额参数如下
/*
* public ThreadPoolExecutor(
//核心线程数,除非allowCoreThreadTimeOut被设置为true,否则它闲着也不会死
int corePoolSize,
//最大线程数,活动线程数量超过它,后续任务就会排队
int maximumPoolSize,
//超时时长,作用于非核心线程(allowCoreThreadTimeOut被设置为true时也会同时作用于核心线程),闲置超时便被回收
long keepAliveTime,
//枚举类型,设置keepAliveTime的单位,有TimeUnit.MILLISECONDS(ms)、TimeUnit. SECONDS(s)等
TimeUnit unit,
//缓冲任务队列,线程池的execute方法会将Runnable对象存储起来
BlockingQueue<Runnable> workQueue,
//线程工厂接口,只有一个new Thread(Runnable r)方法,可为线程池创建新线程
ThreadFactory threadFactory)
*/
poolExecutor = new ThreadPoolExecutor(3, 5,
1, TimeUnit.SECONDS, new LinkedBlockingDeque<Runnable>(128));
Runnable runnable1=new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
//开启音频播放
Log.i("Thread","start");
soundPoolManager.creatSounPool(3, AudioManager.STREAM_MUSIC, 0);
soundPoolManager.load(musicName,1 );
//soundPoolManager.play(1, 1, 5, 0, 1);
try {
Thread.sleep(10000);
handler2.post(runnable2);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
};
poolExecutor.execute(runnable1); //开启线程
/*
* 开启一个新线程,定时置keyBack为0
*/
new Thread(new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
handler.post(runnable);//启动计时器,每一秒执行一次runnable.
}
}).start();
}
/*
* 创建一个handler对象并重写runnable的run方法,实现,当线程启动时,自动启动消息推送
*/
Handler handler=new Handler();
Runnable runnable=new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
//当线程不没有被中断,重复执行消息推送
keyBack=0;
handler.postDelayed(runnable, 5000); //自身调用自身,陷入2秒的定时循环
}
};
/*
* 创建一个handler对象并重写runnable的run方法,实现,当线程启动时,每0-20秒随机播放
*/
Handler handler2=new Handler();
Runnable runnable2=new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
//当线程不没有被中断,重复执行消息推送
soundPoolManager.play(1, 1, 0, 0, 1);
Log.i("AtTime","successfull");
handler2.postDelayed(runnable2, (int)(Math.random()*20+5)*1000);//自身调用自身,陷入2秒的定时循环
}
};
@SuppressLint("NewApi")
public void creatMyWebView(WebView w) {
//加入下载监听器,用于用户第一次支付时下载插件用
w.setDownloadListener(new MyWebViewDownLoadListener());
w.setWebViewClient(new WebViewClient(){
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
if( url.startsWith("http:") || url.startsWith("https:") ) {
return false;
}
// Otherwise allow the OS to handle things like tel, mailto, etc.
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
startActivity( intent );
return true;
}
});
//支持JS
WebSettings settings = w.getSettings();
settings.setJavaScriptEnabled(true);
w.setWebChromeClient(new WebChromeClient(){ //辅助WebView处理Javascript的对话框,网站图标,网站title,加载进度等
@Override
public void onProgressChanged(WebView view, int newProgress) {
// TODO 自动生成的方法存根
if(newProgress==100){
pg1.setVisibility(View.GONE);//加载完网页进度条消失
}
else{
pg1.setVisibility(View.VISIBLE);//显示进度条
pg1.setProgress(newProgress);//设置进度值
}
}
});
//设置webview提供的各个属性
w.getSettings().setUseWideViewPort(true);//设置此属性,可任意比例缩放。
w.getSettings().setSupportZoom(true); //允许组件具有放大和缩小功能
w.getSettings().setBuiltInZoomControls(true);
//不显示webview缩放按钮
settings.setDisplayZoomControls(false);
}
/*
* 下载监听内部类的定义
*/
private class MyWebViewDownLoadListener implements DownloadListener{
//添加监听事件即可
public void onDownloadStart(String url, String userAgent, String contentDisposition,
String mimetype,long contentLength) {
Uri uri = Uri.parse(url);
Intent intent = new Intent(Intent.ACTION_VIEW, uri);
startActivity(intent);
}
}
/*
* 设置触摸监控事件
*/
@Override
public boolean onTouch(View v,MotionEvent event) {
if(event.getAction() == MotionEvent.ACTION_DOWN){// 当按下时
// 获得按下时的X坐标
downX = event.getX();
downY=event.getY();
}else if(event.getAction() == MotionEvent.ACTION_MOVE){// 当手指滑动时
// 获得滑过的距离
float rightmoveDistanceX = event.getX() - downX;
float leftmoveDistanceX = downX-event.getX() ;
Y=Math.abs(event.getY()-downY);
if(rightmoveDistanceX > width/5 && Y<height/7){// 如果是向右滑动
webView.setX(rightmoveDistanceX); // 设置界面的X到滑动到的位置
try {
Thread.sleep(10);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//webView.setY(0); //固定住此时webview的Y
}
else if(leftmoveDistanceX > width/5 && Y<height/7) {
webView.setX(-leftmoveDistanceX); // 设置界面的X到滑动到的位置
//webView.setY(0); //固定住此时webview的Y
try {
Thread.sleep(50);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}else if(event.getAction() == MotionEvent.ACTION_UP){// 当抬起手指时
// 获得滑过的距离
float moveDistanceX = event.getX() - downX;
float leftmoveDistanceX= downX-event.getX() ;
if(moveDistanceX > width*2 / 8 && Y<height/7){
// 如果滑动的距离超过了手机屏幕的一半, 结束当前Activity
if(webView.canGoBack()) { //如果能够后退则后退操作,如果不行,则提示
webView.goBack();
webView.setX(0); // 设置界面的X到初始位置
}
else {
Toast.makeText(MainActivity.this, "没有上一页了",
Toast.LENGTH_SHORT).show();
webView.setX(0); // 设置界面的X到初始位置
}
}else if(leftmoveDistanceX>width*2/8 && Y<height/7) {
if(webView.canGoForward()) { //如果能够后退则后退操作,如果不行,则提示
webView.goForward();
webView.setX(0); // 设置界面的X到初始位置
}
else
{
Toast.makeText(MainActivity.this, "没有下一页了",
Toast.LENGTH_SHORT).show();
webView.setX(0); // 设置界面的X到初始位置
}
}
else{ // 如果滑动距离没有超过一半
// 恢复初始状态
webView.setX(0);
}
}
return false;
}
/*
* 进入沉浸模式,即自动隐藏状态栏以及导航栏
* @see android.app.Activity#onWindowFocusChanged(boolean)
*/
@Override
public void onWindowFocusChanged(boolean hasFocus) { //进入沉浸模式,即自动隐藏状态栏以及导航栏
super.onWindowFocusChanged(hasFocus);
//判断是否有焦点
if(hasFocus && Build.VERSION.SDK_INT >= 19){
View decorView = getWindow().getDecorView();
decorView.setSystemUiVisibility(
View.SYSTEM_UI_FLAG_LAYOUT_STABLE
|View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
|View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
|View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
|View.SYSTEM_UI_FLAG_FULLSCREEN
|View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
);
}
}
/*
* 设置后退键连按两次退出
* @see android.app.Activity#onKeyDown(int, android.view.KeyEvent)
*/
@Override
public boolean onKeyDown(int keyCode,KeyEvent event) {
if(keyCode==KeyEvent.KEYCODE_BACK)
{
keyBack++;
if(keyBack==1) {
Toast.makeText(MainActivity.this, "再按一次退出", Toast.LENGTH_SHORT).show();
Log.i("keyBack","1");
}
else if(keyBack==2)
finish();
}
return true;
}
@Override
public void onDestroy() {
//soundPoolManager.soundPool.release();
super.onDestroy();
}
}
3、MediaPlayer的代码
package com.example.myexplorer;
import android.content.Context;
import android.media.MediaPlayer;
import android.util.Log;
public class mediaplayer {
Context context;
MediaPlayer myMediaPlayer;
public mediaplayer(Context context) {
this.context=context;
}
protected void creatMediaPlayer() {
Log.i("Creat","begin");
//通过mediaPlayer的静态方法creat创建一个MediaPlayer对象
myMediaPlayer=MediaPlayer.create(context,
context.getResources().getIdentifier(
"com.example.myexplorer:raw/background_music", null, null));
//(com.example.myexplorer.R.raw.background_music));
Log.i("Creat","successfull");
}
protected void play() {
try {
//myMediaPlayer.prepare(); //准备并加载音频
myMediaPlayer.start(); //开始播放音频
Log.i("play","successfull");
} catch (IllegalStateException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
protected void stop() {
myMediaPlayer.stop();
}
protected void pause() {
myMediaPlayer.pause();
}
protected void release() {
myMediaPlayer.release();
}
}
欢迎界面WelcomeActivity的代码:
package com.example.myexplorer;
import android.app.Activity;
import android.content.Intent;
import android.graphics.drawable.AnimationDrawable;
import android.os.Build;
import android.os.Bundle;
import android.view.View;
import android.view.Window;
import android.widget.LinearLayout;
public class welcomeActivity extends Activity {
private AnimationDrawable ad;
private LinearLayout ll;
mediaplayer musicPlayer;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
this.requestWindowFeature(Window.FEATURE_NO_TITLE);//隐藏标题
setContentView(R.layout.welcome);
ll=(LinearLayout)findViewById(R.id.ll);
ad=(AnimationDrawable)ll.getBackground();
musicPlayer=new mediaplayer(this);
musicPlayer.creatMediaPlayer(); //创建一个播放器
musicPlayer.play(); //开始播放
ad.start();
new Thread(new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
try {
Thread.sleep(3000);
Intent intent =new Intent(welcomeActivity.this,MainActivity.class);
startActivity(intent);
musicPlayer.stop();
musicPlayer.release();
finish();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}).start();
}
/*
* 进入沉浸模式,即自动隐藏状态栏以及导航栏
* @see android.app.Activity#onWindowFocusChanged(boolean)
*/
@Override
public void onWindowFocusChanged(boolean hasFocus) { //进入沉浸模式,即自动隐藏状态栏以及导航栏
super.onWindowFocusChanged(hasFocus);
//判断是否有焦点
if(hasFocus && Build.VERSION.SDK_INT >= 19){
View decorView = getWindow().getDecorView();
decorView.setSystemUiVisibility(
View.SYSTEM_UI_FLAG_LAYOUT_STABLE
|View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
|View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
|View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
|View.SYSTEM_UI_FLAG_FULLSCREEN
|View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
);
}
}
}