问题
I'm working on an android application, that is a messaging application actually.
I'm using RecyclerView
to render content of a particular conversation.
What I'm stuck with is, I have a fragment that takes input from user to create a new conversation, I use that information to launch an activity for that conversation, to update its layout, adapter for the RecyclerView etc.
I dismiss the fragment when user input is valid(not empty etc.), send a test message in the conversation and use the conversation identifier to start the conversation activity.
But I'm getting this NullPointerException
that is related to the RecyclerView
, the heading of the stack trace is :
java.lang.NullPointerException: Attempt to invoke virtual method 'boolean android.support.v7.widget.RecyclerView$LayoutManager.onAddFocusables(android.support.v7.widget.RecyclerView, java.util.ArrayList, int, int)' on a null object reference
Above this, I also get one saying No adapter attached; skipping layout
.
I saw answers here on stackoverflow saying that, you should initiate an Adapter/LayoutManager
first and then attach it to the RecyclerView, but I'm already doing it.
I'm writing snippets of my code here.
Interface method that gets invoked when user input is valid.
public void onCreateConversation(DialogFragment dialog, String conversationName) {
dialog.dismiss();
Conversation newConversation = client.newConversation(Arrays.asList(userList);
String identifier = newConversation.getId().toString();
// prepare initiation message
String initialMessageText = "starting conversation";
MessagePart initialMessagePart = client.newMessagePart("text/initiation", initialMessageText.getBytes());
Message initialMessage = client.newMessage(Arrays.asList(initialMessagePart));
// send initiation message
newConversation.send(initialMessage);
startConversationActivity(identifier);
}
Start an activity for the conversation
public void startConversationActivity(String identifier) {
Intent intent = new Intent(this, ChatConversationActivity.class);
intent.putExtra("IDENTIFIER", identifier);
startActivity(intent);
}
The onCreate method of ChatConversationActivity
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.loading_conversation);
Intent intent = getIntent();
conversationIdentifier = intent.getStringExtra("IDENTIFIER");
// argument 'client' is reference to the connection
conversationViewControl = new ConversationViewController(this, client, conversationIdentifier);
}
In the constructor of ConversationViewController
public ConversationViewController(ChatConversationActivity activity, Client client, String identifier) {
activity.setContentView(R.layout.activity_conversation);
// messages recycler view
messageRecyclerView = (RecyclerView) activity.findViewById(R.id.messageRecyclerView);
// layout manager for recycler view
recyclerViewLayoutManager = new LinearLayoutManager(activity);
// message adapter
MessageAdapter = null;
// private conversation object in ConversationViewController
activeConversation = getConversation(identifier);
// this will render the layout for conversation
drawConversationView(activeConversation);
}
'getConversation' asks the service for conversation with an identifier
private Conversation getConversation(String identifier) {
if(activeConversation == null) {
Query query = Query.builder(Conversation.class)
.predicate(new Predicate(Conversation.Property.ID, Predicate.Operator.EQUAL_TO, identifier))
.build();
List<Conversation> results = client.executeQuery(query, Query.ResultType.OBJECTS);
if(results != null && results.size() > 0) {
// loading first object as identifiers are unique for all conversations
return results.get(0);
}
}
return activeConversation;
}
'drawConversationView' will update the view for conversation
private void drawConversation(Conversation conversation) {
// Only proceed if there is a valid conversation
if(conversation != null) {
Log.d("create conversation", "activeConversation is not null");
// recycler view layout manager
recyclerViewLayoutManager.setOrientation(LinearLayoutManager.VERTICAL);
messageRecyclerView.setLayoutManager(recyclerViewLayoutManager);
// messages for the conversation
List<Message> messages = client.getMessages(conversation);
// recycler view adapter, 'activity' is also private object
messageAdapter = new MessageAdapter(messages, activity);
messageRecyclerView.setAdapter(messageAdapter);
} else {
Log.d("create conversation", "activeConversation is still null");
}
}
This thing is crashing randomly
, sometimes the conversation gets created, I get to see the view of it, sometimes not.
I'm new in both Java and Android world, can you please help me track this?
回答1:
I can see two unreasonable things in your code.
Attach the LayoutManager as soon as you collect a reference to RecyclerView
You can try attaching the LayoutManager
to RecyclerView
, in the ConversationViewController
itself, before you make any attempt to collect your conversation data.
...
// messages recycler view
messageRecyclerView = (RecyclerView) mca.findViewById(R.id.messageRecyclerView);
// layout manager for recycler view
recyclerViewLayoutManager = new LinearLayoutManager(mca);
recyclerViewLayoutManager.setOrientation(LinearLayoutManager.VERTICAL);
// set this right here
messageRecyclerView.setLayoutManager(recyclerViewLayoutManager);
...
This would probably save you from crashing.
Implement callbacks to make sure you render only when you have the data
In the ConversationViewController
, you are calling getConversation
and drawConversation
methods one after another, but you are collecting some data in the first and using it in the second method.
You can try implementing an interface and use that to invoke the drawConversation
from the method getConversation
, once you have the conversation data, instead of calling them synchronously.
I hope this will help you here.
来源:https://stackoverflow.com/questions/31276294/why-my-android-activity-is-crashing-with-no-adapter-attached-skipping-layout