我昨天刚开始学习编写服务,这里我有一项服务,即使我的应用程序终止,我也希望它能够一直运行。此服务在我的Firebase数据库上有一个侦听器,如果数据已更改,则会生成通知。
令我感到困惑的是,只有在应用程序运行时,我的服务才能成功运行。在我关闭应用程序后,我的手机立即通知我“不幸的是,此应用程序已停止(崩溃)”。警报来了两次,然后服务从未重启(我猜)。
我无法弄清楚为什么我的服务在关闭应用程序后崩溃了。我在MainActivity中的OnCreate方法中启动了Service。这是整个服务类:
public class MyService extends Service
{
private static DatabaseReference databaseReference;
private static String uid;
private static SharedPreferences sharedPreferences;
private static int notification_id=0;
private static boolean launched=false;
public MyService(){}
@Override public int onStartCommand(Intent intent, int flags, int startId)
{
if(!launched)
{
launched=true;
databaseReference=MainActivity.databaseReference;
uid=MainActivity.uid;
sharedPreferences=MainActivity.sharedPreferences;
databaseReference.child("users").child(uid).addValueEventListener(new ValueEventListener()
{
@Override public void onDataChange(DataSnapshot dataSnapshot)
{
MyData myData=dataSnapshot.getValue(MyData.class);
if(myData!=null)
{
ArrayList<String> myGroups=myData.getGroups();
for(String group_id:myGroups)
{
if(group_record_listener!=null)databaseReference.child("group_records").child(group_id).removeEventListener(group_record_listener);
databaseReference.child("group_records").child(group_id).addValueEventListener(group_record_listener);
}
}
}
@Override public void onCancelled(DatabaseError databaseError)
{
System.out.println(databaseError.getMessage());
}
});
}
return START_STICKY;
}
private ValueEventListener group_record_listener=new ValueEventListener()
{
@Override public void onDataChange(DataSnapshot dataSnapshot)
{
final String group_id=dataSnapshot.getKey();
Query lastQuery=databaseReference.child("group_records").child(group_id).child("records").orderByKey().limitToLast(1);
lastQuery.addListenerForSingleValueEvent(new ValueEventListener()
{
@Override public void onDataChange(DataSnapshot dataSnapshot)
{
for(DataSnapshot childSnapshot:dataSnapshot.getChildren())
{
final Record new_record=childSnapshot.getValue(Record.class);
if(new_record!=null)
{
if((new_record.getType()==1)&&new_record.getTo_name().equals(sharedPreferences.getString("name","")))
{
if(group_record_listener!=null)databaseReference.child("group_records").child(group_id).removeEventListener(group_record_listener);
}
if(!new_record.getOperator().equals(sharedPreferences.getString("name","")))
{
databaseReference.child("groups").child(group_id).child("name").addListenerForSingleValueEvent(new ValueEventListener()
{
@Override public void onDataChange(DataSnapshot dataSnapshot)
{
String group_name=(String)dataSnapshot.getValue();
generateNotification(new_record,group_name);
}
@Override public void onCancelled(DatabaseError databaseError){}
});
}
}
}
}
@Override public void onCancelled(DatabaseError databaseError){}
});
}
@Override public void onCancelled(DatabaseError databaseError)
{
System.out.println(databaseError.getMessage());
}
};
private void generateNotification(Record record,String group_name)
{
String str="";
switch (record.getType())
{
//. . . determine str
}
Notification notification=new Notification.Builder(this)
.setSmallIcon(R.mipmap.ic_launcher)
.setContentTitle("group \""+group_name+"\"")
.setContentText(str)
.setWhen(System.currentTimeMillis())
.build();
NotificationManager manager=(NotificationManager)getSystemService(NOTIFICATION_SERVICE);
notification_id++;
manager.notify(notification_id,notification);
}
@Override public IBinder onBind(Intent intent)
{
return null;
}
}
如果您有任何想法,请帮忙。提前谢谢~~
答案 0 :(得分:1)
您的服务使用来自MainActivity
的静态成员:databaseReference
,uid
和sharedPreferences
。正如您在帖子中解释的那样,该服务是从MainActivity.onCreate()
开始的。在这种情况下,databaseReference
,uid
和sharedPreferences
(可能)已初始化并具有有效值。
服务中的onStartCommand()
方法返回START_STICKY
。如果您的应用程序被终止,例如,如果您将其放在后台,然后从最近的任务列表中滑动它,则应用程序的进程将被销毁,然后,因为您的服务是START_STICKY
,系统会创建一个应用程序的新实例(新进程)。此新实例包含服务组件,但没有MainActivity
的有效实例。 MainActivity
的静态成员将具有默认值。特别是,uid
将为null,这会在您调用databaseReference.child("users").child(uid)
时导致异常。您可以通过添加调试日志记录来输出uid
和sharedPreferences
的值来确认这种情况。
但在花费大量精力试图完成这项工作之前,请注意当前的设计是电池杀手。使数据库上的活动侦听器始终运行服务需要Firebase维护与数据库的网络连接。我不知道您的数据库监控要求是什么,但通常情况下更好的情况是服务器端处理监视器更改(例如云功能)并将FCM消息发送给需要通知的用户。