Android Studio如何自动 import

Eclipse自动添加import语句, 使用Ctrl + Shift + o组合, 可以自动查找java的import语句进行添加;
Android默认是Alt+Enter单个添加import语句, 可以修改IDE, 使其自动添加, 所使用的java库;
位置: Files ->Settings-> IDE Settings-> Editor -> Auto Import

关于Auto Import的设置也有好几项,估计很多人看着也萌,我这边解释下,如果我解释了你还是觉得不懂,那你就不用管它各项是干啥的,直接都勾上就好了。如下图:

逐一解释下吧:

XML

  •  Show import popup,这个是用于编辑XML时,自动会弹出一个import的对话框,问你是否需要导入。

Java

  • Insert imports on paste:(All Ask None),这个其实就是你在复制代码的时候,对于导入的包是否需要进行询问的一个选项。
     All:选择这项的时候,你黏贴的代码,有需要导入的包名时,会自动导入,不会弹提示框
     ASK:选择这项的时候,你黏贴的代码,有需要导入的包名时,会弹提示框,问你要不要导入
     None:选择这项的时候,你黏贴的代码,有需要导入的包名时,不会弹提示框,也不会自动导入。
  • Show import popup:这个是和上面的Insert imports on paste是不同的项了哈,不要混一起,这个是指当你输入的类的声明没被导入时,会弹出一个选择的对话框。但是这边需要注意下,这个选项其实是有点问题的。不管你勾还是不勾,反正对话框是不会弹出来的,在你输完类名后,声明都自动导入了。所以我估计这个可能是Android Studio的bug。
  • Optimize imports on fly:这个其实和快捷键Ctrl+Shift+O/Ctrl+Alt+O是一样的,就是把不用的声明移除掉。
  • Add unambiguous imports on the fly:这个就是自动导入功能了,当你输入类名后,声明就被自动导入了。
  • Exclude from Import and Completion:这个其实就是你自定义import。可以不用关注,一般来说你是用不上的。

%title插图%num

 

audio不能自动播放的解决方案

背景
实现H5改造客户端版本的英语听说答题功能,这里涉及到很多页面线程的使用,如果自动播放题目,每隔几秒播放内容,循环播放几次等等,在客户端环境里天生蕴藏着多线程操作和media的库,而改成H5页面的方式,只能好好研究H5的音频播放控制的api。

audio尝试
由于项目所给的时间非常紧,还没有做好充分调研就开始磨刀霍霍,上来分析如果包装题目数据,让页面播放题目的音频更加的合理,根据题目的音频数量按照一定的格式,比如audioPath、times、sleep等关键因素

audioPath:音频的路径,这里包括项目本地路径和远程路径的区分
times:循环几次播放
sleep:播放完休眠多久,setInterval需要
凭借自己前端的基础,信心满满的噼里啪啦胡乱的敲着键盘,宛如进入忘我的境地,纵有前方千军万马,也要杀他个片甲不留。怀着这样的心情代码大厦就被我一层一层的浇筑成功,通过桌面浏览器按照想象的画面勾勒出来,正所谓多情总被无情伤,整个过程我竟然忘我的用了平时个人冲浪的firefox浏览器,我怎么没用Chrome浏览器进行调测,真是不能原谅自己竟然犯了这个错误,firefox是支持audio进行自动播放,javascript进行api操控,完美达到预想中的效果,而Chrome和Safari 浏览器基于安全的策略,已经停止自动播放,主要现象如下:

Chrome提示:DOMException: play() failed because the user didn’t interact with the document first.
Safari 提示:NotAllowedError: The request is not allowed by the user agent or the platform in the current context, possibly because the user denied permission.
一句话总结就是不允许你自动播放audio,即使你通过代码trigger触发play等事件都是不允许的,必须要你进行和浏览器进行事件互动,人为的点击,触摸等操作才能播放。经调研得知:*开始移动端浏览器是完全禁止音视频自动播放的,考虑到了手机的带宽以及对电池的消耗。但是后来又改了,因为浏览器厂商发现网页开发人员可能会使用 其他替代方案,而播放性能消耗更为糟糕,所以这样对用户反而是不利的。因此浏览器厂商放开了对多媒体自动播放的限制,只要具备以下条件就能自动播放:

