安卓APP源碼和報(bào)告——音樂(lè)播放器
課?程?設(shè)?計(jì)?報(bào)?告
院 系:專(zhuān) 業(yè):題 目:科 目:學(xué) 生:指導(dǎo)教師:完成時(shí)間:
目 錄
1. 引言1
1.1 目的1
1.2 背景1
2. 需求分析1
3.?系統(tǒng)設(shè)計(jì)1
3.1總體設(shè)計(jì)1
3.2功能設(shè)計(jì)1
4. 系統(tǒng)開(kāi)發(fā)2
4.1源程序清單2
4.2功能實(shí)現(xiàn)2
5. 系統(tǒng)測(cè)試2
5.1測(cè)試方法2
5.2測(cè)試實(shí)現(xiàn)2
5.3測(cè)試結(jié)果2
6. 結(jié)論與心得2
7. 參考文獻(xiàn)3
引言
1.1 目的
該APP實(shí)現(xiàn)了播放音樂(lè)MV的功能,連接在包中導(dǎo)入數(shù)據(jù)庫(kù),可上傳大量的音樂(lè)MV供使用者欣賞,使用前需要進(jìn)行注冊(cè)登錄獲取自己的賬號(hào)密碼,可直接從一個(gè)音樂(lè)MV跳轉(zhuǎn)到下一個(gè)音樂(lè)MV,隨意調(diào)整視頻進(jìn)度等功能。
1.2 背景
在人們繁忙的生活中,一天之余我們都需要休息,可以通過(guò)此款音樂(lè)播放器聽(tīng)音樂(lè),播放音樂(lè),看音樂(lè)MV,讓人們生活得到放松。需求分析
當(dāng)人們疲憊時(shí),可以通過(guò)聽(tīng)音樂(lè)緩解。
當(dāng)人們閑暇時(shí),可以聽(tīng)音樂(lè)放松心情。
當(dāng)人們快樂(lè)時(shí),可以聽(tīng)音樂(lè)一起快樂(lè)。
當(dāng)人們悲傷時(shí),可以聽(tīng)音樂(lè)療傷。
當(dāng)人們生氣時(shí),可以聽(tīng)音樂(lè)消氣。
系統(tǒng)設(shè)計(jì)
3.1總體設(shè)計(jì)
1.基本的手機(jī)顯示界面
2.用戶(hù)的注冊(cè)
3.用戶(hù)登錄
4.用戶(hù)進(jìn)入音樂(lè)播放器
5.點(diǎn)擊列表中想要播放的音樂(lè)
6.跳轉(zhuǎn)到音樂(lè)MV界面播放
7.用戶(hù)可以暫停音樂(lè),播放音樂(lè),隨意跳動(dòng)進(jìn)度條,上一首音樂(lè),下一首音樂(lè)。
3.2功能設(shè)計(jì)
安卓APP源碼和報(bào)告——音樂(lè)播放器
安卓APP源碼和報(bào)告——音樂(lè)播放器[/caption]
系統(tǒng)開(kāi)發(fā)
4.1源程序清單
1、工程配置文件

工程結(jié)構(gòu)目錄

