Service(服务)是一种可以在后台长时间执行的运行操作,没有用户界面的应用组件。主要处理用户长时间不用的功能,但又不得不时刻在后台待命的一些指令。
根据我对其他框架的学习,类同的方法、组件都大同小异,就比如:
其实这些组件、方法、库的设计思想和针对的问题都离不开一种设计模式 - Observer观察者模式(发布-订阅)
主要是完成定时任务、通知反馈这类业务需求而存在。
onCreate() :
首次创建服务时,系统将调用此方法。如果服务已在运行,则不会调用此方法,该方法只调用一次。
onStartCommand() :
当另一个组件通过调用startService()请求启动服务时,系统将调用此方法。
onDestroy() :
当服务不再使用且将被销毁时,系统将调用此方法。
onBind() :
当另一个组件通过调用bindService()与服务绑定时,系统将调用此方法。
onUnbind() :
当另一个组件通过调用unbindService()与服务解绑时,系统将调用此方法。
onRebind() :
当旧的组件与服务解绑后,另一个新的组件与服务绑定,onUnbind()返回true时,系统将调用此方法。
简单写一个测试服务,每隔一秒打印一次时间。
public class TestService extends Service {
//线程的声明
private Thread thread = null;
Calendar ca = null;
@Override
public void onCreate() {
super.onCreate();
// 公共时间对象
ca = Calendar.getInstance();
//创建服务时,创建线程对象
thread = new Thread(null, background ,"TestThread");
}
@SuppressWarnings("deprecation")
@Override
public void onStart(Intent intent, int startId) {
super.onStart(intent, startId);
if (!thread.isAlive()) {
thread.start();
}
}
/**
*服务关闭时,销毁线程
*/
@Override
public void onDestroy() {
super.onDestroy();
if (thread.isAlive()) {
thread.interrupt();
}
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
private Runnable background = new Runnable() {
@Override
public void run() {
try{
while (!Thread.interrupted()) {
int mYear = ca.get(Calendar.YEAR);
int mMonth = ca.get(Calendar.MONTH) + 1;
int mDay = ca.get(Calendar.DAY_OF_MONTH);
int mHour = ca.get(Calendar.HOUR_OF_DAY);
int mMinute = ca.get(Calendar.MINUTE);
time = mYear + "-" + mMonth + "-" + mDay + " " + mHour + ":" + mMinute;
Log.i("当前时间", time)
Thread.sleep(1000);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
}
如果不在AndroidManifest.xml里注册服务,使用后,应用启动会出现报错
<service android:name=".service.TestService" />
public class MainActivity extends AppCompatActivity {
static Intent serviceTest = null; // 测试服务
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
init_service(getBaseContext())
}
private static void init_service(Context context) {
serviceTest = new Intent(context, TestService.class);
context.startService(serviceTest);
}
}
这里我会大致提供实现实时聊天功能的服务部分代码
使用service实现的聊天功能
很久没有画数据流图,有点生疏。
为了展示方便,我就将代码综合在一起了,没有分三层架构。
/**
* 聊天服务
*/
public class ChatService extends Service {
private Thread thread = null; // 线程的声明
static SqlChat sqlChat; // 预显示聊天信息表
static SqlChatInfo sqlChatInfo; // 聊天信息内容表
public static SqlFriend sqlFriend; // 好友信息表
static String uid; // 当前用户ID,主要是用于定向连接服务器
static String time; // 当前时间
static SharedPreferences user;
@Override
public void onCreate() {
super.onCreate();
// 公共时间
Calendar ca = Calendar.getInstance();
// 获取到用户ID
user = getBaseContext().getSharedPreferences("user", MODE_PRIVATE);
uid = user.getString("id", "");
// 初始化数据库对象
sqlChat = new SqlChat(getBaseContext(), uid);
sqlFriend = new SqlFriend(getBaseContext(), Long.valueOf(uid).longValue());
// 创建服务时,创建线程对象
thread = new Thread(null, getChatInfo ,"ChatThread");
}
@SuppressWarnings("deprecation")
@Override
public void onStart(Intent intent, int startId) {
super.onStart(intent, startId);
if (!thread.isAlive()) {
thread.start();
}
}
@Override
public void onDestroy() {
super.onDestroy();
//服务关闭时,销毁线程
if (thread.isAlive()) {
thread.interrupt();
}
}
private Runnable getChatInfo = new Runnable() {
@Override
public void run() {
try{
while (!Thread.interrupted()) {
// 监听聊天信息 服务器控制层的@GetMapper("chat/{id}")
// id可以为雪花临时编号也可以是指定长久编号
String jsonChatInfo = okHttp.get(getBaseContext(), "chat/" + uid);
// 数据转换
Gson gson = new Gson();
Result<List<ChatInfo>> result = gson.fromJson(jsonChatInfo, new TypeToken<Result<List<ChatInfo>>>(){}.getType());
if (result.getCode() == 1) {
int mYear = ca.get(Calendar.YEAR);
int mMonth = ca.get(Calendar.MONTH) + 1;
int mDay = ca.get(Calendar.DAY_OF_MONTH);
int mHour = ca.get(Calendar.HOUR_OF_DAY);
int mMinute = ca.get(Calendar.MINUTE);
time = mYear + "-" + mMonth + "-" + mDay + " " + mHour + ":" + mMinute;
// Log.i("service", result.getData().toString());
// 获取服务器存储的数据
for (ChatInfo chatInfo:result.getData()) {
insertChatInfo(getBaseContext(), chatInfo);
}
}
Thread.sleep(3000); // 每隔三秒实现一次访问
}
} catch (InterruptedException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
};
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
public static void insertChatInfo(Context context, ChatInfo chatInfo) throws IOException {
// 初始化聊天信息数据库
sqlChatInfo = new SqlChatInfo(context, uid, String.valueOf(chatInfo.getId()));
Chat ch = sqlChat.select(Long.valueOf(chatInfo.getId()).longValue());
Friend friend = sqlFriend.select(chatInfo.getId());
// 异常判断
if (friend == null)
throw new IOException("短信指向异常");
// Log.i("test", ch.toString());
if (ch.getId() == null) {
ch.setId(friend.getId());
ch.setImage(friend.getImage());
ch.setNotes(friend.getNotes());
ch.setNext(chatInfo.getText());
ch.setState(1); // 参数state 0 -> 不显示 1 -> 显示(可以实现聊天信息删除以及数据恢复)
ch.setService(1);
ch.setTime(time);
sqlChat.insert(ch);
} else {
ch.setId(friend.getId());
ch.setNext(chatInfo.getText());
ch.setService(ch.getService() + 1); // 小红点加一
ch.setTime(time);
sqlChat.update(ch);
}
// 添加聊天信息
ChatInfo chatInfo1 = new ChatInfo();
chatInfo1.setId(friend.getId());
chatInfo1.setState(1);
chatInfo1.setText(chatInfo.getText());
chatInfo1.setTime(time);
// Log.i("test", chatInfo1.toString());
if (sqlChatInfo.insert(chatInfo1)) {
Log.i("insert", "ChatInfo添加成功!");
ShowNotifications.showN(context, ch);
if (UserInfoActivity.chatInfoViewModel != null) { // 如果在聊天界面就更新数据
UserInfoActivity.chatInfoViewModel.setListChatInfo();
}
if (ChatFragment.chatViewModel != null) { // 如果在主界面Chat更新界面
ChatFragment.chatViewModel.renew();
}
} else {
Log.i("insert", "ChatInfo添加失败!");
}
}
}