Java Android:无论应用程序崩溃或正在工作,都可以运行服务
我正在开发获取应用程序日志并将其上传到服务器的功能。我们正在将日志写入文件 我需要做什么? 我们使用fabric(目前为Firebase crashlystics)进行崩溃报告。但有时会错过很多撞车事件。因此,我们无法跟踪客户问题。我们决定实施我们自己的事故报告工具。我们决定在启动应用程序时上载日志,而不进行任何进一步的处理。一旦应用程序崩溃,崩溃报告将写入该文件,在下次启动应用程序时,该文件将上载到服务器。我不想让用户为这样的事情纠结,所以我决定用服务来做这件事。所以我需要在应用程序启动时启动服务,日志应该上传到服务中的服务器,而不需要任何硬件。如果应用程序在下一行服务启动后崩溃,则服务不应停止 我试过什么? 我使用该服务将日志上传到服务器。我已尝试在应用程序类Java Android:无论应用程序崩溃或正在工作,都可以运行服务,java,android,crash-reports,android-intentservice,foreground-service,Java,Android,Crash Reports,Android Intentservice,Foreground Service,我正在开发获取应用程序日志并将其上传到服务器的功能。我们正在将日志写入文件 我需要做什么? 我们使用fabric(目前为Firebase crashlystics)进行崩溃报告。但有时会错过很多撞车事件。因此,我们无法跟踪客户问题。我们决定实施我们自己的事故报告工具。我们决定在启动应用程序时上载日志,而不进行任何进一步的处理。一旦应用程序崩溃,崩溃报告将写入该文件,在下次启动应用程序时,该文件将上载到服务器。我不想让用户为这样的事情纠结,所以我决定用服务来做这件事。所以我需要在应用程序启动时启动
onCreate()
上启动前台服务,该服务将位于不同的进程上,并且工作正常。但问题是,如果登录活动(第一个活动)onCreate()
发生任何崩溃,前台服务不会按预期启动。服务进程在崩溃后停止
我想要什么?
我想启动前台服务或意图服务上传日志到服务器。上传日志后,它将停止。同时,若应用程序由于其他原因崩溃,服务不应该停止,它应该完成他们的任务
代码
class LogSendService : IntentService("LogSendService") {
private val NOTIFICATION_ID = 12345
internal var allLogFile: File? = null
override fun onHandleIntent(intent: Intent?) {
createAndShowForegroundNotification(this, NOTIFICATION_ID, "We are gathering logs", true)
writeLogs()
}
private fun createAndShowForegroundNotification(mService: Service, notificationId: Int, message: String, isOnGoing: Boolean) {
val builder = getNotificationBuilder(mService,
"Log Service", // Channel id
NotificationManagerCompat.IMPORTANCE_LOW) //Low importance prevent visual appearance for this notification channel on top
builder.setSmallIcon(R.mipmap.home_icon)
.setContentTitle(mService.getString(R.string.app_name))
.setContentText(message)
if (isOnGoing) {
builder.setOngoing(true)
}
val notification = builder.build()
mService.startForeground(notificationId, notification)
}
private fun writeLogs() {
try {
//log write and upload process
createAndShowForegroundNotification(this, NOTIFICATION_ID, "success", false)
} catch (e: Exception) {
e.printStackTrace()
createAndShowForegroundNotification(this, NOTIFICATION_ID, e.message!!, false)
}
stopForeground(false)
stopSelf()
}
companion object {
val STATUS_FINISHED = 1
fun getNotificationBuilder(context: Context, channelId: String, importance: Int): NotificationCompat.Builder {
val builder: NotificationCompat.Builder
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
prepareChannel(context, channelId, importance)
builder = NotificationCompat.Builder(context, channelId)
} else {
builder = NotificationCompat.Builder(context)
}
return builder
}
@TargetApi(26)
private fun prepareChannel(context: Context, id: String, importance: Int) {
val appName = context.getString(R.string.app_name)
val description = "Testing Log Service"
val nm = context.getSystemService(Activity.NOTIFICATION_SERVICE) as NotificationManager
if (nm != null) {
var nChannel: NotificationChannel? = nm.getNotificationChannel(id)
if (nChannel == null) {
nChannel = NotificationChannel(id, appName, importance)
nChannel.description = description
nm.createNotificationChannel(nChannel)
}
}
}
}
}
class LogWriteService : Service() {
private val NOTIFICATION_ID = 12345
internal var allLogFile: File? = null
override fun onBind(intent: Intent): IBinder? {
return null
}
inner class MyBinder : Binder() {
val service: LogWriteService
get() = this@LogWriteService
}
override fun onCreate() {
super.onCreate()
// startLogService();
createAndShowForegroundNotification(this, NOTIFICATION_ID, "We are gathering logs", true)
writeLogs()
}
private fun createAndShowForegroundNotification(yourService: Service, notificationId: Int, message: String, isOnGoing: Boolean) {
val builder = getNotificationBuilder(yourService,
"Log Service", // Channel id
NotificationManagerCompat.IMPORTANCE_LOW) //Low importance prevent visual appearance for this notification channel on top
builder.setSmallIcon(R.mipmap.home_icon)
.setContentTitle(yourService.getString(R.string.app_name))
.setContentText(message)
if (isOnGoing) {
builder.setOngoing(true)
}
val notification = builder.build()
yourService.startForeground(notificationId, notification)
}
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
return Service.START_STICKY
}
private fun writeLogs() {
try {
//log write and upload
} catch (e: Exception) {
e.printStackTrace()
createAndShowForegroundNotification(this, NOTIFICATION_ID, e.message!!, false)
}
stopForeground(false)
stopSelf()
}
companion object {
val STATUS_FINISHED = 1
fun getNotificationBuilder(context: Context, channelId: String, importance: Int): NotificationCompat.Builder {
val builder: NotificationCompat.Builder
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
prepareChannel(context, channelId, importance)
builder = NotificationCompat.Builder(context, channelId)
} else {
builder = NotificationCompat.Builder(context)
}
return builder
}
@TargetApi(26)
private fun prepareChannel(context: Context, id: String, importance: Int) {
val appName = context.getString(R.string.app_name)
val description = "Testing Log Service"
val nm = context.getSystemService(Activity.NOTIFICATION_SERVICE) as NotificationManager
if (nm != null) {
var nChannel: NotificationChannel? = nm.getNotificationChannel(id)
if (nChannel == null) {
nChannel = NotificationChannel(id, appName, importance)
nChannel.description = description
nm.createNotificationChannel(nChannel)
}
}
}
}
}
应用程序类
public void onCreate() {
startLogService()
// Other code
}
private void startLogService() {
Intent serviceIntent = new Intent(this, LogWriteService.class);
/* if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { // i have tried with this also
startForegroundService(serviceIntent);
} else {
startService(serviceIntent);
}*/
bindService(serviceIntent, m_serviceConnection, BIND_AUTO_CREATE);
}
后勤活动
public class LoginActivity extends AppCompatActivity{
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_initial_login);
int i = 10/0; // just for crash test
}
}
LogSendService类(意向服务)
LogSendService类(前台服务)
有人能提出解决方案吗?还是更好的方法?
注意:有些代码是Java的,有些是Kotlin的您到底想要什么?服务应该永远运行吗?并使用startService()而不是bindService()。我想启动将日志上载到服务器的服务。它将在上载日志后停止。但条件是,若应用程序同时崩溃,那个么服务不应该停止,它应该完成那个项任务。bindService()在绑定活动激活之前具有作用域。您到底想要什么?服务应该永远运行吗?并使用startService()而不是bindService()。我想启动将日志上载到服务器的服务。它将在上载日志后停止。但条件是,若应用程序同时崩溃,那个么服务不应该停止,它应该完成那个项任务。bindService()具有作用域,直到绑定活动处于活动状态。