没音频轨道,或者设置了 muted 属性
在视图里面是可见的,要插入到 DOM 里面并且不是 display: none 或者 visibility: hidden 的,没有滑出可视区域
换句话说,只要你不开声音扰民,且对用户可见,就让你自动播放,不需要你去使用 GIF 的方法进行 hack。这种实现主要对于视频的,自动播放但是却是静音的,需要你点击喇叭才能有声音,这对于音频答题就跟没说一样。果断放弃。。。。
而桌面浏览器Chrome官方提示2018.10月份也放开自动播放限制,不知道效果是不是和上面的一样,如果一样也是鸡肋。

AudioContext
上天总是公平的,audio被阉割了,一定有另一个家伙替代了他,而他就是AudioContext,可以自动播放,更多API可以参考MSDN,功能强大。

在这里遇到了一个问题就是加载的音频字节数组不可以跨域,而恰恰我的音频文件不是项目里的地址。

let request = new XMLHttpRequest();
request.open(“GET”, link, true);
request.responseType = “arraybuffer”;

解决跨域的问题无非就是那几种方案,因为我当前的平台就是跨域代理平台,那就干脆直接就通过代理的方式请求文件流,返回给XMLHttpRequest吧,link直接指向后台java逻辑

终于可以播放,几大主流浏览器毫无压力,不过还没有上生产测试效果,而且并发起来之后我担心读取音频流这块会有瓶颈,不管怎么样,胜利的喜悦难以言表,应急的方案也很难完美。

audio 标签自动播放不起作用或者 play() 报错

audio 标签自动播放不起作用或者 play() 报错
问题描述
页面的 audio 标签设置了自动播放属性,进入页面自动播放不起作用,或者用 js 控制 play(),方法无效,报错!

解决方案
经过各种百度,谷歌,追踪到原因如下:
页面必须进行交互才能进行对 audio 播放;

声音无法自动播放这个在IOS/Android上面一直是个惯例,桌面版的Safari在2017年的11版本也宣布禁掉带有声音的多媒体自动播放功能,紧接着在2018年4月份发布的Chrome 66也正式关掉了声音自动播放,也就是说自动播放在在桌面版浏览器也将失效;

如Android Chrome文档提到。因此浏览器厂商放开了对多媒体自动播放的限制,只要具备以下条件就能自动播放:

(1)没音频轨道,或者设置了muted属性

(2)在视图里面是可见的,要插入到DOM里面并且不是display: none或者visibility: hidden的,没有滑出可视区域。

换句话说,只要你不开声音扰民,且对用户可见,就让你自动播放,不需要你去使用GIF的方法进行hack.桌面版的浏览器在近期也使用了这个策略;

所以上面提到很多人是监听整个页面的点击事件进行播放,不管点的哪里,只要点了就行,包括触摸下滑。这种方法只适用于一个声音资源

