我是RecyclerView的新手,所以如果分辨率非常简单,请原谅我。我四处寻找但没有运气,所以我需要指导。 使用FirestoreUI将聊天功能与Firestore相匹配,从https://github.com/firebase/FirebaseUI-Android获取代码。
这是主要代码:
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;
import com.firebase.ui.auth.util.ui.ImeHelper;
import com.firebase.ui.firestore.FirestoreRecyclerAdapter;
import com.firebase.ui.firestore.FirestoreRecyclerOptions;
import com.google.android.gms.tasks.OnFailureListener;
import com.google.firebase.auth.FirebaseAuth;
import com.google.firebase.firestore.CollectionReference;
import com.google.firebase.firestore.FirebaseFirestore;
import com.google.firebase.firestore.Query;
import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.OnClick;
/**
* Class demonstrating how to setup a {@link RecyclerView} with an adapter while taking sign-in
* states into consideration. Also demonstrates adding data to a ref and then reading it back using
* the {@link FirestoreRecyclerAdapter} to build a simple chat app.
* <p>
* For a general intro to the RecyclerView, see <a href="https://developer.android.com/training/material/lists-cards.html">Creating
* Lists</a>.
*/
public class BlaBlaBlaChat extends AppCompatActivity
implements FirebaseAuth.AuthStateListener {
private static final String TAG = "BlaBlaBlaChat";
private static final CollectionReference sChatCollection =
FirebaseFirestore.getInstance().collection("chats");
/** Get the last 50 chat messages ordered by timestamp . */
private static final Query sChatQuery = sChatCollection.orderBy("timestamp").limit(50);
static {
FirebaseFirestore.setLoggingEnabled(true);
}
@BindView(R.id.messagesList)
RecyclerView mRecyclerView;
@BindView(R.id.sendButton)
Button mSendButton;
@BindView(R.id.messageEdit)
EditText mMessageEdit;
@BindView(R.id.emptyTextView)
TextView mEmptyListMessage;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.ireland_chat);
ButterKnife.bind(this);
mRecyclerView.setHasFixedSize(true);
mRecyclerView.setLayoutManager(new LinearLayoutManager(this));
ImeHelper.setImeOnDoneListener(mMessageEdit, new ImeHelper.DonePressedListener() {
@Override
public void onDonePressed() {
onSendClick();
}
});
}
@Override
public void onStart() {
super.onStart();
if (isSignedIn()) { attachRecyclerViewAdapter(); }
FirebaseAuth.getInstance().addAuthStateListener(this);
}
@Override
protected void onStop() {
super.onStop();
FirebaseAuth.getInstance().removeAuthStateListener(this);
}
@Override
public void onAuthStateChanged(@NonNull FirebaseAuth auth) {
mSendButton.setEnabled(isSignedIn());
mMessageEdit.setEnabled(isSignedIn());
if (isSignedIn()) {
attachRecyclerViewAdapter();
} else {
Toast.makeText(this, R.string.signing_in, Toast.LENGTH_SHORT).show();
auth.signInAnonymously().addOnCompleteListener(new BlaBlaBlaChatSignInHolder(this));
}
}
private boolean isSignedIn() {
return FirebaseAuth.getInstance().getCurrentUser() != null;
}
private void attachRecyclerViewAdapter() {
final RecyclerView.Adapter adapter = newAdapter();
// Scroll to bottom on new messages
adapter.registerAdapterDataObserver(new RecyclerView.AdapterDataObserver() {
@Override
public void onItemRangeInserted(int positionStart, int itemCount) {
mRecyclerView.smoothScrollToPosition(adapter.getItemCount());
}
});
mRecyclerView.setAdapter(adapter);
}
@OnClick(R.id.sendButton)
public void onSendClick() {
String uid = FirebaseAuth.getInstance().getCurrentUser().getUid();
String name = "User " + uid.substring(0, 6);
onAddMessage(new BlaBlaBlaChatAbstractExtend(name, mMessageEdit.getText().toString(), uid));
mMessageEdit.setText("");
}
protected RecyclerView.Adapter newAdapter() {
FirestoreRecyclerOptions<BlaBlaBlaChatAbstractExtend> options =
new FirestoreRecyclerOptions.Builder<BlaBlaBlaChatAbstractExtend>()
.setQuery(sChatQuery, BlaBlaBlaChatAbstractExtend.class)
.setLifecycleOwner(this)
.build();
return new FirestoreRecyclerAdapter<BlaBlaBlaChatAbstractExtend, BlaBlaBlaChatHolder>(options) {
@Override
public BlaBlaBlaChatHolder onCreateViewHolder(ViewGroup parent, int viewType) {
return new BlaBlaBlaChatHolder(LayoutInflater.from(parent.getContext())
.inflate(R.layout.message, parent, false));
}
@Override
protected void onBindViewHolder(@NonNull BlaBlaBlaChatHolder holder, int position, @NonNull BlaBlaBlaChatAbstractExtend model) {
holder.bind(model);
}
@Override
public void onDataChanged() {
// If there are no chat messages, show a view that invites the user to add a message.
mEmptyListMessage.setVisibility(getItemCount() == 0 ? View.VISIBLE : View.GONE);
}
};
}
protected void onAddMessage(BlaBlaBlaChatAbstractExtend chat) {
sChatCollection.add(chat).addOnFailureListener(this, new OnFailureListener() {
@Override
public void onFailure(@NonNull Exception e) {
Log.e(TAG, "Failed to write message", e);
}
});
}
这是xml:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.example.balblabla.BlaBlaBlaChat">
<TextView
android:id="@+id/emptyTextView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="16dp"
android:text="@string/start_chatting" />
<android.support.v7.widget.RecyclerView
android:id="@+id/messagesList"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_alignParentStart="true"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:layout_above="@+id/footer"
android:clipToPadding="false"
android:padding="16dp"
tools:listitem="@layout/ireland_chat_message" />
<LinearLayout
android:id="@+id/footer"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentStart="true"
android:layout_alignParentLeft="true"
android:layout_alignParentBottom="true"
android:paddingStart="16dp"
android:paddingEnd="16dp"
android:paddingLeft="16dp"
android:orientation="horizontal">
<EditText
android:id="@+id/messageEdit"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:imeOptions="actionDone"
android:inputType="text" />
<Button
android:id="@+id/sendButton"
style="@style/Widget.AppCompat.Button.Borderless.Colored"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|end"
android:text="@string/send" />
</LinearLayout>
</RelativeLayout>
来自logcat:
01-12 18:07:36.443 31599-31599/com.example.carlo.blablabla E/UncaughtException: java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.carlo.blablabla/com.example.carlo.blablabla.BlaBlaBlaChat}: java.lang.NullPointerException: Attempt to invoke virtual method 'void android.support.v7.widget.RecyclerView.setHasFixedSize(boolean)' on a null object reference
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2724)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2789)
at android.app.ActivityThread.-wrap12(ActivityThread.java)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1527)
at android.os.Handler.dispatchMessage(Handler.java:110)
at android.os.Looper.loop(Looper.java:203)
at android.app.ActivityThread.main(ActivityThread.java:6251)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1063)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:924)
Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'void android.support.v7.widget.RecyclerView.setHasFixedSize(boolean)' on a null object reference
at com.example.carlo.blablabla.BlaBlaBlaChat.onCreate(BlaBlaBlaChat.java:73)
at android.app.Activity.performCreate(Activity.java:6681)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1118)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2677)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2789)
at android.app.ActivityThread.-wrap12(ActivityThread.java)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1527)
at android.os.Handler.dispatchMessage(Handler.java:110)
at android.os.Looper.loop(Looper.java:203)
at android.app.ActivityThread.main(ActivityThread.java:6251)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1063)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:924)
01-12 18:07:36.715 31599-31599/com.example.carlo.blablabla E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.carlo.blablabla, PID: 31599
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.carlo.blablabla/com.example.carlo.blablabla.BlaBlaBlaChat}: java.lang.NullPointerException: Attempt to invoke virtual method 'void android.support.v7.widget.RecyclerView.setHasFixedSize(boolean)' on a null object reference
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2724)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2789)
at android.app.ActivityThread.-wrap12(ActivityThread.java)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1527)
at android.os.Handler.dispatchMessage(Handler.java:110)
at android.os.Looper.loop(Looper.java:203)
at android.app.ActivityThread.main(ActivityThread.java:6251)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1063)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:924)
Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'void android.support.v7.widget.RecyclerView.setHasFixedSize(boolean)' on a null object reference
at com.example.carlo.blablabla.BlaBlaBlaChat.onCreate(BlaBlaBlaChat.java:73)
at android.app.Activity.performCreate(Activity.java:6681)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1118)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2677)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2789)
at android.app.ActivityThread.-wrap12(ActivityThread.java)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1527)
at android.os.Handler.dispatchMessage(Handler.java:110)
at android.os.Looper.loop(Looper.java:203)
at android.app.ActivityThread.main(ActivityThread.java:6251)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1063)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:924)
Gradle项目
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
repositories {
jcenter()
google()
}
dependencies {
classpath 'com.android.tools.build:gradle:3.0.1'
classpath 'com.google.gms:google-services:3.1.0'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}
allprojects {
repositories {
jcenter()
google()
maven {
url "https://maven.google.com" // Google's Maven repository
}
}
}
task clean(type: Delete) {
delete rootProject.buildDir
}
Gradle APP:
apply plugin: 'com.android.application'
android {
compileSdkVersion 27
buildToolsVersion '26.0.2'
defaultConfig {
applicationId "com.example.blablabla.albalbalb"
minSdkVersion 19
targetSdkVersion 27
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
exclude group: 'com.android.support', module: 'support-annotations'
})
compile 'com.android.support:appcompat-v7:27.0.2'
compile 'com.android.support.constraint:constraint-layout:1.0.2'
testCompile 'junit:junit:4.12'
compile 'com.google.android.gms:play-services-location:11.8.0'
compile 'com.google.android.gms:play-services-maps:11.8.0'
compile 'com.google.firebase:firebase-core:11.8.0'
compile 'com.google.firebase:firebase-auth:11.8.0'
compile 'com.google.firebase:firebase-firestore:11.8.0'
compile 'com.google.firebase:firebase-storage:11.8.0'
implementation 'com.android.support:cardview-v7:27.0.2'
implementation 'com.android.support:recyclerview-v7:27.0.2'
compile 'de.hdodenhof:circleimageview:1.3.0'
compile 'com.google.android.gms:play-services-appinvite:11.8.0'
compile 'com.google.firebase:firebase-messaging:11.8.0'
compile 'com.google.android.gms:play-services-ads:11.8.0'
compile 'com.google.firebase:firebase-appindexing:11.8.0'
compile 'com.google.firebase:firebase-crash:11.8.0'
compile 'com.google.firebase:firebase-analytics:11.8.0'
compile 'com.android.support:design:27.0.2'
compile 'com.github.bumptech.glide:glide:4.3.1'
compile 'com.google.firebase:firebase-database:11.8.0'
compile 'com.google.firebase:firebase-config:11.8.0'
compile 'com.firebaseui:firebase-ui-database:3.1.3'
compile 'com.firebaseui:firebase-ui-auth:3.1.3'
implementation 'com.firebaseui:firebase-ui-firestore:3.1.3'
implementation 'com.firebaseui:firebase-ui-storage:3.1.3'
compile 'com.google.android.gms:play-services-auth:11.8.0'
implementation 'com.jakewharton:butterknife:8.8.1'
// Testing dependencies
androidTestCompile 'com.android.support.test:runner:1.0.1'
androidTestCompile 'com.android.support:support-annotations:27.0.2'
}
apply plugin: 'com.google.gms.google-services'
代码只是来自Github代码的剪切/粘贴,但出了点问题。
答案 0 :(得分:1)
看起来您没有正确地将ButterKnife库添加到项目中。
在您应用的build.gradle文件中,您必须在implementation "com.jakewharton:butterknife:8.8.1"
之后添加annotationProcessor,如下所示:
annotationProcessor "com.jakewharton:butterknife-compiler:8.8.1"
在你的项目的build.gradle文件中,将ButterKnife插件添加到你的buildscript中:
dependencies {
classpath 'com.android.tools.build:gradle:3.0.1'
classpath 'com.google.gms:google-services:3.1.0'
classpath 'com.jakewharton:butterknife-gradle-plugin:8.8.1'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
答案 1 :(得分:0)
您正在使用永远不会初始化的mRecyclerView
,这就是您收到该错误的原因。为了解决这个问题,您必须先使用它进行初始化。假设您RecyclerView
的ID为recycler_view
,请在onCreate()
方法中使用以下代码:
RecyclerView mRecyclerView = (RecyclerView) findViewById(R.id.recycler_view);