手机影音第十五天,利用service实现后台播放音乐,在通知栏显示当前音乐信息等...
代码已经托管到码云上,有兴趣的小伙伴可以下载看看
https://git.oschina.net/joy_yuan/MobilePlayer
先来一张目前的音乐播放器的效果图,当播放时,手机的状态通知栏也会有音乐信息显示。
这里可以看到有歌名、演唱者,还有歌曲的总时间,当前播放时间,当前播放进度,音乐暂停、下一首,上一首,音乐循环模式(单曲循环,顺序播放、循环播放)功能的实现。下一步就是把中间空白的部分填充歌词,然后做成根据进度显示歌词。
由于这次的内容有点多,是写了一天半的代码,讲的没那么细,具体的代码可以去下载源码看下。
一、要想做成即使推出播放器后(不是杀死进程),音乐播放器继续播放,那么就不能在activity里进行播放音乐,需要在service里播放音乐
1、aidl的使用,来连接activity和service。
这个aidl有点类似service的接口。
其实用来连接activity和service也可以用内部类IBindler 来做,具体的可以看我前面写的博客,四大组件之service,里面有详细写activity绑定service。
// IMusicPlayerService.aidl
package com.yuanlp.mobileplayer;// Declare any non-default types here with import statementsinterface IMusicPlayerService {/*** 根据对应位置打开音乐* @param position*/void openAudio(int position);/*** 播放音乐*/void startAudio();/*** 暂停音乐*/void pauseAudio();/*** 停止音乐*/void stopAudio();/*** 得到当前播放进度* @return*/int getCurrentPosition();/*** 得到总时长* @return*/long getDuration();/*** 得到演唱者* @return*/String getSinger();/*** 得到音乐大小* @return*/long getSize();/*** 得到歌名* @return*/String getSong();/*** 得到路径* @return*/String getAudioPath();/*** 得到下一首*/void getNext();/*** 得到上一首*/void getPre();/*** 设置播放模式* @param playMode*/void setPlayMode(int playMode);/*** 得到播放模式*/int getPlayMode();/*** 是否播放*/boolean isPlaying();void seekTo(int progress);
}
2 、创建service,第一种可以直接写类,然后继承Service,需要手动重写oncreate()和onBind()方法,然后还要在AndroidManifext.xml里注册这个类;第二种,右键new一个service,这样就不用去重写方法,以及去注册了,因为IDE会自动帮我们做好。
package com.yuanlp.mobileplayer.service;import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Intent;
import android.media.MediaPlayer;
import android.os.Build;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.support.annotation.RequiresApi;
import android.util.Log;import com.yuanlp.mobileplayer.IMusicPlayerService;
import com.yuanlp.mobileplayer.R;
import com.yuanlp.mobileplayer.activity.AudioPlayerAcivity;
import com.yuanlp.mobileplayer.bean.MediaItem;
import com.yuanlp.mobileplayer.utils.CacheUtils;import java.io.IOException;
import java.util.ArrayList;public class MusicPlayerService extends Service {private static final String TAG = "MusicPlayerService";public static final String OPENAUDIOPLAYER = "com.yuanlp.mobilePlayer_openAudioPlayer";private int position;private ArrayList<MediaItem> medialist;private MediaItem item;private MediaPlayer mediaPlayer;private NotificationManager manger; //状态栏通知管理器public static final int REPEAT_NORMAL=1; //默认播放模式,即顺序播放public static final int REPEAT_SINGLE=2; //单曲循环public static final int REPEAT_ALL=3; //循环播放private int playMode=REPEAT_NORMAL; //播放模式public MusicPlayerService() {}@Overridepublic void onCreate() {super.onCreate();playMode=CacheUtils.getPlayMode(this,"playmode");}/*** 在这里获取aidl的实例,需要在onBind()方法里返回这个实例。onBind()方法在activity与service绑定时自动调用。**/private IMusicPlayerService.Stub stub=new IMusicPlayerService.Stub() {MusicPlayerService service=MusicPlayerService.this;@Overridepublic void openAudio(int position) throws RemoteException {System.out.println("调取了内部的方法传递position为"+position);service.openAudio(position);}@RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN)@Overridepublic void startAudio() throws RemoteException {service.startAudio();}@Overridepublic void pauseAudio() throws RemoteException {service.pauseAudio();}@Overridepublic void stopAudio() throws RemoteException {service.stopAudio();}@Overridepublic int getCurrentPosition() throws RemoteException {return service.getCurrentPosition();}@Overridepublic long getDuration() throws RemoteException {return service.getDuration();}@Overridepublic String getSinger() throws RemoteException {return service.getSinger();}@Overridepublic long getSize() throws RemoteException {return service.getSize();}@Overridepublic String getSong() throws RemoteException {return service.getSong();}@Overridepublic String getAudioPath() throws RemoteException {return service.getAudioPath();}@Overridepublic void getNext() throws RemoteException {service.getNext();}@Overridepublic void getPre() throws RemoteException {service.getPre();}@Overridepublic void setPlayMode(int playMode) throws RemoteException {service.setPlayMode(playMode);}@Overridepublic int getPlayMode() throws RemoteException {return service.getPlayMode();}/*** 是否播放*/@Overridepublic boolean isPlaying() throws RemoteException {return service.isPlaying();}//把进度条调整到progress的位置public void seekTo(int progress){service.seekTo(progress);}};// public class Mybinder extends Binder{
// public MusicPlayerService getService(){
// return MusicPlayerService.this;
// }
// }
//
// public Mybinder binder=new Mybinder();
// @Override
// public IBinder onBind(Intent intent) {
//
// return binder;
//
// }@Overridepublic IBinder onBind(Intent intent) {System.out.println("绑定了服务------------");//当绑定时,获取activity通过intent传过来的序列化的list数据。medialist= (ArrayList<MediaItem>) intent.getSerializableExtra("medialist");System.out.println("获取服务里的数据。。。"+medialist.size());return stub;}/*** 根据对应位置打开音乐* @param position*/private void openAudio(int position){this.position=position;Log.d(TAG, "openAudio:当前位置 "+position);item=medialist.get(position);Log.d(TAG, "openAudio: 当前位置对应的歌名"+item.getName());if (mediaPlayer!=null){mediaPlayer.reset();mediaPlayer=null;}try {mediaPlayer=new MediaPlayer();mediaPlayer.setOnPreparedListener(new MyOnPreparedListener());mediaPlayer.setOnCompletionListener(new MyOnCompletionListener());mediaPlayer.setOnErrorListener(new MyOnErrorListener());mediaPlayer.setDataSource(item.getData());mediaPlayer.prepareAsync();} catch (IOException e) {e.printStackTrace();}}/*** 播放出错时回调*/class MyOnErrorListener implements MediaPlayer.OnErrorListener {@Overridepublic boolean onError(MediaPlayer mp, int what, int extra) {getNext();return true;}}/*** 播放完成时*/class MyOnCompletionListener implements MediaPlayer.OnCompletionListener {@Overridepublic void onCompletion(MediaPlayer mp) {getNext();}}/*** 准备好播放时回调*/class MyOnPreparedListener implements MediaPlayer.OnPreparedListener {@RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN)@Overridepublic void onPrepared(MediaPlayer mp) {startAudio();//在这里发送广播,通知activity,播放的进度、音乐名称、歌唱家等信息notifyChange(OPENAUDIOPLAYER);}}/*** 发送广播通知activity* @param openaudioplayer*/private void notifyChange(String openaudioplayer) {Intent intent=new Intent(openaudioplayer);sendBroadcast(intent);}/*** 播放音乐*/@RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN)public void startAudio(){mediaPlayer.start();manger= (NotificationManager) getSystemService(NOTIFICATION_SERVICE); //获取系统的通知服务//Notification notifaction= null;Intent intent=new Intent(this, AudioPlayerAcivity.class); //点击通知栏后,打开activity音乐界面Bundle bundle=new Bundle();bundle.putSerializable("mediallist",medialist);intent.putExtras(bundle); //把list数据回传给activity,不然会报错intent.putExtra("Notifaction",true); //标识来自状态PendingIntent pendingintent=PendingIntent.getActivity(this,1,intent,PendingIntent.FLAG_UPDATE_CURRENT);Notification notifaction = new Notification.Builder(this).setSmallIcon(R.drawable.notification_music_playing).setContentTitle("原立鹏音乐播放器") //状态通知栏标题.setContentText("正在播放:"+getSong()) //状态通知栏内容.setContentIntent(pendingintent).build(); //这个一定要写最后面,不然会出错manger.notify(1,notifaction); //显示状态栏}/*** 暂停音乐*/public void pauseAudio(){mediaPlayer.pause();//停止播放时取消状态栏manger.cancel(1);}/*** 停止音乐*/public void stopAudio(){mediaPlayer.stop();}/*** 得到当前播放进度* @return*/public int getCurrentPosition(){return mediaPlayer.getCurrentPosition();}/*** 得到总时长* @return*/public long getDuration(){return mediaPlayer.getDuration();}/*** 得到演唱者* @return*/public String getSinger(){return item.getArtist();}/*** 得到音乐大小* @return*/public long getSize(){return item.getSize();}/*** 得到歌名* @return*/public String getSong(){return item.getName();}/*** 得到路径* @return*/public String getAudioPath(){return item.getData();}/*** 得到下一首*/public void getNext(){}/*** 得到上一首*/public void getPre(){}/*** 设置播放模式,并将播放模式写到sharepreferences里,记忆用户播放模式* @param playMode*/public void setPlayMode(int playMode){this.playMode=playMode;CacheUtils.putPlayMode(this,"playmode",playMode);}/*** 得到播放模式*/public int getPlayMode(){return playMode;}public boolean isPlaying(){return mediaPlayer.isPlaying();}public void seekTo(int progress){mediaPlayer.seekTo(progress);}
}
二、在activity里,接收audiopager传过来的list数据,并绑定服务,在绑定服务时,通过intent将list数据传给service;在开始播放音乐时,接收service发出的广播,来更新页面显示的歌名、时间等信息,并在handler里每秒刷新下时间。
package com.yuanlp.mobileplayer.activity;import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.ServiceConnection;
import android.graphics.drawable.AnimationDrawable;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.os.RemoteException;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.SeekBar;
import android.widget.TextView;
import android.widget.Toast;import com.yuanlp.mobileplayer.IMusicPlayerService;
import com.yuanlp.mobileplayer.R;
import com.yuanlp.mobileplayer.bean.MediaItem;
import com.yuanlp.mobileplayer.service.MusicPlayerService;
import com.yuanlp.mobileplayer.utils.Utils;import java.util.ArrayList;import static android.content.ContentValues.TAG;/*** Created by 原立鹏 on 2017/7/27.*/public class AudioPlayerAcivity extends Activity implements View.OnClickListener {private static final int UPDATE_SEEKBAR = 0; //更新进度条时的handler消息private ImageView iv_play_icon;private int position; //获取从audiopager中从intent传过来的位置信息private ArrayList<MediaItem> medialist;private IMusicPlayerService mservice;private ImageView ivPlayIcon;private TextView tvSigner;private TextView tvSong;private TextView tvTime;private SeekBar seekbarAudio;private Button btAudioMode;private Button btAudioPre;private Button btAudioStartPause;private Button btAudioNext;private Button btLyrc;private boolean isPlaying;private MyBroadcast broadcast; //广播类实例private Utils utils;private boolean isNotifaction; //判断是否是从notifaction那里传过来的intentprivate int currentposition;/*** Find the Views in the layout<br />* <br />* Auto-created on 2017-07-28 08:54:55 by Android Layout Finder* (http://www.buzzingandroid.com/tools/android-layout-finder)*/private void findViews() {System.out.println("初始化数据");ivPlayIcon = (ImageView)findViewById( R.id.iv_play_icon );tvSigner = (TextView)findViewById( R.id.tv_signer );tvSong = (TextView)findViewById( R.id.tv_song );tvTime = (TextView)findViewById( R.id.tv_time );seekbarAudio = (SeekBar)findViewById( R.id.seekbar_audio );btAudioMode = (Button)findViewById( R.id.bt_audio_mode );btAudioPre = (Button)findViewById( R.id.bt_audio_pre );btAudioStartPause = (Button)findViewById( R.id.bt_audio_start_pause );btAudioNext = (Button)findViewById( R.id.bt_audio_next );btLyrc = (Button)findViewById( R.id.bt_lyrc );btAudioMode.setOnClickListener( this );btAudioPre.setOnClickListener( this );btAudioStartPause.setOnClickListener( this );btAudioNext.setOnClickListener( this );btLyrc.setOnClickListener( this );}/*** Handle button click events<br />* <br />* Auto-created on 2017-07-28 08:54:55 by Android Layout Finder* (http://www.buzzingandroid.com/tools/android-layout-finder)*/@Overridepublic void onClick(View v) {if ( v == btAudioMode ) {// Handle clicks for btAudioModegetPlayMode(); //设置播放模式} else if ( v == btAudioPre ) {// Handle clicks for btAudioPreposition-=1;if (position<0){position=medialist.size()-1;}try {MediaItem item=medialist.get(position);tvSigner.setText(item.getArtist());tvSong.setText(item.getName());mservice.openAudio(position);} catch (RemoteException e) {e.printStackTrace();}} else if ( v == btAudioStartPause ) {try {isPlaying=mservice.isPlaying();if (isPlaying){ //表示此时在播放,应该把图片切换为播放界面,然后暂停播放mservice.pauseAudio();btAudioStartPause.setBackgroundResource(R.drawable.bt_audio_start_selector);}else{mservice.startAudio();btAudioStartPause.setBackgroundResource(R.drawable.bt_audio_pause_selector);}} catch (RemoteException e) {e.printStackTrace();}// Handle clicks for btAudioStartPause} else if ( v == btAudioNext ) {// Handle clicks for btAudioNextposition+=1;if (position>=medialist.size()){position=0;}try {MediaItem item=medialist.get(position);tvSigner.setText(item.getArtist());tvSong.setText(item.getName());mservice.openAudio(position);} catch (RemoteException e) {e.printStackTrace();}} else if ( v == btLyrc ) {// Handle clicks for btLyrc}}private void getPlayMode() {try {int playMode=mservice.getPlayMode();if (playMode==MusicPlayerService.REPEAT_NORMAL){playMode=MusicPlayerService.REPEAT_SINGLE; //切换为单曲循环,并把按钮图片切换}else if (playMode==MusicPlayerService.REPEAT_SINGLE){playMode=MusicPlayerService.REPEAT_ALL; //如果为单曲循环,切换为循环播放}else if (playMode==MusicPlayerService.REPEAT_ALL){playMode=MusicPlayerService.REPEAT_NORMAL; //如果为循环播放,则切换为顺序播放,播放全部后,停止播放}else {playMode=MusicPlayerService.REPEAT_NORMAL; //如果为循环播放,则切换为顺序播放,播放全部后,停止播放}mservice.setPlayMode(playMode);setPlayMode();} catch (RemoteException e) {e.printStackTrace();}}private void setPlayMode() {try {int playMode=mservice.getPlayMode();if (playMode==MusicPlayerService.REPEAT_NORMAL){btAudioMode.setBackgroundResource(R.drawable.bt_audio_mode_normal_selector);Toast.makeText(this,"顺序播放",Toast.LENGTH_SHORT).show();}else if (playMode==MusicPlayerService.REPEAT_SINGLE){btAudioMode.setBackgroundResource(R.drawable.bt_audio_mode_single_selector);Toast.makeText(this,"单曲循环",Toast.LENGTH_SHORT).show();}else if (playMode==MusicPlayerService.REPEAT_ALL){btAudioMode.setBackgroundResource(R.drawable.bt_audio_mode_all_selector);Toast.makeText(this,"循环播放",Toast.LENGTH_SHORT).show();}} catch (RemoteException e) {e.printStackTrace();}}public void checkPlayMode(){try {int playMode=mservice.getPlayMode();if (playMode==MusicPlayerService.REPEAT_NORMAL){btAudioMode.setBackgroundResource(R.drawable.bt_audio_mode_normal_selector);}else if (playMode==MusicPlayerService.REPEAT_SINGLE){btAudioMode.setBackgroundResource(R.drawable.bt_audio_mode_single_selector);}else if (playMode==MusicPlayerService.REPEAT_ALL){btAudioMode.setBackgroundResource(R.drawable.bt_audio_mode_all_selector);}} catch (RemoteException e) {e.printStackTrace();}}Handler handler=new Handler(){@Overridepublic void handleMessage(Message msg) {super.handleMessage(msg);switch (msg.what){case UPDATE_SEEKBAR://1 得到当前进度try {int currentPosition=mservice.getCurrentPosition();seekbarAudio.setProgress(currentPosition);String time=utils.stringForTime(currentPosition)+"/"+utils.stringForTime((int) mservice.getDuration());tvTime.setText(time);handler.removeMessages(UPDATE_SEEKBAR);/*** 每秒刷新下进度条*/handler.sendEmptyMessageDelayed(UPDATE_SEEKBAR,1000);} catch (RemoteException e) {e.printStackTrace();}break;}}};@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);Log.d(TAG, "onCreate: 音乐播放activity被创建了");System.out.println("音乐播放activity被创建了");setContentView(R.layout.activity_audioplayer);utils=new Utils();/*** 初始化音乐界面的图片变化的布局*/initView();/*** 实例化布局里的各个控件*/findViews();//注册广播registerBorader();/*** 根据位置获取音乐*/getData();/*** 绑定服务并启动服务*/bindAndStartService();seekbarAudio.setOnSeekBarChangeListener(new MyOnSeekBarChangeListener());}class MyOnSeekBarChangeListener implements SeekBar.OnSeekBarChangeListener {@Overridepublic void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {if (fromUser){try {mservice.seekTo(progress);} catch (RemoteException e) {e.printStackTrace();}}}@Overridepublic void onStartTrackingTouch(SeekBar seekBar) {}@Overridepublic void onStopTrackingTouch(SeekBar seekBar) {}}private void bindAndStartService() {System.out.println("绑定服务 bindService。。。。。。");Intent intent=new Intent(this, MusicPlayerService.class);//intent.setAction("com.yuanlp.mobilePlayer");Bundle bundle=new Bundle();bundle.putSerializable("medialist",medialist);intent.putExtras(bundle);startService(intent); //不至于多次实例化服务对象//System.out.println("数量是多少"+medialist.size());bindService(intent,conn,BIND_AUTO_CREATE);System.out.println("绑定后,再启动服务");// Bundle bundle=new Bundle();startService(intent); //不至于多次实例化服务对象// bundle.putSerializable("medialist",medialist);
// intent.putExtras(bundle);}/*** 与服务创建连接*/private ServiceConnection conn=new ServiceConnection() {/*** 当连接成功时,回调方法* @param name* @param service*/@Overridepublic void onServiceConnected(ComponentName name, IBinder service) {System.out.println("成功连接。。。");mservice=IMusicPlayerService.Stub.asInterface(service);if (mservice!=null){try {if (!isNotifaction){ //不是 从状态栏里过来的,是从列表过来的,那么重新播放System.out.println("成功连接后,service不为空");mservice.openAudio(position);}else{showViewData();}
// MediaItem item=medialist.get(position);
// String artist=item.getArtist();
// String song=item.getName();
// tvSigner.setText(artist);
// tvSong.setText(song);} catch (RemoteException e) {e.printStackTrace();}}}/*** 当连接失败时回调方法* @param name*/@Overridepublic void onServiceDisconnected(ComponentName name) {System.out.println("连接失败。。。");try {if (mservice!=null){mservice.stopAudio();mservice=null;}} catch (RemoteException e) {e.printStackTrace();}}};private void getData() {System.out.println("获取数据------");medialist=new ArrayList<MediaItem>();medialist= (ArrayList<MediaItem>) getIntent().getSerializableExtra("mediallist");System.out.println("当前的list数量------------------------"+medialist.size());//得到intent的数据isNotifaction = getIntent().getBooleanExtra("Notifaction",false);if (!isNotifaction){position = getIntent().getIntExtra("position", 0);}//currentposition = getIntent().getIntExtra("currentPosition",0);System.out.println("传到activity里获取的当前进度isNotifaction是------------"+isNotifaction);}private void initView() {System.out.println("初始化跳动的图片");iv_play_icon= (ImageView) findViewById(R.id.iv_play_icon);iv_play_icon.setBackgroundResource(R.drawable.animation_list);AnimationDrawable rocketAnimation= (AnimationDrawable) iv_play_icon.getBackground();rocketAnimation.start();}/*** 广播接收,接受来自service里开始播放后发送的广播*/class MyBroadcast extends BroadcastReceiver{@Overridepublic void onReceive(Context context, Intent intent) {/*** 接收到广播后,显示歌曲名、歌曲时间等信息*/showViewData();checkPlayMode();}}/*** 接收到广播后,显示歌曲名、歌曲时间等信息*/private void showViewData() {try {tvSigner.setText(mservice.getSinger());tvSong.setText(mservice.getSong());//设置进度条seekbarAudio.setMax((int) mservice.getDuration());handler.sendEmptyMessage(UPDATE_SEEKBAR);} catch (RemoteException e) {e.printStackTrace();}}/*** 注册广播,接收service发送的广播*/private void registerBorader() {System.out.println("注册广播");broadcast=new MyBroadcast();IntentFilter intentfilter=new IntentFilter();intentfilter.addAction(MusicPlayerService.OPENAUDIOPLAYER);registerReceiver(broadcast,intentfilter);}/*** 在onDestroy里取消注册广播*/@Overrideprotected void onDestroy() {handler.removeCallbacksAndMessages(null); //推出activity时,移除所有消息if (broadcast!=null){unregisterReceiver(broadcast);broadcast=null; //这里为什么把广播设置为null,因为取消注册后,垃圾回收器不一定马上回收广播,如果设置为null,那么会优先回收这个}super.onDestroy();}
}
转载于:https://blog.51cto.com/cm0425/1951857
手机影音第十五天,利用service实现后台播放音乐,在通知栏显示当前音乐信息等...相关推荐
- 55.深度解密五十五:利用互联网思维进行实体行业“吸粉和变现”(实用性)
网络营销推广技术.技巧深度解密(五十五)指南: 1.本文档适合零基础以及互联网营销推广工作者,主要讲解实体行业微信吸粉和变现的另类操作问题. 2.原创版权文档,任何抄袭或者全部.部分模仿都是侵权行为. ...
- Android 通过蒲公英pgyer的接口 Service 实现带进度下载App 通知栏显示 在线更新 自动更新Demo
Android 通过蒲公英pgyer的接口 Service 实现带进度下载App 通知栏显示 在线更新 自动更新Demo 标签: app在线更新下载Update升级 2016-09-18 20:47 ...
- Android开发笔记(一百六十五)利用红外发射遥控电器
红外遥控是一种无线控制技术,它具有功耗小.成本低.易实现等诸多优点,因而被各种电子设备特别是家用电器广泛采用,像日常生活中的电视遥控器.空调遥控器等等基本都采用红外遥控技术. 不过遥控器并不都是红外遥 ...
- 网易云视频播放器不使用Service实现后台播放
最近在一家公司实习,要求我在Android上找到播放器实现后台播放的方法,通过研究网易云视频中的播放器,我找到了其中的方法,虽然我觉得网易的方法有点取巧. 1. 问题描述 网易云视频播放器在播放过程 ...
- Android开发笔记(一百七十五)利用Room简化数据库操作
虽然Android提供了数据库帮助器,但是开发者在进行数据库编程时仍有诸多不便,比如每次增加一张新表,开发者都得手工实现以下代码逻辑: 1.重写数据库帮助器的onCreate方法,添加该表的建表语句: ...
- Android开发笔记(一百五十五)利用GL10描绘点、线、面
上一篇文章介绍了GL10的常用方法,包括如何设置颜色.如何指定坐标系.如何调整镜头参数.如何挪动观测方位等等,不过这些方法只是绘图前的准备工作,真正描绘点.线.面的制图工作并未涉及,那么本文就来谈谈如 ...
- 第二十五篇、基于Arduino uno,获取max30205人体温度传感器的温度信息——结果导向
0.结果 说明:先来看看串口调试助手显示的结果,显示的是温度值,因为是接触式传感器,可以测量人体体温,如果不接触,测量的就是空气温度.如果是你想要的,可以接着往下看. 1.外观 说明:虽然max302 ...
- Android使用本地Service实现后台播放音乐
配置文件 <service android:name=".MyService"></service> 布局 <Buttonandroid:id=&qu ...
- opengl正方形绕点旋转_一题十五种解法够不够? 旋转,构造,四点共圆乐不停...
平移,旋转,轴对称是我们初中学习的"几何三大变换".在我们初中阶段学习的几何知识中占据着核心的地位,特别是旋转,那更是核心中的核心(河南中考22题年年考). 如何更好的理解旋转,如 ...
- SAP UI5 应用开发教程之八十五 - 如何用 OPA5 编写测试用例来测试用户输入文本的功能试读版
一套适合 SAP UI5 初学者循序渐进的学习教程 作者简介 Jerry Wang,2007 年从电子科技大学计算机专业硕士毕业后加入 SAP 成都研究院工作至今.Jerry 是 SAP 社区导师,S ...
最新文章
- JAVA - HashMap和HashTable
- 流API--使用并行流
- 【计算机网络】数据链路层 : 概述 ( 基本概念 | 功能 | 为 “网络层“ 提供的服务 )
- centos -bash-4.1$ 不显示用户名路径
- Could not load JDBC driver class [com.mysql.jdbc.Driver]
- SpringBoot 3.0最低版本要求的JDK 17,这几个新特性不能不知道!
- 活动目录建立IIS站点
- 利用CSS3 animation绘制动态卡通人物,无需使用JS代码
- 德鲁克:终生难忘的7堂课
- Edraw Max 9.x 安装
- 青岛理工计算机网络期末试题,青岛理工大学计算机网络试题2008~2009
- 详谈软件工程之软件开发方法(一)
- starUML4.0导出的图片去除水印的方法
- 10分钟教你用Python实现微信翻译机器人
- span标签的使用场景
- 鸿蒙测试机型微博,华为多款机型开启鸿蒙尝鲜:微博已适配 HarmonyOS 小尾巴
- A brief introduction to complex analysis
- Python经典实验4-字典和集合的应用
- 3d效果图制作傻瓜软件_3D效果图制作哪个软件是最适合的?
- 结构化分析与面向对象的区别_JAVA进阶 深入理解面向对象