$(“#audio”).play()报错 not a function

<audio id=”audio” src=”waring.wav” preload=”auto” controls loop></audio>

$(‘#audio’).play();
报错原因:play()方法属于DOM对象方法,$(‘#audio’)为jquery对象

解决办法:将jquery对象转换为DOM对象

首先打印jquery对象$(‘#audio’)

%title插图%num
两种转换方式将一个jQuery对象转换成DOM对象:[index]和.get(index);
(1)jQuery对象是一个数据对象,可以通过[index]的方法,来得到相应的DOM对象。
如:var audio =$(‘#audio’) ; //jQuery对象
var au=audio [0]; //DOM对象
(2)jQuery本身提供,通过.get(index)方法,得到相应的DOM对象
如:var audio =$(‘#audio’) ;//jQuery对象
var au=audio.get(0); //DOM对象

Android Recyclerview列表自动播放视频

前言:*近项目比较忙很久没写了,一个月迭代了三个版本也是醉了。。。谁叫我们是苦逼的程序猿呢,回归正传;*近主要在弄一个跟视频有关的项目,里面也学到一些东西,现在记录一下;其中一个是仿微博的视频列表自动播放功能,具体可以看下图:

%title插图%num

项目中视频使用的是GSYVideoPlayer 这个开源库。
ps:作者很热心,nice。

废话不多说,直接进入重点;既然要实现类似微博那种滚动列表时,处于当前屏幕的项自动播放,那么肯定得监听列表的滚动事件,好在Recyclerview中给我们提供了接口:

mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
switch (newState) {
case SCROLL_STATE_IDLE: //滚动停止
break;
case SCROLL_STATE_DRAGGING: //手指拖动
break;
case SCROLL_STATE_SETTLING: //惯性滚动
break;
}
}

@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
}
});

如上onScrollStateChanged 方法 给我们返回了三种状态:
SCROLL_STATE_DRAGGING: 手指按住屏幕拖动
SCROLL_STATE_SETTLING: 手指快速在屏幕滑一下后的惯性滑动
SCROLL_STATE_IDLE: 屏幕处于禁止状态

而onScrolled 方法给我们返回了 dx:水平滚动距离、dy:垂直滚动距离。这两个值都是用手指开始触摸的位置减去移动后的位置,所以:
dx > 0 时为手指向左滑动,列表滚动显示右面的内容
dx < 0 时为手指向右滑动,列表滚动显示左面的内容
dy > 0 时为手指向上滑动,列表滚动显示下面的内容
dy < 0 时为手指向下滑动,列表滚动显示上面的内容
项目中暂时没用到这些,但是这些值很有用。

在这个方法中我们需要获取三个值:
(1) 在屏幕可见区域的*项位置 : 通过findFirstVisibleItemPosition()方法获取
(2) 在屏幕可见区域的*后一项位置 : 通过findLastVisibleItemPosition() 方法获取
(3)屏幕可见项的数目 : 用(2)减去(1)即可

为什么需要以上值,这里说下整体思路:
(1)获取当前处于屏幕可见的列表
(2)滑出屏幕的视频我们需要回收掉
(3)当屏幕处于静止状态时我们才开始播放视频

*点:获取可见列表;上面获取的三个值已经解决了,直接看代码:

public int firstVisibleItem, lastVisibleItem, visibleCount;

@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
firstVisibleItem = layoutManager.findFirstVisibleItemPosition();
lastVisibleItem = layoutManager.findLastVisibleItemPosition();
visibleCount = lastVisibleItem – firstVisibleItem;
}

第二点:回收滑出屏幕的视频,获取到当前播放的位置(开源库中有相关方法)判断是否在屏幕可见,不可见就回收;具体看代码

@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
//大于0说明有播放
if (GSYVideoManager.instance().getPlayPosition() >= 0) {
//当前播放的位置
int position = GSYVideoManager.instance().getPlayPosition();
//对应的播放列表TAG
if (GSYVideoManager.instance().getPlayTag().equals(HomeAdapter.TAG) && (position < firstVisibleItem || position > lastVisibleItem)) {
GSYVideoManager.releaseAllVideos();
}
}
}

第三点:屏幕处于静止时才开始播放,只要播放的逻辑写在onScrollStateChanged 的 SCROLL_STATE_IDLE 状态下即可;

@Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
switch (newState) {
case SCROLL_STATE_IDLE: //滚动停止
autoPlayVideo(recyclerView);
break;
}
}

private void autoPlayVideo(RecyclerView view) {
RecyclerView.LayoutManager layoutManager = view.getLayoutManager();
for (int i = 0; i < visibleCount; i++) {
if (layoutManager != null && layoutManager.getChildAt(i) != null && layoutManager.getChildAt(i).findViewById(R.id.video_item_player) != null) {
HomeGSYVideoPlayer homeGSYVideoPlayer = (HomeGSYVideoPlayer) layoutManager.getChildAt(i).findViewById(R.id.video_item_player);
Rect rect = new Rect();
homeGSYVideoPlayer.getLocalVisibleRect(rect);
int videoheight = homeGSYVideoPlayer.getHeight();
if (rect.top == 0 && rect.bottom == videoheight) {
if (homeGSYVideoPlayer.getCurrentState() == homeGSYVideoPlayer.CURRENT_STATE_NORMAL || homeGSYVideoPlayer.getCurrentState() == homeGSYVideoPlayer.CURRENT_STATE_ERROR) {
homeGSYVideoPlayer.getStartButton().performClick();
}
return;
}

}
}
GSYVideoPlayer.releaseAllVideos();
}

