Android 关闭服务的进度对话框
Android close progress dialog from service
在我的片段中有一个按钮,单击该按钮将启动一个服务,该服务轮询传感器,并使用执行程序服务将传感器数据存储到数据库中。片段的 onClick
如下所示:
public void onClick(View v) {
if (!recordingStarted){
try{
recordingStarted = true;
mainActivity.startService(new Intent(mainActivity, SensorService.class));
startButton.setText(getResources().getString(R.string.start_button_label_stop));
Snackbar.make(coordinatorLayout, "Recording...", Snackbar.LENGTH_SHORT).show();
} catch (SQLException e){
mainActivity.logger.e(getActivity(),TAG, "SQL error insertSubject()", e);
}
} else {
dialog = new ProgressDialog(mainActivity);
dialog.setTitle("Stop recording");
dialog.setMessage("Please wait...");
dialog.show();
mainActivity.stopService(new Intent(mainActivity, SensorService.class));
startButton.setEnabled(false);
Snackbar.make(coordinatorLayout, "Recording stopped.", Snackbar.LENGTH_SHORT).show();
}
}
SensorService
class 设置为使用 ExecutorService
.
每 10 毫秒将传感器数据存储到数据库中
class 的相关部分是:
public class SensorService extends Service implements SensorEventListener {
public void onSensorChanged(SensorEvent event) {
//get sensor values here
//insert into database
try{
executor.execute(insertHandler);
} catch (SQLException e) {
Log.e(TAG, "insertData: " + e.getMessage(), e);
}
}
}
@Override
public void onCreate() {
super.onCreate();
dbHelper = new DBHelper(getApplicationContext());
PowerManager manager =
(PowerManager) getSystemService(Context.POWER_SERVICE);
wakeLock = manager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
registerReceiver(receiver, new IntentFilter(Intent.ACTION_SCREEN_OFF));
//Executor service and runnable for DB inserts
executor = Executors.newSingleThreadExecutor();
insertHandler = new InsertHandler();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
super.onStartCommand(intent, flags, startId);
startForeground(Process.myPid(), new Notification());
registerListener();
wakeLock.acquire();
return START_STICKY;
}
@Override
public void onDestroy() {
//Prevent new tasks from being added to thread
executor.shutdown();
try {
//Wait for all tasks to finish before we proceed
while (!executor.awaitTermination(10, TimeUnit.SECONDS)) {
Log.i(TAG, "Waiting for current tasks to finish");
}
} catch (InterruptedException e) {
executor.shutdownNow();
}
//Stop everything else once the task queue is clear
unregisterReceiver(receiver);
unregisterListener();
wakeLock.release();
dbHelper.close();
stopForeground(true);
}
class InsertHandler implements Runnable {
public void run() {
dbHelper.insertData(Short.parseShort(MainActivity.subInfo.get("subNum")), System.currentTimeMillis(),
accelerometerMatrix[0], accelerometerMatrix[1], accelerometerMatrix[2],
accelerometerWorldMatrix[0], accelerometerWorldMatrix[1], accelerometerWorldMatrix[2],
gyroscopeMatrix[0], gyroscopeMatrix[1], gyroscopeMatrix[2]);
}
}
}
因此,当用户点击按钮时,SensorService
会执行其 onCreate
和 onStartCommand
方法。每当传感器数据发生变化时,执行程序服务将其插入数据库
当用户再次点击停止按钮时,我告诉执行器关闭,但首先要完成所有当前任务的处理。清除执行程序队列后,我们关闭数据库、注销侦听器等。
在执行程序等待关闭并清除队列的这个阶段,我想向用户显示一个进度对话框,告诉用户它正在完成关闭过程。
因此,一旦按下停止按钮,我就会在片段本身中显示进度对话框。但是,如何仅在执行程序服务完成其队列处理并正确关闭后才关闭该对话框?
我可以使用异步任务轻松完成此操作,但我选择为此使用执行程序服务,因此这不是一个选项
进度对话框属于片段,所以我无法从服务内部执行类似 MainActivity.dialog.dismiss()
的操作。无论如何,我觉得这不是一种非常干净的处理方式
所以我想我只剩下 Handlers,但不完全确定在这种情况下如何设置它,因为执行程序服务在另一个服务中运行 (SensorService
)。如果使用处理程序来解决这个问题,代码会是什么样子?
您需要某种机制让服务向 activity 组件发送信号。最简单和最常见的方法是使用事件总线。正确的实现完全取决于您,但您可以使用现有的事件总线库来帮助您。您可以通过简单的 google 搜索找到这些。
在我的片段中有一个按钮,单击该按钮将启动一个服务,该服务轮询传感器,并使用执行程序服务将传感器数据存储到数据库中。片段的 onClick
如下所示:
public void onClick(View v) {
if (!recordingStarted){
try{
recordingStarted = true;
mainActivity.startService(new Intent(mainActivity, SensorService.class));
startButton.setText(getResources().getString(R.string.start_button_label_stop));
Snackbar.make(coordinatorLayout, "Recording...", Snackbar.LENGTH_SHORT).show();
} catch (SQLException e){
mainActivity.logger.e(getActivity(),TAG, "SQL error insertSubject()", e);
}
} else {
dialog = new ProgressDialog(mainActivity);
dialog.setTitle("Stop recording");
dialog.setMessage("Please wait...");
dialog.show();
mainActivity.stopService(new Intent(mainActivity, SensorService.class));
startButton.setEnabled(false);
Snackbar.make(coordinatorLayout, "Recording stopped.", Snackbar.LENGTH_SHORT).show();
}
}
SensorService
class 设置为使用 ExecutorService
.
class 的相关部分是:
public class SensorService extends Service implements SensorEventListener {
public void onSensorChanged(SensorEvent event) {
//get sensor values here
//insert into database
try{
executor.execute(insertHandler);
} catch (SQLException e) {
Log.e(TAG, "insertData: " + e.getMessage(), e);
}
}
}
@Override
public void onCreate() {
super.onCreate();
dbHelper = new DBHelper(getApplicationContext());
PowerManager manager =
(PowerManager) getSystemService(Context.POWER_SERVICE);
wakeLock = manager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
registerReceiver(receiver, new IntentFilter(Intent.ACTION_SCREEN_OFF));
//Executor service and runnable for DB inserts
executor = Executors.newSingleThreadExecutor();
insertHandler = new InsertHandler();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
super.onStartCommand(intent, flags, startId);
startForeground(Process.myPid(), new Notification());
registerListener();
wakeLock.acquire();
return START_STICKY;
}
@Override
public void onDestroy() {
//Prevent new tasks from being added to thread
executor.shutdown();
try {
//Wait for all tasks to finish before we proceed
while (!executor.awaitTermination(10, TimeUnit.SECONDS)) {
Log.i(TAG, "Waiting for current tasks to finish");
}
} catch (InterruptedException e) {
executor.shutdownNow();
}
//Stop everything else once the task queue is clear
unregisterReceiver(receiver);
unregisterListener();
wakeLock.release();
dbHelper.close();
stopForeground(true);
}
class InsertHandler implements Runnable {
public void run() {
dbHelper.insertData(Short.parseShort(MainActivity.subInfo.get("subNum")), System.currentTimeMillis(),
accelerometerMatrix[0], accelerometerMatrix[1], accelerometerMatrix[2],
accelerometerWorldMatrix[0], accelerometerWorldMatrix[1], accelerometerWorldMatrix[2],
gyroscopeMatrix[0], gyroscopeMatrix[1], gyroscopeMatrix[2]);
}
}
}
因此,当用户点击按钮时,SensorService
会执行其 onCreate
和 onStartCommand
方法。每当传感器数据发生变化时,执行程序服务将其插入数据库
当用户再次点击停止按钮时,我告诉执行器关闭,但首先要完成所有当前任务的处理。清除执行程序队列后,我们关闭数据库、注销侦听器等。
在执行程序等待关闭并清除队列的这个阶段,我想向用户显示一个进度对话框,告诉用户它正在完成关闭过程。
因此,一旦按下停止按钮,我就会在片段本身中显示进度对话框。但是,如何仅在执行程序服务完成其队列处理并正确关闭后才关闭该对话框?
我可以使用异步任务轻松完成此操作,但我选择为此使用执行程序服务,因此这不是一个选项
进度对话框属于片段,所以我无法从服务内部执行类似 MainActivity.dialog.dismiss()
的操作。无论如何,我觉得这不是一种非常干净的处理方式
所以我想我只剩下 Handlers,但不完全确定在这种情况下如何设置它,因为执行程序服务在另一个服务中运行 (SensorService
)。如果使用处理程序来解决这个问题,代码会是什么样子?
您需要某种机制让服务向 activity 组件发送信号。最简单和最常见的方法是使用事件总线。正确的实现完全取决于您,但您可以使用现有的事件总线库来帮助您。您可以通过简单的 google 搜索找到这些。