使用MVVM和Firestore获取空对象引用

huangapple go评论86阅读模式
英文:

Getting null object reference using MVVM & Firestore

问题

I'm trying to use MVVM in my project for so many days. But unable to achieve it.

My code:

FeedRepository.java

public class FeedsRepository {

private static FeedsRepository instance;

private List<Feed> feedsToAppend = new ArrayList<>();


public static FeedsRepository getInstance() {
    if (instance == null) {
        instance = new FeedsRepository();
    }
    return instance;
}

public MutableLiveData<List<Feed>> getFeeds() {

    MutableLiveData<List<Feed>> mFeeds = new MutableLiveData<>();

    Query query;
    query = feedsRef.whereEqualTo("userID", currentUID).whereEqualTo("not_interested", false)
            .orderBy("created_at", Query.Direction.DESCENDING).limit(10);
    query.get().addOnCompleteListener(new OnCompleteListener<QuerySnapshot>() {
        @Override
        public void onComplete(@NonNull Task<QuerySnapshot> task) {
            if (task.isSuccessful()) {

                QuerySnapshot snapshot = task.getResult();

                if (snapshot.isEmpty()) {

                } else {

                    List<DocumentSnapshot> documents = snapshot.getDocuments();

                    for (DocumentSnapshot doc: documents) {
                        final Feed feed = doc.toObject(Feed.class);
                        feed.setFeedID(doc.getId());
                        feed.setFeedAvailable(true);

                        feedsToAppend.add(feed);
                        System.out.println("Feed: " + feed.getFeedID());
                    }

                    System.out.println("Total feeds to append: " + feedsToAppend.size());
                    mFeeds.setValue(feedsToAppend);

                }

            }
        }
    }).addOnFailureListener(new OnFailureListener() {
        @Override
        public void onFailure(@NonNull Exception e) {

        }
    });

    return mFeeds;

}

**HomeViewModel.java**

```java
public class HomeViewModel extends ViewModel {

    private MutableLiveData<List<Feed>> mFeeds;
    private FeedsRepository repo;

    public void init() {

        if (mFeeds != null) {
            return;
        }
        repo = FeedsRepository.getInstance();
        mFeeds = repo.getFeeds();
    }

    public LiveData<List<Feed>> getFeeds() {

        return mFeeds;

    }

}

HomeFragment.java

public View onCreateView(@NonNull LayoutInflater inflater,
                             ViewGroup container, Bundle savedInstanceState) {

    View view = inflater.inflate(R.layout.home_fragment, container, false);

    feedsRecycleView = view.findViewById(R.id.feeds_recycler_view);

    homeViewModel = ViewModelProviders.of(this).get(HomeViewModel.class);
    homeViewModel.init();

    homeViewModel.getFeeds().observe(getViewLifecycleOwner(), new Observer<List<Feed>>() {
        @Override
        public void onChanged(List<Feed> feeds) {
            System.out.println("Feed adapter feeds: "+feeds.size());
            mFeeds = feeds;
            feedAdapter.notifyDataSetChanged();
        }
    });

    List<Feed> testFeeds = homeViewModel.getFeeds().getValue();
    System.out.println("Test feeds are : " + testFeeds.size());

    feedAdapter = new FeedAdapter(getContext(), homeViewModel.getFeeds().getValue());
    feedsRecycleView.setAdapter(feedAdapter);

    feedsRecycleView.setHasFixedSize(true);
    LinearLayoutManager linearLayoutManager = new LinearLayoutManager(getContext());
    linearLayoutManager.setStackFromEnd(true); //newer posts will be shown on top
    linearLayoutManager.setReverseLayout(true);
    feedsRecycleView.setLayoutManager(linearLayoutManager);

    return view;

}

I get error

"Attempt to invoke interface method 'int java.util.List.size()' on a
null object reference"

on this line

List<Feed> testFeeds = homeViewModel.getFeeds().getValue();

and

feedAdapter = new FeedAdapter(getContext(), homeViewModel.getFeeds().getValue());

Please anyone tell me where am I making mistake.

英文:

I'm trying to use MVVM in my project for so many days. But unable to achieve it.

My code:

FeedRepository.java

public class FeedsRepository {
private static FeedsRepository instance;
private List&lt;Feed&gt; feedsToAppend = new ArrayList&lt;&gt;();
public static FeedsRepository getInstance() {
if (instance == null) {
instance = new FeedsRepository();
}
return instance;
}
public MutableLiveData&lt;List&lt;Feed&gt;&gt; getFeeds() {
MutableLiveData&lt;List&lt;Feed&gt;&gt; mFeeds = new MutableLiveData&lt;&gt;();
Query query;
query = feedsRef.whereEqualTo(&quot;userID&quot;, currentUID).whereEqualTo(&quot;not_interested&quot;, false)
.orderBy(&quot;created_at&quot;, Query.Direction.DESCENDING).limit(10);
query.get().addOnCompleteListener(new OnCompleteListener&lt;QuerySnapshot&gt;() {
@Override
public void onComplete(@NonNull Task&lt;QuerySnapshot&gt; task) {
if (task.isSuccessful()) {
QuerySnapshot snapshot = task.getResult();
if (snapshot.isEmpty()) {
} else {
List&lt;DocumentSnapshot&gt; documents = snapshot.getDocuments();
for (DocumentSnapshot doc: documents) {
final Feed feed = doc.toObject(Feed.class);
feed.setFeedID(doc.getId());
feed.setFeedAvailable(true);
feedsToAppend.add(feed);
System.out.println(&quot;Feed: &quot; + feed.getFeedID());
}
System.out.println(&quot;Total feeds to append: &quot; + feedsToAppend.size());
mFeeds.setValue(feedsToAppend);
}
}
}
}).addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(@NonNull Exception e) {
}
});
return mFeeds;
}

HomeViewModel.java

public class HomeViewModel extends ViewModel {
private MutableLiveData&lt;List&lt;Feed&gt;&gt; mFeeds;
private FeedsRepository repo;
public void init() {
if (mFeeds != null) {
return;
}
repo = FeedsRepository.getInstance();
mFeeds = repo.getFeeds();
}
public LiveData&lt;List&lt;Feed&gt;&gt; getFeeds() {
return mFeeds;
}
}

HomeFragment.java

    public View onCreateView(@NonNull LayoutInflater inflater,
ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.home_fragment, container, false);
feedsRecycleView = view.findViewById(R.id.feeds_recycler_view);
homeViewModel = ViewModelProviders.of(this).get(HomeViewModel.class);
homeViewModel.init();
homeViewModel.getFeeds().observe(getViewLifecycleOwner(), new Observer&lt;List&lt;Feed&gt;&gt;() {
@Override
public void onChanged(List&lt;Feed&gt; feeds) {
System.out.println(&quot;Feed adapter feeds: &quot;+feeds.size());
mFeeds = feeds;
feedAdapter.notifyDataSetChanged();
}
});
List&lt;Feed&gt; testFeeds = homeViewModel.getFeeds().getValue();
System.out.println(&quot;Test feeds are : &quot; + testFeeds.size());
feedAdapter = new FeedAdapter(getContext(), homeViewModel.getFeeds().getValue());
feedsRecycleView.setAdapter(feedAdapter);
feedsRecycleView.setHasFixedSize(true);
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(getContext());
linearLayoutManager.setStackFromEnd(true); //newer posts will be shown on top
linearLayoutManager.setReverseLayout(true);
feedsRecycleView.setLayoutManager(linearLayoutManager);
return view;
}

I get error

> "Attempt to invoke interface method 'int java.util.List.size()' on a
> null object reference"

on this line

List&lt;Feed&gt; testFeeds = homeViewModel.getFeeds().getValue();

and

feedAdapter = new FeedAdapter(getContext(), homeViewModel.getFeeds().getValue());

Please anyone tell me where am I making mistake.

答案1

得分: 1

以下是翻译好的内容:

你遇到了以下错误:

> “尝试在空对象引用上调用接口方法'int java.util.List.size()'

很可能是在以下这行代码出现的问题:

System.out.println("Test feeds are : " + testFeeds.size());

这是因为你的 testFeeds 对象是 null,这意味着:

homeViewModel.getFeeds().getValue();

返回了 null。这也意味着 getValue() 方法返回了一个空的 LiveData 对象,而事实上在你的 HomeViewModel 类中,getFeeds() 方法返回了一个从未初始化的 LiveData 对象。要解决这个问题,请更改以下代码行:

private MutableLiveData<List> mFeeds

private MutableLiveData<List> mFeeds = new MutableLiveData<>();

英文:

You are getting the following error:

> "Attempt to invoke interface method 'int java.util.List.size()' on a null object reference"

Most likely at this particular line of code:

System.out.println(&quot;Test feeds are : &quot; + testFeeds.size());

And this is because your testFeeds object is null, meaning that:

homeViewModel.getFeeds().getValue();

Return null. This also means that getValue() method returns a LiveData object that is null, which is indeed the case as in your HomeViewModel class the getFeeds() method returns a LiveData object which is never initialized. To solve this, please change the following line of code:

private MutableLiveData&lt;List&lt;Feed&gt;&gt; mFeeds

to

private MutableLiveData&lt;List&lt;Feed&gt;&gt; mFeeds = new MutableLiveData&lt;&gt;();

答案2

得分: 0

我已经弄清楚了。

我不得不在FeedsRepository中添加这一行,

public MutableLiveData<ArrayList<Feed>> getFeeds() {
MutableLiveData<ArrayList<Feed>> mFeeds = new MutableLiveData<>();
mFeeds.setValue(feedsToAppend);

然后在从后端获取记录之后再次执行

mFeeds.setValue(feedsToAppend);

由于后端处理是异步的,并且需要时间来获取,它可能会返回空对象。

英文:

Okay. I have figured it out.

I had to add this line in FeedsRepository,

 public MutableLiveData&lt;ArrayList&lt;Feed&gt;&gt; getFeeds() {
MutableLiveData&lt;ArrayList&lt;Feed&gt;&gt; mFeeds = new MutableLiveData&lt;&gt;();
mFeeds.setValue(feedsToAppend);
......

and after fetching records from backend, again

mFeeds.setValue(feedsToAppend);

As the backend process is asynchronous, and would take time to fetch
it would return with null object.

huangapple
  • 本文由 发表于 2020年8月11日 18:41:11
  • 转载请务必保留本文链接:https://go.coder-hub.com/63356483.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定