autoPlayVideo方法里面就是通过 循环遍历 可见区域的播放器 然后通过 getLocalVisibleRect(rect) 方法计算出谁完全显示出来,对应方法可以查看getLocalVisibleRect 写的很详细;其中getChildAt() 获取的是屏幕可见范围下标从0开始的view,例如当前屏幕只够显示三个view,对应的下标就是0、1、2;与滑动的item的position没有关系。 *后判断如果播放器处于可播放的状态即调用start按钮播放。

因为是公司代码,所以很多地方不能开放出来,忘见谅。*后附上主要完整代码:

public int firstVisibleItem, lastVisibleItem, visibleCount;

public void loadListener() {

mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {

boolean scrollState = false;

@Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
switch (newState) {
case SCROLL_STATE_IDLE: //滚动停止
scrollState = false;
// autoPlayVideo(recyclerView);
break;
case SCROLL_STATE_DRAGGING: //手指拖动
scrollState = true;
break;
case SCROLL_STATE_SETTLING: //惯性滚动
scrollState = true;
break;
}
}

@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
firstVisibleItem = layoutManager.findFirstVisibleItemPosition();
lastVisibleItem = layoutManager.findLastVisibleItemPosition();
visibleCount = lastVisibleItem – firstVisibleItem;

//大于0说明有播放
if (GSYVideoManager.instance().getPlayPosition() >= 0) {
//当前播放的位置
int position = GSYVideoManager.instance().getPlayPosition();
//对应的播放列表TAG
if (GSYVideoManager.instance().getPlayTag().equals(HomeAdapter.TAG) && (position < firstVisibleItem || position > lastVisibleItem)) {
GSYVideoManager.onPause();
}
}
}

});
}

private void autoPlayVideo(RecyclerView view) {
RecyclerView.LayoutManager layoutManager = view.getLayoutManager();

for (int i = 0; i < visibleCount; i++) {
if (layoutManager != null && layoutManager.getChildAt(i) != null && layoutManager.getChildAt(i).findViewById(R.id.video_item_player) != null) {
HomeGSYVideoPlayer homeGSYVideoPlayer = (HomeGSYVideoPlayer) layoutManager.getChildAt(i).findViewById(R.id.video_item_player);
Rect rect = new Rect();
homeGSYVideoPlayer.getLocalVisibleRect(rect);
int videoheight = homeGSYVideoPlayer.getHeight();
if (rect.top == 0 && rect.bottom == videoheight) {
if (homeGSYVideoPlayer.getCurrentState() == homeGSYVideoPlayer.CURRENT_STATE_NORMAL || homeGSYVideoPlayer.getCurrentState() == homeGSYVideoPlayer.CURRENT_STATE_ERROR) {
homeGSYVideoPlayer.getStartButton().performClick();
}
return;
}

}
}
GSYVideoPlayer.releaseAllVideos();
}

说到这里还有一点可以说下,就是给视频弄圆角的时候,具体效果可以看上图,这里需要给TextureView设置圆角,一般的通过写shape设置background已经不适用了,好在网上找到一个方法:

public class TextureVideoViewOutlineProvider extends ViewOutlineProvider {
private float mRadius;

public TextureVideoViewOutlineProvider(float radius) {
this.mRadius = radius;
}

@Override
public void getOutline(View view, Outline outline) {
Rect rect = new Rect();
view.getGlobalVisibleRect(rect);
int leftMargin = 0;
int topMargin = 0;
Rect selfRect = new Rect(leftMargin, topMargin,
rect.right – rect.left – leftMargin, rect.bottom – rect.top – topMargin);
outline.setRoundRect(selfRect, mRadius);
}
}

