到底什么是云计算 学了云计算能从事哪些职业

到底什么是云计算?学了云计算能从事哪些职业 ?随着国家政策支持以及互联网的迅猛发展,我国云计算产业迎来全新发展机遇。越来越多的企业选择使用云计算技术,云计算人才也成为稀缺人才。很多人看好云计算的未来前景,但却不知道云计算方向可以从事什么职业,接下来小编就给大家解答一下。

%title插图%num

云计算(cloud computing)是分布式计算、效用计算、负载均衡、并行计算、网络存储、热备份冗杂和虚拟化等计算机技术混合演进并跃升的结果。学习云计算你可从事的职业有:

1、云系统管理员:配置和维护的系统,包括基本的云平台,解决出现的问题,并计划未来云的能力要求。

2、云计算工程师:负责云计算和数据中心项目交付计划和技术方案的制定,负责云基础架构、上云数据迁移、云容灾备份以及云可靠性、安全性等的规划设计及实施工作。

3、云计算开发工程师:负责设计和开发面向云服务的分布式软件。

4、云计算架构师:领导云计算项目的开发和部署,确保系统的可扩展性、可靠性、安全性、可维护性,并在预算内达到业务和IT业绩表现要求。

5、运维工程师:负责云计算项目实施和运维,做好网络存储、数据库、备份、恢复、同步等相关工作。

当然,随着容器技术的发展以及企业对信息安全重视,学习云计算你还可以从事v等。而胜任工作的一切前提是你掌握企业所需的技术。

iOS Charles(花瓶)抓包

抓包工具Charles下载地址:https://www.charlesproxy.com/download/

第 1 步: 打开Charles

没有花瓶的同学可以用水瓶代替

 

%title插图%num

第 2 步: 联网

把手机和电脑连接到同一个网络下,这里连的都是WIFI

%title插图%num第 3 步: 手机设置代理

%title插图%num

第 4 步: 接受Charles的邀请

以上步骤做好之后,在手机里随便打开什么APP,然后花瓶就会给你发邀请函,这个时候我们一定要接受,如果你不小心拒*了,在花瓶菜单栏:“Proxy” → “Access Control Settings” 在这里把你的手机的 IP 地址手动填上去。

 

%title插图%num

第 5 步: 拷贝目标地址

%title插图%num

 

第 6 步: 把地址加入名单

%title插图%num

第 7 步: 完成地址设置

%title插图%num

第 8 步: 打开证书链接菜单

%title插图%num

第 9 步: 手机输入证书地址

%title插图%num

第 10 步: 手机安装证书

%title插图%num

第 11 步: 打开证书信任设置

%title插图%num

 

做到这里就可以抓包了

iOS开发 检测项目中是否包含UIWebView

ITMS-90809: Deprecated API Usage – Apple will stop accepting submissions of apps that use UIWebView APIs . See https://developer.apple.com/documentation/uikit/uiwebview for more information.

自从2020开始,每次上传包,都会有ITMS-90809: Deprecated API Usage UIWebView,可以自己进行检查

1.打开终端,cd + 把项目的工程文件所在文件夹拖入终端(即 得到项目的工程文件所在的路径)

2.输入以下命令(注意*后有个点号,而且点号和 UIWebView 之间必须有一个空格):

grep -r UIWebView .
3.以上操作都正确的话,会马上出现工程中带有 UIWebView 的文件的列表(包括在工程中无法搜索到的 .a 文件中对UIWebView 的引用)

 

注:引用AFNetWorking可以直接把AFNetWorking 里面的 UIWebView+AFNetworking 扩展删掉就可以了,没影响的。

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 组件→远程桌面服务→远程桌面会话主机→连接”中,选择“限制连接数量”进行配置。

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

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