尝试在后台/前台运行时应用程序崩溃但适用于其他手机
Posted
技术标签:
【中文标题】尝试在后台/前台运行时应用程序崩溃但适用于其他手机【英文标题】:App crashes when trying to run in background/foreground but works for other phones 【发布时间】:2018-07-24 22:25:56 【问题描述】:在使用 android studio 和 firebase 时,单击通知时,我的应用(在后台或前台)在 API 26 设备上崩溃。而当我使用 API 23 设备时,当应用程序关闭并单击通知时应用程序崩溃,但当应用程序处于后台/前台时仍然可以处理通知。我不明白这个问题,感谢任何帮助。
通知服务
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Intent;
import android.support.v4.app.NotificationCompat;
import com.google.firebase.messaging.RemoteMessage;
public class FirebaseMessagingService extends com.google.firebase.messaging.FirebaseMessagingService
@Override
public void onMessageReceived(RemoteMessage remoteMessage)
super.onMessageReceived(remoteMessage);
String notification_title = remoteMessage.getNotification().getTitle();
String notification_message = remoteMessage.getNotification().getBody();
String click_action = remoteMessage.getNotification().getClickAction();
String from_user_id = remoteMessage.getData().get("from_user_id");
NotificationCompat.Builder mBuilder =
new NotificationCompat.Builder(FirebaseMessagingService.this, "default")
.setSmallIcon(R.mipmap.ic_launcher)
.setContentTitle(notification_title)
.setContentText(notification_message);
Intent resultIntent = new Intent(click_action);
resultIntent.putExtra("user_id", from_user_id);
PendingIntent resultPendingIntent =
PendingIntent.getActivity(
FirebaseMessagingService.this,
0,
resultIntent,
PendingIntent.FLAG_UPDATE_CURRENT
);
mBuilder.setContentIntent(resultPendingIntent);
int mNotificationId = (int) System.currentTimeMillis();
NotificationManager mNotifyMgr =
(NotificationManager) getSystemService(NOTIFICATION_SERVICE);
mNotifyMgr.notify(mNotificationId, mBuilder.build());
用户活动
import android.content.Context;
import android.content.Intent;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.Toolbar;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import com.firebase.ui.database.FirebaseRecyclerAdapter;
import com.firebase.ui.database.FirebaseRecyclerOptions;
import com.google.firebase.database.DatabaseReference;
import com.google.firebase.database.FirebaseDatabase;
import com.google.firebase.database.Query;
import com.squareup.picasso.Picasso;
import de.hdodenhof.circleimageview.CircleImageView;
public class UsersActivity extends AppCompatActivity
private Toolbar mToolbar;
private RecyclerView mUsersList;
private DatabaseReference mUsersDatabase;
@Override
protected void onCreate(Bundle savedInstanceState)
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_users);
mToolbar=(Toolbar)findViewById(R.id.users_appBar);
setSupportActionBar(mToolbar);
getSupportActionBar().setTitle("All Users");
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
mUsersDatabase= FirebaseDatabase.getInstance().getReference().child("Users");
mUsersDatabase.keepSynced(true);
mUsersList=(RecyclerView)findViewById(R.id.users_list);
mUsersList.setHasFixedSize(true);
mUsersList.setLayoutManager(new LinearLayoutManager(this));
@Override
protected void onStart()
super.onStart();
startListening();
public void startListening()
Query query = FirebaseDatabase.getInstance()
.getReference()
.child("Users")
.limitToLast(50);
FirebaseRecyclerOptions<Users> options =
new FirebaseRecyclerOptions.Builder<Users>()
.setQuery(query, Users.class)
.build();
FirebaseRecyclerAdapter<Users, UserViewHolder> adapter = new FirebaseRecyclerAdapter<Users, UserViewHolder>(options)
@Override
public UserViewHolder onCreateViewHolder(ViewGroup parent, int viewType)
// Create a new instance of the ViewHolder, in this case we are using a custom
// layout called R.layout.message for each item
View view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.users_single_layout, parent, false);
return new UserViewHolder(view);
@Override
protected void onBindViewHolder(UserViewHolder holder, int position, Users model)
// Bind the Chat object to the ChatHolder
holder.setName(model.name);
holder.setStatus(model.status);
holder.setUserImage(model.getThumb_image());
final String user_id= getRef(position).getKey();
holder.mView.setOnClickListener(new View.OnClickListener()
@Override
public void onClick(View v)
Intent profileIntent = new Intent(UsersActivity.this, ProfileActivity.class);
if (user_id != null)
profileIntent.putExtra("user_id", user_id);
startActivity(profileIntent);
);
;
mUsersList.setAdapter(adapter);
adapter.startListening();
public static class UserViewHolder extends RecyclerView.ViewHolder
View mView;
public UserViewHolder(View itemView)
super(itemView);
mView = itemView;
public void setName(String name)
TextView userNameView = (TextView) mView.findViewById(R.id.user_single_name);
userNameView.setText(name);
public void setStatus(String status)
TextView userStatusView= (TextView) mView.findViewById(R.id.user_single_status);
userStatusView.setText(status);
public void setUserImage(String thumb_image)
CircleImageView userImageView = (CircleImageView) mView.findViewById(R.id.user_single_image);
Picasso.get().load(thumb_image).placeholder(R.drawable.accountpicture).into(userImageView);
个人资料活动
import android.app.ProgressDialog;
import android.support.annotation.NonNull;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;
import com.google.android.gms.tasks.OnCompleteListener;
import com.google.android.gms.tasks.OnFailureListener;
import com.google.android.gms.tasks.OnSuccessListener;
import com.google.android.gms.tasks.Task;
import com.google.firebase.auth.FirebaseAuth;
import com.google.firebase.auth.FirebaseUser;
import com.google.firebase.database.DataSnapshot;
import com.google.firebase.database.DatabaseError;
import com.google.firebase.database.DatabaseReference;
import com.google.firebase.database.FirebaseDatabase;
import com.google.firebase.database.ValueEventListener;
import com.squareup.picasso.Callback;
import com.squareup.picasso.NetworkPolicy;
import com.squareup.picasso.Picasso;
import java.text.DateFormat;
import java.util.Date;
import java.util.HashMap;
public class ProfileActivity extends AppCompatActivity
private ImageView mProfileImage;
private TextView mProfileName, mProfileStatus, mProfileFriendsCount;
private Button mProfileSendReqBtn;
private DatabaseReference mUserDatabase;
private Button declineRequest;
private FirebaseUser mCurrent_user;
private ProgressDialog mProgressDialog;
private DatabaseReference mFriendRequestDatabase;
private DatabaseReference mFriendDatabase;
private String mCurrent_state;
private DatabaseReference mNotificationDatabase;
@Override
protected void onCreate(Bundle savedInstanceState)
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_profile);
final String user_id = getIntent().getStringExtra("user_id");
mUserDatabase = FirebaseDatabase.getInstance().getReference().child("Users").child(user_id);
mFriendRequestDatabase = FirebaseDatabase.getInstance().getReference().child("Friend_req");
mCurrent_user= FirebaseAuth.getInstance().getCurrentUser();
mFriendDatabase= FirebaseDatabase.getInstance().getReference().child("Friends");
mNotificationDatabase= FirebaseDatabase.getInstance().getReference().child("notifications");
mProfileImage = (ImageView) findViewById(R.id.profile_image);
mProfileName = (TextView) findViewById(R.id.profile_profileName);
mProfileStatus = (TextView) findViewById(R.id.profile_status);
mProfileFriendsCount = (TextView) findViewById(R.id.profile_totalFriends);
mProfileSendReqBtn = (Button) findViewById(R.id.profile_send_req_btn);
declineRequest= (Button)findViewById(R.id.profile_decline_btn);
mCurrent_state = "not_friends";
mProgressDialog = new ProgressDialog(this);
mProgressDialog.setTitle("Loading User Data");
mProgressDialog.setMessage("Please wait...");
mProgressDialog.setCanceledOnTouchOutside(false);
mProgressDialog.show();
mUserDatabase.keepSynced(true);
mFriendDatabase.keepSynced(true);
mFriendRequestDatabase.keepSynced(true);
declineRequest.setVisibility(View.INVISIBLE);
if(mCurrent_user.getUid().equals(user_id))
mProfileSendReqBtn.setVisibility(View.INVISIBLE);
mUserDatabase.addValueEventListener(new ValueEventListener()
@Override
public void onDataChange(@NonNull DataSnapshot dataSnapshot)
String diplay_name = dataSnapshot.child("name").getValue().toString();
String status = dataSnapshot.child("status").getValue().toString();
final String image = dataSnapshot.child("image").getValue().toString();
mProfileName.setText(diplay_name);
mProfileStatus.setText(status);
Picasso.get().load(image).networkPolicy(NetworkPolicy.OFFLINE).placeholder(R.drawable.accountpicture).into(mProfileImage, new Callback()
@Override
public void onSuccess()
@Override
public void onError(Exception e)
Picasso.get().load(image).placeholder(R.drawable.accountpicture).into(mProfileImage);
);
mFriendRequestDatabase.child(mCurrent_user.getUid()).addListenerForSingleValueEvent(new ValueEventListener()
@Override
public void onDataChange(@NonNull DataSnapshot dataSnapshot)
if(dataSnapshot.hasChild(user_id))
String req_type= dataSnapshot.child(user_id).child("request_type").getValue().toString();
if(req_type.equals("received"))
mCurrent_state= "req_received";
mProfileSendReqBtn.setText("Accept Friend Request");
declineRequest.setVisibility(View.VISIBLE);
mUserDatabase.keepSynced(true);
mFriendDatabase.keepSynced(true);
mFriendRequestDatabase.keepSynced(true);
else if(req_type.equals("sent"))
mCurrent_state="req_sent";
mProfileSendReqBtn.setText("Cancel Friend Request");
mUserDatabase.keepSynced(true);
mFriendDatabase.keepSynced(true);
mFriendRequestDatabase.keepSynced(true);
else if(req_type.equals("req_sent"))
mCurrent_state= "not_friends";
mProfileSendReqBtn.setText("Send Friend Request");
mUserDatabase.keepSynced(true);
mFriendDatabase.keepSynced(true);
mFriendRequestDatabase.keepSynced(true);
mProgressDialog.dismiss();
else
mFriendDatabase.child(mCurrent_user.getUid()).addListenerForSingleValueEvent(new ValueEventListener()
@Override
public void onDataChange(@NonNull DataSnapshot dataSnapshot)
if(dataSnapshot.hasChild(user_id))
mCurrent_state= "friends";
mProfileSendReqBtn.setText("Unfriend User");
mProfileSendReqBtn.setEnabled(true);
mUserDatabase.keepSynced(true);
mFriendDatabase.keepSynced(true);
mFriendRequestDatabase.keepSynced(true);
mProgressDialog.dismiss();
@Override
public void onCancelled(@NonNull DatabaseError databaseError)
mProgressDialog.dismiss();
);
@Override
public void onCancelled(@NonNull DatabaseError databaseError)
);
@Override
public void onCancelled(@NonNull DatabaseError databaseError)
);
mProfileSendReqBtn.setOnClickListener(new View.OnClickListener()
@Override
public void onClick(View v)
mProfileSendReqBtn.setEnabled(false);
if (user_id.equals(mCurrent_user.getUid()))
Toast.makeText(ProfileActivity.this, "Cannot send friend request to yourself!", Toast.LENGTH_LONG).show();
declineRequest.setVisibility(View.INVISIBLE);
else
if (mCurrent_state.equals("not_friends"))
mFriendRequestDatabase.child(mCurrent_user.getUid()).child(user_id).child("request_type").setValue("sent").addOnCompleteListener(new OnCompleteListener<Void>()
@Override
public void onComplete(@NonNull Task<Void> task)
if (task.isSuccessful())
mFriendRequestDatabase.child(user_id).child(mCurrent_user.getUid()).child("request_type").setValue("received").addOnSuccessListener(new OnSuccessListener<Void>()
@Override
public void onSuccess(Void aVoid)
HashMap<String, String> notificationData= new HashMap<>();
notificationData.put("from", mCurrent_user.getUid());
notificationData.put("type", "request");
mNotificationDatabase.child(user_id).push().setValue(notificationData).addOnSuccessListener(new OnSuccessListener<Void>()
@Override
public void onSuccess(Void aVoid)
mCurrent_state = "req_sent";
mProfileSendReqBtn.setText("Cancel Friend Request");
mUserDatabase.keepSynced(true);
mFriendDatabase.keepSynced(true);
mFriendRequestDatabase.keepSynced(true);
);
);
else
Toast.makeText(ProfileActivity.this, "Error", Toast.LENGTH_LONG).show();
mProfileSendReqBtn.setEnabled(true);
);
if (mCurrent_state.equals("req_sent"))
mProfileSendReqBtn.setEnabled(true);
mFriendRequestDatabase.child(mCurrent_user.getUid()).child(user_id).removeValue().addOnSuccessListener(new OnSuccessListener<Void>()
@Override
public void onSuccess(Void aVoid)
mFriendRequestDatabase.child(user_id).child(mCurrent_user.getUid()).removeValue().addOnSuccessListener(new OnSuccessListener<Void>()
@Override
public void onSuccess(Void aVoid)
mCurrent_state = "req_sent";
mProfileSendReqBtn.setText("Send Friend Request");
mCurrent_state = "not_friends";
mUserDatabase.keepSynced(true);
mFriendDatabase.keepSynced(true);
mFriendRequestDatabase.keepSynced(true);
);
);
if (mCurrent_state.equals("req_received"))
declineRequest.setVisibility(View.INVISIBLE);
mProfileSendReqBtn.setEnabled(true);
final String currentDate = DateFormat.getDateTimeInstance().format(new Date());
mFriendDatabase.child(mCurrent_user.getUid()).child(user_id).setValue(currentDate).addOnSuccessListener(new OnSuccessListener<Void>()
@Override
public void onSuccess(Void aVoid)
mFriendDatabase.child(user_id).child(mCurrent_user.getUid()).setValue(currentDate).addOnSuccessListener(new OnSuccessListener<Void>()
@Override
public void onSuccess(Void aVoid)
mFriendRequestDatabase.child(mCurrent_user.getUid()).child(user_id).removeValue().addOnSuccessListener(new OnSuccessListener<Void>()
@Override
public void onSuccess(Void aVoid)
mFriendRequestDatabase.child(user_id).child(mCurrent_user.getUid()).removeValue().addOnSuccessListener(new OnSuccessListener<Void>()
@Override
public void onSuccess(Void aVoid)
mCurrent_state = "friends";
mProfileSendReqBtn.setText("Unfriend User");
mUserDatabase.keepSynced(true);
mFriendDatabase.keepSynced(true);
mFriendRequestDatabase.keepSynced(true);
);
);
);
);
);
declineRequest.setOnClickListener(new View.OnClickListener()
@Override
public void onClick(View v)
declineRequest.setVisibility(View.INVISIBLE);
mFriendRequestDatabase.child(mCurrent_user.getUid()).child(user_id).removeValue().addOnSuccessListener(new OnSuccessListener<Void>()
@Override
public void onSuccess(Void aVoid)
mFriendRequestDatabase.child(user_id).child(mCurrent_user.getUid()).removeValue().addOnSuccessListener(new OnSuccessListener<Void>()
@Override
public void onSuccess(Void aVoid)
mCurrent_state= "not_friends";
mProfileSendReqBtn.setText("Send Friend Request");
mUserDatabase.keepSynced(true);
mFriendDatabase.keepSynced(true);
mFriendRequestDatabase.keepSynced(true);
);
);
);
INDEX.JS 文件
'use strict'
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp(functions.config().firebase);
/*
* 'OnWrite' works as 'addValueEventListener' for android. It will fire the function
* everytime there is some item added, removed or changed from the provided 'database.ref'
* 'sendNotification' is the name of the function, which can be changed according to
* your requirement
*/
exports.sendNotification = functions.database.ref('/notifications/user_id/notification_id').onWrite((change, context) =>
/*
* You can store values as variables from the 'database.ref'
* Just like here, I've done for 'user_id' and 'notification'
*/
const user_id = context.params.user_id;
const notification_id = context.params.notification_id;
console.log('We have a notification from : ', user_id);
/*
* Stops proceeding to the rest of the function if the entry is deleted from database.
* If you want to work with what should happen when an entry is deleted, you can replace the
* line from "return console.log.... "
*/
if(!change.after.val())
return console.log('A Notification has been deleted from the database : ', notification_id);
/*
* 'fromUser' query retreives the ID of the user who sent the notification
*/
const fromUser = admin.database().ref(`/notifications/$user_id/$notification_id`).once('value');
return fromUser.then(fromUserResult =>
const from_user_id = fromUserResult.val().from;
console.log('You have new notification from : ', from_user_id);
/*
* The we run two queries at a time using Firebase 'Promise'.
* One to get the name of the user who sent the notification
* another one to get the devicetoken to the device we want to send notification to
*/
const userQuery = admin.database().ref(`Users/$from_user_id/name`).once('value');
const deviceToken = admin.database().ref(`/Users/$user_id/device_token`).once('value');
return Promise.all([userQuery, deviceToken]).then(result =>
const userName = result[0].val();
const token_id = result[1].val();
/*
* We are creating a 'payload' to create a notification to be sent.
*/
const payload =
notification:
title : "New Friend Request",
body: `$userName has sent you a request`,
icon: "default",
click_action : "com.example.****.chattingapp_TARGET_NOTIFICATION"
,
data :
from_user_id : from_user_id
;
/*
* Then using admin.messaging() we are sending the payload notification to the token_id of
* the device we retreived.
*/
return admin.messaging().sendToDevice(token_id, payload).then(response =>
return console.log('This was the notification Feature');
);
);
);
);
我得到的错误
E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.****.chattingapp, PID: *****
java.lang.RuntimeException: Unable to start activity ComponentInfocom.example.****.chattingapp/com.example.****.chattingapp.ProfileActivity: java.lang.NullPointerException: Can't pass null for argument 'pathString' in child()
at com.example.****.chattingapp.ProfileActivity.onCreate(ProfileActivity.java:53)
数据库值
【问题讨论】:
写出了问题所在:“Can't pass null for argument 'pathString' in child()” 是的,我可以看到。但我没有任何空值 我认为问题是“FirebaseDatabase.getInstance().getReference().child("Users").child(user_id);"其中 USER_ID 为 NULL 但它在我的数据库中不为空 错误表示处理一个“child()”方法时会出现 NullPointerException。用动态字符串调用的最明显的 child() 是那一行……所以……为什么不在调试模式下启动应用程序并在 onCreate() 方法的开头设置断点?然后你会看到哪个是有问题的行。 【参考方案1】:您删除了错误的大部分重要行。 但是,您必须非常仔细地查看它,甚至对其进行解码。它的意思是:在调用“Firebase .....child()”方法时,“ProfileActivity.onCreate()”方法存在问题。您使用变量(而不是固定字符串)调用“child()”方法的行很少,因此其中之一(请检查错误日志并找到该“child()”警告的行)是真正的问题。
【讨论】:
【参考方案2】:所以我发现我需要
final String user_id;
String data = getIntent().getStringExtra("user_id");
if (data == null)
user_id = getIntent().getStringExtra("from_user_id");
else
user_id = getIntent().getStringExtra("user_id");
我没有检查我从意图中得到了什么字符串,因此出现了空异常。
【讨论】:
以上是关于尝试在后台/前台运行时应用程序崩溃但适用于其他手机的主要内容,如果未能解决你的问题,请参考以下文章
适用于 Android 的 Azure 通知中心:如何使用后台服务处理数据消息?
Android 应用在收到新的 FCM 消息时崩溃(前台和后台)
Flutter Firebase前台推送通知未显示但后台正在运行
手机和电脑的后台程序是否与前台程序同时运行 只是被前台覆盖了
在三星设备 (SM-J200F-sdk 22) 中调用 ACTION_VIEW (geo / map) 的意图时应用程序崩溃但适用于许多其他设备!任何解决方案?