*后给view设置就行:

mVideoView.setOutlineProvider(new TextureVideoViewOutlineProvider(radius));
mVideoView.setClipToOutline(true);

Android 实现背景音乐的播放及震动

Android 实现背景音乐的播放及震动
实现音乐应用
播放背景音乐
基础
Android支持一般音乐格式,如mid格式,mp3格式。
将要引用的音频文件放入文件夹“res/raw”
在Eclipse中,”raw”文件夹默认在”res”文件夹下。在Android编译器下,需要自己添加。
需要import “Android.media.MediaPlayer”
实现细节:
声明MediaPlayer变量
MediaPlayer MediaPlayer;

实例化该对象,并且用已添加至资源文件夹的音乐文件来初始化该对象。
mediaPlayer = MediaPlayer.create(this, R.raw.xxx);

播放音乐
if(!mediaPlayer.isPlaying())mediaPlayer.start();

暂停播放
if(mediaPlayer.isPlaying())mediaPlayer.pause();

停止播放
if(mediaPlayer.isPlaying())mediaPlayer.stop();

音效
基础

支持普通的音乐格式,如“mid格式”、“MP3格式”和“ogg格式”,但是利用SoundPool来实现播放必须保证该音乐文件的大小不超过1MB。
需要将音频问价能放置在’res/raw’中。
需要import “android.media.SoundPool”。
tips:SoundPool适用于短促且对反应速度比较高的情况(游戏音效或者按键声。)
实现细节:
声明SoundPool变量:
SoundPool soundPool;
声明”HashMap
手机震动
使安卓手机震动能够给用户提供一个触觉上的反馈与交互,可以保证更佳的用户体验并且使得用户直接感知到安卓应用的反馈。(无法在安卓模拟器上调试。)

基础
要实现震动功能必须在Manifest.xml中添加permission。

<manifest xmlns:android=”http://schemas.android.com/apk/res/android”
package=”…“>
<uses-permission
android:name=”android.permission.VIBRATE”/>
<application android:label=”…”> … </application>
</manifest>

震动时长(自定义)
实例化 Vibrator对象:
Vibrator v = (Vibrator)getSystemService(Context.VIBRATOR_SERVICE);

震动时长设置(300毫秒)
v.vibrate(300);
自定义震动模式
实例化
Vibrator v = (Vibrator)getSystemService(Context.VIBRATOR_SERVICE);
– 举例:
利用自定义的模式使得手机以摩斯密码的模式向使用者传递“SOS”讯息。在莫斯密码中s = “…”,o = “—”,其中有在“.”和“-”的停顿,包括字母和单词之间的停顿时长也不相同。

以下的为不同的停顿长度:

int dot = 200; // 莫斯密码点的震动时长
int dash = 500; // 莫斯密码横的震动时长
int short_gap = 200; // 点与横之间的时长间隔
int medium_gap = 500; // 字母之间的时间间隔
int long_gap = 1000; // 单词之间的时间间隔

模式定义(SOS):

long[] pattern = {0, // 立刻开始
dot, short_gap, dot, short_gap, dot, // s
medium_gap,
dash, short_gap, dash, short_gap, dash, // o
medium_gap,
dot, short_gap, dot, short_gap, dot, // s
long_gap
};

实现震动:

v.vibrate(pattern, -1); //-1表示不重复震动

用户自定义停止震动
实例化Vibrator

Vibrator v = (Vibrator)getSystemService(Context.VIBRATOR_SERVICE);

立即开始震动,震动200毫秒,停止500毫秒

long[] pattern = { 0, 200, 500 };
v.vibrate(pattern, 0);

tips:
0表示的是重复该震动模式,从pattern数组下标0开始。若输入1,实现的震动模式会变成震动500毫秒暂停200毫秒。

取消震动,可由用户对应用发出的某指令来成为取消震动的条件。由开发者自定义:

v.cancel();

下面的链接是实现以上功能的Demo,以供参考。

Demo链接