1.
4.2功能實(shí)現(xiàn)
數(shù)據(jù)庫(kù)存儲(chǔ)相關(guān)代碼:
import?android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import androidx.annotation.Nullable;
public class MyDBHelper extends SQLiteOpenHelper {
private static final String?DBNAME=”financial.db”;
private static final int?VERSION=1;
public MyDBHelper(Context?context) {
super(context,?DBNAME, null,?VERSION);
}
//1 創(chuàng)建數(shù)據(jù)庫(kù)
@Override
public void onCreate(SQLiteDatabase db) {
//創(chuàng)建用戶(hù)表
db.execSQL(“create table tb_userinfo(id integer primary key autoincrement,name varchar(10),pwd varchar(15),email varchar(50),phone varchar(11))”);
}
//2 升級(jí)數(shù)據(jù)庫(kù)
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
}
}
2.用戶(hù)實(shí)現(xiàn)注冊(cè)以及賬號(hào)密碼存儲(chǔ)的相關(guān)代碼:
import androidx.appcompat.app.AppCompatActivity;
import android.annotation.SuppressLint;
import android.content.Intent;
import android.content.SharedPreferences;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;
import com.example.videoplayer.R;
import com.example.videoplayer.db.MyDBHelper;
public class LoginActivity extends AppCompatActivity {
//1 定義對(duì)象
EditText et_name,et_pwd;
Button btn_newregister,btn_login;
MyDBHelper mhelper;
SQLiteDatabase db;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_login);
//2 綁定控件
initView();
//3 登錄按鈕功能的實(shí)現(xiàn)
btnLogin();
//4 新用戶(hù)注冊(cè)按鈕功能的實(shí)現(xiàn)
btnNewRegister();
}
//2 綁定控件——————–代碼
private void initView() {
et_name=findViewById(R.id.et_name_lg);
et_pwd=findViewById(R.id.et_pwd_lg);
btn_newregister=findViewById(R.id.bt_newregister_lg);
btn_login=findViewById(R.id.bt_login_lg);
mhelper=new MyDBHelper(LoginActivity.this);
db=mhelper.getWritableDatabase();
}
//3 登錄按鈕功能的實(shí)現(xiàn)—————————代碼
private void btnLogin() {
btn_login.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//首先:獲取輸入的用戶(hù)名和密碼
String inputname=et_name.getText().toString();
String inputpwd=et_pwd.getText().toString();
//其次:對(duì)獲取的用戶(hù)名和密碼進(jìn)行判斷
if(inputname.equals(“”)||inputpwd.equals(“”)){//用戶(hù)名或密碼為空
Toast.makeText(LoginActivity.this,”用戶(hù)名或密碼不能為空”,Toast.LENGTH_SHORT).show();
}else{//用戶(hù)名或密碼不為空時(shí),我們?cè)賹?duì)輸入的正確性進(jìn)行判斷。
// 根據(jù)輸入的用戶(hù)名和密碼從數(shù)據(jù)庫(kù)中查詢(xún)
Cursor cursor =db.rawQuery(“select * from tb_userinfo where name=? and pwd=?”,new String[]{inputname,inputpwd});
//根據(jù)查詢(xún)到的結(jié)果進(jìn)行判斷
if (cursor.moveToNext()){//查詢(xún)到時(shí)
@SuppressLint(“Range”) String getname=cursor.getString(cursor.getColumnIndex(“name”));
@SuppressLint(“Range”) String getpwd=cursor.getString(cursor.getColumnIndex(“pwd”));
if(inputname.equalsIgnoreCase(getname)&&inputpwd.equalsIgnoreCase(getpwd)){
SharedPreferences.Editor editor=getSharedPreferences(“userinfo”,0).edit();
editor.putString(“username”,inputname);
editor.putString(“userpwd”,inputpwd);
editor.commit();
Toast.makeText(LoginActivity.this,”用戶(hù)名和密碼正確,歡迎登陸”,Toast.LENGTH_SHORT).show();
Intent intent=new Intent(LoginActivity.this, MainActivity.class);
startActivity(intent);
finish();
}
}else{//沒(méi)有查詢(xún)到結(jié)果時(shí)
Toast.makeText(LoginActivity.this,”用戶(hù)名或密碼錯(cuò)誤,請(qǐng)重新輸入”,Toast.LENGTH_SHORT).show();
et_name.setText(“”);
et_pwd.setText(“”);
}
}
}
});
}
//4 新用戶(hù)注冊(cè)按鈕功能的實(shí)現(xiàn)————————代碼
private void btnNewRegister() {
btn_newregister.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent=new Intent(LoginActivity.this, RegisterActivity.class);
startActivity(intent);
finish();
}
});
}
}
3.運(yùn)行后虛擬機(jī)顯示相關(guān)代碼:
import androidx.appcompat.app.AppCompatActivity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
public class MainActivity extends AppCompatActivity {
Button button;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
button=findViewById(R.id.button);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent intent=new Intent(MainActivity.this,VideoActivity.class);
startActivity(intent);
}
});
}
}
4.播放音樂(lè)MV相關(guān)代碼:
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.MediaController;
import android.widget.TextView;
import android.widget.VideoView;
public class PlayActivity extends AppCompatActivity {
//定義對(duì)象
private TextView my_videoname;
private VideoView my_videoview;?//視頻播放器
private MediaController mediaController;//媒體控制柄
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_play);
initView();?//控件初始化
initData();?//數(shù)據(jù)初始化
}
private void initView() {
my_videoname=findViewById(R.id.my_videoname);
my_videoview=findViewById(R.id.my_videoview);
mediaController=new MediaController(this);
}
private void initData() {
//1、獲取從音樂(lè)列表傳過(guò)來(lái)的視頻名稱(chēng)和視頻地址
String myvideoname=getIntent().getStringExtra(“videoname”);
String myvideourl=getIntent().getStringExtra(“videourl”);
//2、將視頻名稱(chēng)顯示在文本框中,將視頻地址關(guān)聯(lián)到播放器中
my_videoname.setText(myvideoname);
my_videoview.setVideoPath(myvideourl);
//視頻播放器和媒體控制柄關(guān)聯(lián)起來(lái)
my_videoview.setMediaController(mediaController);
//媒體控制柄和視頻播放器關(guān)聯(lián)起來(lái)
mediaController.setMediaPlayer(my_videoview);
//3、啟動(dòng)視頻播放器播放視頻
my_videoview.start();
}
}
5.數(shù)據(jù)庫(kù)存儲(chǔ)數(shù)據(jù)相關(guān)代碼:
import androidx.appcompat.app.AppCompatActivity;
import android.content.ContentValues;
import android.content.Intent;
import android.database.sqlite.SQLiteDatabase;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;
import com.example.videoplayer.R;
import com.example.videoplayer.db.MyDBHelper;
public class RegisterActivity extends AppCompatActivity {
//3定義對(duì)象
EditText et_name,et_pwd,et_email,et_phone;
Button btn_register,btn_cancel;
MyDBHelper mhelper;//創(chuàng)建一個(gè)數(shù)據(jù)庫(kù)類(lèi)文件
SQLiteDatabase db;//創(chuàng)建一個(gè)可以操作的數(shù)據(jù)庫(kù)對(duì)象
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_register);
//4 綁定控件
initView();
//5 注冊(cè)按鈕功能的實(shí)現(xiàn)
btnRegister();
//6 取消按鈕功能的實(shí)現(xiàn)
btnCancel();
}
//4 綁定控件——–代碼
private void initView() {
et_name=findViewById(R.id.et_name_rg);
et_pwd=findViewById(R.id.et_pwd_rg);
et_email=findViewById(R.id.et_email_rg);
et_phone=findViewById(R.id.et_phone_rg);
btn_register=findViewById(R.id.bt_ok_rg);
btn_cancel=findViewById(R.id.bt_cancel_rg);
mhelper=new MyDBHelper(RegisterActivity.this);
db=mhelper.getWritableDatabase();
}
//5 注冊(cè)按鈕功能的實(shí)現(xiàn)——————–代碼
private void btnRegister() {
btn_register.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//創(chuàng)建一個(gè)對(duì)象,用來(lái)封裝一行數(shù)據(jù)
ContentValues values=new ContentValues();
values.put(“name”,et_name.getText().toString());//將輸入的用戶(hù)名放到name列
values.put(“pwd”,et_pwd.getText().toString());//將輸入的密碼放到pwd列
values.put(“email”,et_email.getText().toString());//將輸入的郵箱放到email列
values.put(“phone”,et_phone.getText().toString());//將輸入的電話(huà)放到phone列
//將封裝好的一行數(shù)據(jù)保存到數(shù)據(jù)庫(kù)的tb_userinfo表中
db.insert(“tb_userinfo”,null,values);
Toast.makeText(RegisterActivity.this,”注冊(cè)成功”,Toast.LENGTH_SHORT).show();
}
});
}
//6 取消按鈕功能的實(shí)現(xiàn)——————-代碼
private void btnCancel() {
btn_cancel.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent=new Intent(RegisterActivity.this, LoginActivity.class);
startActivity(intent);
finish();
}
});
}
}
6.音樂(lè)MV傳獲參代碼:
public class Video {
private String videoName;
private String videoUrl;
public String getVideoName() {
return videoName;
}
public String getVideoUrl() {
return videoUrl;
}
public Video(String videoName, String videoUrl) {
this.videoName = videoName;
this.videoUrl = videoUrl;
}
}
7.音樂(lè)獲取MV名字和地址代碼:
import cn.bmob.v3.BmobObject;
import cn.bmob.v3.datatype.BmobFile;
public class video_table extends BmobObject {
private String video_name;
private BmobFile video_url;
public String getVideo_name() {
return video_name;
}
public BmobFile getVideo_url() {
return video_url;
}
}
8.音樂(lè)列表基本顯示代碼:
import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.RecyclerView;
import androidx.recyclerview.widget.StaggeredGridLayoutManager;
import android.os.Bundle;
import android.os.Environment;
import android.util.Log;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Spinner;
import android.widget.TextView;
import android.widget.Toast;
import java.util.ArrayList;
import java.util.List;
import cn.bmob.v3.Bmob;
import cn.bmob.v3.BmobQuery;
import cn.bmob.v3.exception.BmobException;
import cn.bmob.v3.listener.FindListener;
public class VideoActivity extends AppCompatActivity {
//定義對(duì)象
Spinner spin1;
RecyclerView recyclerView;
List<Video> videolist;
VideoAdapter adapter;
private static final String?TAG?= “VideoActivity”;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_video);
initview();?//控件初始化
initData();//數(shù)據(jù)初始化
initBmobData();//比目云初始化
spin1 = findViewById(R.id.spinner_1);?//綁定控件
String[] arr1={“全部”,”舒緩音樂(lè)”,”搖滾音樂(lè)”,”傷感音樂(lè)”,”激情音樂(lè)”,”網(wǎng)絡(luò)歌曲”};
ArrayAdapter<String> adapter1=new ArrayAdapter<String>(VideoActivity.this, android.R.layout.simple_spinner_item,arr1);?//定義適配器
spin1.setAdapter(adapter1);
spin1.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> arg0, View arg1, int arg2, long arg3) {
TextView txt1=(TextView) arg1;
String str1=txt1.getText().toString();
Toast.makeText(VideoActivity.this,str1,Toast.LENGTH_LONG).show();
}
@Override
public void onNothingSelected(AdapterView<?> parent) {
}
});
}
private void initview() {
recyclerView=findViewById(R.id.recyclerview);
}
private void initData() {
videolist= new ArrayList<>();
//獲取網(wǎng)絡(luò)視頻
Video firstvideo = new Video(“水星記”, “android.resource://”+getPackageName()+”/”+R.raw.shuixingji);
videolist.add(firstvideo);
Video secondvideo = new Video(“演員”, “android.resource://”+getPackageName()+”/”+R.raw.yanyuan);
videolist.add(secondvideo);
//獲取本地視頻
Video thirdvideo=new Video(“see you again”,”android.resource://”+getPackageName()+”/”+R.raw.seeyouagain);
videolist.add(thirdvideo);
Video fourthvideo=new Video(“春嬌與志明”,”android.resource://”+getPackageName()+”/”+R.raw.chunjiao);
videolist.add(fourthvideo);
//獲取模擬器中的視頻
Video fifthvideo=new Video(“說(shuō)散就散”, “android.resource://”+getPackageName()+”/”+R.raw.shuosanjiusan);
videolist.add(fifthvideo);
Video sixthvideo=new Video(“愛(ài)人錯(cuò)過(guò)”, “android.resource://”+getPackageName()+”/”+R.raw.airen);
videolist.add(sixthvideo);
//讓數(shù)據(jù)顯示到recyclerview控件上
adapter=new VideoAdapter(videolist);
StaggeredGridLayoutManager layoutManager=new StaggeredGridLayoutManager(1,StaggeredGridLayoutManager.VERTICAL);
recyclerView.setLayoutManager(layoutManager);
recyclerView.setAdapter(adapter);
}
private void initBmobData() {
//第一:默認(rèn)初始化
Bmob.initialize(this, “f7dc294e96e922bec6d5f56d748ccedb”);
BmobQuery<video_table> myquery=new BmobQuery<>();
myquery.findObjects(new FindListener<video_table>() {
@Override
public void done(List<video_table> list, BmobException e) {
if(e==null){
for (video_table video_tablell : list) {
Log.d(TAG, “視頻名稱(chēng): “+video_tablell.getVideo_name()+”視頻的網(wǎng)址:”+video_tablell.getVideo_url().getUrl());
Video sevenvideo = new Video(video_tablell.getVideo_name(), video_tablell.getVideo_url().getUrl());
videolist.add(sevenvideo);
}
adapter.notifyDataSetChanged();
}else{
Toast.makeText(VideoActivity.this,”查詢(xún)失敗”,Toast.LENGTH_LONG).show();
}
}
});
}
}
9.聯(lián)網(wǎng)獲取音樂(lè)Mv代碼:
import android.content.Intent;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import java.util.List;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
public class VideoAdapter extends RecyclerView.Adapter <VideoAdapter.ViewHolder>{
List<Video> myvideolist;
public VideoAdapter(List<Video> myvideolist) {
this.myvideolist = myvideolist;
}
//方法1:用于創(chuàng)建ViewHolder實(shí)例
@NonNull
@Override
public VideoAdapter.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.video_item,parent,false);
final ViewHolder holder=new ViewHolder(view);
//單擊任意視頻跳轉(zhuǎn)到播放界面
holder.videoview.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
int position= holder.getAdapterPosition();?//返回?cái)?shù)據(jù)在適配器中的位置
Video video=myvideolist.get(position);
String myvideoname=video.getVideoName();
String myvideoUrl=video.getVideoUrl();
Intent intent=new Intent(view.getContext(),PlayActivity.class);
intent.putExtra(“videoname”,myvideoname);
intent.putExtra(“videourl”,myvideoUrl);
view.getContext().startActivity(intent);
}
});
return holder;
}
//方法2:用于對(duì)Recyclerview中子項(xiàng)的數(shù)據(jù)進(jìn)行賦值的
@Override
public void onBindViewHolder(@NonNull VideoAdapter.ViewHolder holder, int position) {
Video video=myvideolist.get(position);
holder.video_name.setText(video.getVideoName());
}
//方法3:返回Recyclerview中數(shù)據(jù)源長(zhǎng)度
@Override
public int getItemCount() {
return myvideolist.size();
}
public class ViewHolder extends RecyclerView.ViewHolder {
TextView video_name;
View videoview;
public ViewHolder(@NonNull View view) {
super(view);
video_name=itemView.findViewById(R.id.video_name);
videoview=view;
}
}
}
10.登錄界面跳轉(zhuǎn)注冊(cè)界面代碼:
import androidx.appcompat.app.AppCompatActivity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import com.example.videoplayer.R;
public class WelcomeActivity extends AppCompatActivity {
//定義對(duì)象
Button bt_know_wel;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_welcome);
//綁定控件
bt_know_wel=findViewById(R.id.bt_know_wel);
//按鈕單擊事件
bt_know_wel.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent=new Intent(WelcomeActivity.this,LoginActivity.class);
startActivity(intent);
finish();
}
});
}
}
系統(tǒng)測(cè)試
5.1測(cè)試方法
使用安卓手機(jī)或虛擬機(jī)將寫(xiě)完的項(xiàng)目跑入,看運(yùn)行結(jié)果。
5.2測(cè)試實(shí)現(xiàn)
1.實(shí)現(xiàn)用戶(hù)注冊(cè),將賬號(hào)密碼存儲(chǔ)進(jìn)數(shù)據(jù)庫(kù)中。
2.實(shí)現(xiàn)用戶(hù)登錄
3.實(shí)現(xiàn)音樂(lè)列表顯示
4.實(shí)現(xiàn)點(diǎn)擊相關(guān)音樂(lè)跳轉(zhuǎn)到播放音樂(lè)以及音樂(lè)MV界面
5.實(shí)現(xiàn)音樂(lè)暫停,切換,跳轉(zhuǎn),上一首,下一首。
5.3測(cè)試結(jié)果

