Android:关闭应用后服务崩溃

时间:2017-09-01 16:25:01

标签: android firebase service firebase-realtime-database

我昨天刚开始学习编写服务,这里我有一项服务,即使我的应用程序终止,我也希望它能够一直运行。此服务在我的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;
}
}

如果您有任何想法,请帮忙。提前谢谢~~

1 个答案:

答案 0 :(得分:1)

您的服务使用来自MainActivity的静态成员:databaseReferenceuidsharedPreferences。正如您在帖子中解释的那样,该服务是从MainActivity.onCreate()开始的。在这种情况下,databaseReferenceuidsharedPreferences(可能)已初始化并具有有效值。

服务中的onStartCommand()方法返回START_STICKY。如果您的应用程序被终止,例如,如果您将其放在后台,然后从最近的任务列表中滑动它,则应用程序的进程将被销毁,然后,因为您的服务是START_STICKY,系统会创建一个应用程序的新实例(新进程)。此新实例包含服务组件,但没有MainActivity的有效实例。 MainActivity的静态成员将具有默认值。特别是,uid将为null,这会在您调用databaseReference.child("users").child(uid)时导致异常。您可以通过添加调试日志记录来输出uidsharedPreferences的值来确认这种情况。

但在花费大量精力试图完成这项工作之前,请注意当前的设计是电池杀手。使数据库上的活动侦听器始终运行服务需要Firebase维护与数据库的网络连接。我不知道您的数据库监控要求是什么,但通常情况下更好的情况是服务器端处理监视器更改(例如云功能)并将FCM消息发送给需要通知的用户。