%title插图%num

Android实现背景音乐播放

实现这个功能将用到android的四大组件之一:Service
注意:Service是自大组件之一,需要注册。

什么是服务?
1:“Service” 意思即“服务”的意思, 像 Windows 上面的服务一样,服务是在后台上运行,承担着静悄悄的不为人所注意的工作。
2:Service运行在后台,它是不可见的、无界面的程序。
3:Service可以在很多场合的应用中使用,比如播放多媒体的时候用户启动了其他Activity,这个时候程序要在后台继续播放;比如检测SD卡上文件的变化;再或者在后台记录用户的地理信息位置的改变;或者启动一个服务来运行并一直监听某种动作等等。

在res下新建一个raw的文件夹,将事先下载好的MP3文件放入中,这里的歌曲是我自己下载的是birds.mp3

MainActivity
/**
* 这是一个Service生命周期及开启服务的小例子
* 实现播放音乐功能
*/
public class MainActivity extends AppCompatActivity {
/**
* 规定开始音乐、暂停音乐、结束音乐的标志
*/
public static final int PLAT_MUSIC=1;
public static final int PAUSE_MUSIC=2;
public static final int STOP_MUSIC=3;

private MyBroadCastReceiver receiver;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

receiver=new MyBroadCastReceiver();
IntentFilter filter=new IntentFilter();
filter.addAction(“com.complete”);
registerReceiver(receiver,filter);
}
public void onClick(View view){
switch (view.getId()){
//开始音乐
case R.id.btn_startmusic:
playingmusic(PLAT_MUSIC);
break;
//暂停
case R.id.btn_pausemusic:
playingmusic(PAUSE_MUSIC);
break;
//停止
case R.id.btn_stopmusic:
playingmusic(STOP_MUSIC);
break;
}
}

private void playingmusic(int type) {
//启动服务,播放音乐
Intent intent=new Intent(this,PlayingMusicServices.class);
intent.putExtra(“type”,type);
startService(intent);
}

@Override
protected void onDestroy() {
super.onDestroy();
unregisterReceiver(receiver);
}
}

MyBroadCastReceiver类(广播接收者):

public class MyBroadCastReceiver extends BroadcastReceiver{
@Override
public void onReceive(Context context, Intent intent) {
Toast.makeText(context,”音乐播放结束”,Toast.LENGTH_SHORT).show();
}
}

PlayingMusicServices类:
/**
* 这是一个Start Service
*/
public class PlayingMusicServices extends Service {
//用于播放音乐等媒体资源
private MediaPlayer mediaPlayer;
//标志判断播放歌曲是否是停止之后重新播放,还是继续播放
private boolean isStop=true;
/**
* onBind,返回一个IBinder,可以与Activity交互
* 这是Bind Service的生命周期方法
* @param intent
* @return
*/
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
//在此方法中服务被创建
@Override
public void onCreate() {
super.onCreate();
if (mediaPlayer==null){
mediaPlayer=new MediaPlayer();

//为播放器添加播放完成时的监听器
mediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
@Override
public void onCompletion(MediaPlayer mp) {
//发送广播到MainActivity
Intent intent=new Intent();
intent.setAction(“com.complete”);
sendBroadcast(intent);
}
});
}
}

/**
* 在此方法中,可以执行相关逻辑,如耗时操作
* @param intent :由Activity传递给service的信息,存在intent中
* @param flags :规定的额外信息
* @param startId :开启服务时,如果有规定id,则传入startid
* @return 返回值规定此startservice是哪种类型,粘性的还是非粘性的
* START_STICKY:粘性的,遇到异常停止后重新启动,并且intent=null
* START_NOT_STICKY:非粘性,遇到异常停止不会重启
* START_REDELIVER_INTENT:粘性的,重新启动,并且将Context传递的信息intent传递
* 此方法是唯一的可以执行很多次的方法
*/
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
switch (intent.getIntExtra(“type”,-1)){
case MainActivity.PLAT_MUSIC:
if (isStop){
//重置mediaplayer
mediaPlayer.reset();
//将需要播放的资源与之绑定
mediaPlayer=MediaPlayer.create(this,R.raw.birds);
//开始播放
mediaPlayer.start();
//是否循环播放
mediaPlayer.setLooping(false);
isStop=false;
}else if (!isStop&&mediaPlayer.isPlaying()&&mediaPlayer!=null){
mediaPlayer.start();
}
break;
case MainActivity.PAUSE_MUSIC:
//播放器不为空,并且正在播放
if (mediaPlayer!=null&&mediaPlayer.isPlaying()){
mediaPlayer.pause();
}
break;
case MainActivity.STOP_MUSIC:
if (mediaPlayer!=null){
//停止之后要开始播放音乐
mediaPlayer.stop();
isStop=true;
}
break;
}
return START_NOT_STICKY;
}

