Why my android activity is crashing with “No adapter attached; skipping layout” but sporadically?

六月ゝ 毕业季﹏ 提交于 2020-01-25 06:23:51

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!