2.

3.

4.

5.

結(jié)論與心得
通過(guò)本次Android項(xiàng)目——音樂(lè)播放器,讓我對(duì)Android有了更深入的理解,對(duì)Android代碼有了更加清晰的邏輯性。寫(xiě)完音樂(lè)播放器這個(gè)項(xiàng)目,讓我覺(jué)得編寫(xiě)Android是一個(gè)很有趣的事情。通過(guò)自學(xué)和聽(tīng)課,我學(xué)會(huì)了如何完成一個(gè)項(xiàng)目,在今后的學(xué)習(xí)中,也會(huì)更加積極。
參考文獻(xiàn)[1] 張逸飛,嚴(yán)張凌.基于A(yíng)ndroid的智能家居客戶(hù)端開(kāi)發(fā)[J].信息與電腦(理論版),2020,32(13),63-65.
[2] 吳紅梅,李慧.基于A(yíng)ndroid的智能家居系統(tǒng)開(kāi)發(fā)[J]. 科技展望,2017,(04):21.
[3] 陳國(guó)童,邱興陽(yáng).基于WIFI的Android手機(jī)智能家居控制[J],遼寧大學(xué)學(xué)報(bào)(自然科學(xué)版),2020,47(1),36-37.
[4] 王宏博.計(jì)算機(jī)軟件設(shè)計(jì)的原則分析[J],數(shù)碼世界,2018(7),1.
[5] 徐連成.基于Labview智能家居控制系統(tǒng)設(shè)計(jì)與仿真[J].電子技術(shù)與軟件工程,2020(15):76-78.
[6][4]高小平.中國(guó)智能家居的現(xiàn)狀及其發(fā)展趨勢(shì)[門(mén)].電器與能效管理技術(shù),2005(4) : 18-21。
[7] 郝志芃.我國(guó)智能家居現(xiàn)狀及未來(lái)發(fā)展趨勢(shì)探析[J]. 科技展望, 2017(03).
[8] 王朝玉.基于物聯(lián)網(wǎng)的智能家居控制系統(tǒng)設(shè)計(jì)[J]. 智能應(yīng)用, 2017(01).
[9]莊建輝,金光,江先亮.MQTT協(xié)議消息推送應(yīng)用于海島物聯(lián)網(wǎng)的設(shè)計(jì)與實(shí)現(xiàn)[J].數(shù)據(jù)通信.2018(4):1-3.42.
[10]SHAOS,PIPATTANASOMPORNM,RAHMA.Developmentofphysical-baseddemandrespoe