@Override
public void onDestroy() {
super.onDestroy();
}
}

在清单配置文件中注册服务:
<service android:name=”.PlayingMusicServices”
android:exported=”true”
android:enabled=”true”/>

 

多用户同时登陆远程服务器设置方法

首先,要服务器开启远程桌面连接:

计算机—属性—远程设置—勾选“允许运行任意版本远程桌面的计算机连接(较不安全)”

%title插图%num

接下来,修改远程桌面的连接数,具体修改方法如下:

控制面板→类别选择”小图标”→管理工具→远程桌面服务→远程桌面会话主机设置→把”限制每个用户只能进行一个会话”勾选去掉,操作图如下:

%title插图%num

然后双击连接中的RDP-Tcp→网络适配器→*大连接数修改为2此时的同时远程桌面连接的数量即设置为2。

如果只需要2个用户同时登陆,上面的设置已经可以了。

%title插图%num

接下来是调整超过2个连接数的的设置方法:需要安装终端服务器(未测试)

*步.在开始->运行命令栏中输入 gpedit.msc

在组策略中依次打开“计算机配置→策略→管理模板→Windows 组件→远程桌面服务→远程桌面会话主机→连接”中,选择“限制连接数量”进行配置。

第二步.在角色里增加远程桌面服务。

右击我的电脑,选择管理,在服务器管理→角色中添加远程桌面角色,一直下一步,然后重启服务器。

audio自动播放完美兼容实现方案

前述:*近解决的一个疑难杂症,是关于audio自动播放与监听audio加载完成在ios上的兼容性问题,其表现为pc,安卓谷歌浏览器正常,ios微信,谷歌浏览器不正常。

需求:在音频加载前放置一个全局loading,音频加载完成后取消loading,并自动播放;项目为vue前端项目,兼容pc,移动端。

解决方案1(失败):

that.audioTimer=setTimeout(function(){
that.audioLoading = that.$loading({
lock: true,
text: ‘音频加载中…’,
spinner: ‘el-icon-loading’,
background: ‘rgba(0, 0, 0, 0.7)’
});
},200);
//兼容谷歌浏览器
audioElement.addEventListener(“progress”, function() {
//关闭loading并让audio.paly()
});
audioElement.addEventListener(“canplay”, function() {
//关闭loading并让audio.paly()
});
//兼容微信浏览器
document.addEventListener(“WeixinJSBridgeReady”, function () {
alert(“微信”)
//关闭loading并让audio.paly()
}, false)
问题在于addEventListener(“canplay”)与(“progress”)在ios微信浏览器不兼容,而在微信浏览器上类似上述的兼容微信浏览器代码根本难以实现,并且兼容这些浏览器需要写很多重复的代码,复用性不高;

解决方案2(成功):

思路,用全局自定义方法get请求替换监听音频加载是否完成方案;

*步,封装axios get方法

import axios from ‘axios’
import { Loading } from ‘element-ui’

const get = function(path, callback){
//配置路径
let fainalPath = path;
if(path.indexOf(“http”) < 0){
fainalPath = “http://” + Host + path;
}

//延时Loading
let getloadtimer = null;
let getloading = null;
getloadtimer = setTimeout(function(){
getloading = Loading.service({
lock: true,
text: ‘资源加载中…’,
spinner: ‘el-icon-loading’,
background: ‘rgba(0, 0, 0, 0.7)’
});
},200);
//网络不稳定Loading
let setIntvar = null;
let setIntvarnum = 0;
let netLoading = null;
setIntvar = setInterval(function(){
if(setIntvarnum>=10){
if(getloading != null) {
getloading.close();
}
netLoading = Loading.service({
lock: true,
text: ‘网络环境不稳定,请您刷新或者重新登录…’,
spinner: ‘el-icon-loading’,
background: ‘rgba(0, 0, 0, 0.7)’
});
}else {
setIntvarnum += 1
}
},1000);
//网络请求
axios.get(fainalPath
,{headers: {
‘Content-Type’:’application/json;charset=UTF-8′,
‘Accept’:’application/json’
}})
.then(function (response) {
closeAll(getloadtimer,setIntvar,getloading,netLoading);
callback(response)
})
.catch(function (error) {
closeAll(getloadtimer,setIntvar,getloading,netLoading);
if (error.response) {
console.log(error.response.data);
console.log(error.response.status);
tipError(error.response.data.code,error.response.status,path)
}
})
};
<audio id=”playButton” :src=”audioSrc” :autoplay=”autoplay” @ended=”audioEnd”></audio>
第二步:在vue页面中,监听数据变幻,并加载音频;

watch: {
‘response’: ‘renderData’
}
response是父组件传来的数据;renderData是子组件的数据初始化方法;在renderData里做下面的方法。

let audioSrc = “http://xxxx.com/测试.mp3”;
let audioElement = document.getElementById(‘playButton’);
api.get(audioSrc,function(response){
//audioElement.load();
audioElement.play();
})
第三步:当你点击音频时不需要重复加载,它会从cache里去拿;

choiceAudio (id) {
this.isEnded = ‘pause’;
let audioSrc = “http:/xxxx”+ id +”.mp3″;
document.getElementById(‘playButton’).setAttribute(‘src’, audioSrc);
document.getElementById(‘playButton’).load();
document.getElementById(‘playButton’).play();
},

总结:经过方案二,在pc,安卓,ios里都能正常运行,完美!

ubuntu创建新用户并设置samba服务

1.新建自己的用户并查看
sudo useradd -m -s /bin/bash 用户名
sudo passwd 用户名
ls /home -t

或者:

#1创建一个新的普通用户:(-m:表示用户,-s表示shell环境)
sudo useradd -m guest -s /bin/bash
#2.新普通用户设置密码,请按系统提示输入两次密码:
sudo passwd guest
#3.可为普通用户增加管理员权限,方便部署,避免一些对新手来说比较棘手的权限问题
sudo adduser guest sudo
#4.用户从root用户切换到普通用户,命令如下:
su guest

2.给新用户添加sudo权限
sudo vim /etc/sudoers
#找到:root ALL=(ALL:ALL)ALL
#添加: 用户名 ALL=(ALL:ALL)ALL

3.删除用户:
执行userdel命令:sudo userdel 用户名
删除用户目录命令:sudo rm -rf 用户名
删除用户权限相关配置:删除或者注释掉/etc/sudoers中关于要删除用户的配置,否则无法再次创建同名用户。
4.samba共享的设置 可以让windows访问linux系统的共享文件
安装:sudo apt-get install samba
修改配置文件:sudo vim /etc/samba/smb.conf
[test] #自定义共享名称
comment = This is share software #共享描述
path = /home/testfile #共享目录路径
available = yes
browseable = yes #设置共享是否可浏览,如果no就表示隐藏,需要通过IP+共享名称进行访问
public = no #设置共享是否允许guest账户访问
writeable = yes  #设置共享是否具有可写权限
guest = no #功能同public 一样
force user = test
force group = test
create mask = 0777 #创建的文件目录为 777
directory mask = 0777 #创建的文件目录为 777

5.添加访问共享用户并设置共享密码:sudo smbpasswd -a 用户名
6.重启samba服务:sudo service smbd restart
7.完成以上可通过\\ip访问你服务器文件