【问题标题】:ListView refreshes only on scroll up and downListView 仅在上下滚动时刷新
【发布时间】:2021-08-21 13:49:53
【问题描述】:

我写了一个聊天应用程序,但问题是如果另一个用户写给我,消息不会立即加载。

仅当我向上然后向下滚动时。

如果我写了一条消息,它会立即更新。

我使用 Firebase 和 Nativescript。

TS:

import { DatePipe } from "@angular/common";
import { Component, ElementRef, Input, OnInit, ViewChild } from "@angular/core";
import { ActivatedRoute } from "@angular/router";
import { FormatListNumbered } from "@material-ui/icons";
import { RouterExtensions } from "@nativescript/angular";
import {  EventData, ListView, TextField } from "@nativescript/core";
import { ScrollView } from "@nativescript/core/ui/scroll-view"
import { connectableObservableDescriptor } from "rxjs/internal/observable/ConnectableObservable";
import { ChatService, DataChat } from "../shared/chat.service";
import { FormControl } from '@angular/forms';

import { UserService, DataUser } from "../shared/user.service";
import { firestore } from "@nativescript/firebase";
import { AsyncAction } from "rxjs/internal/scheduler/AsyncAction";
import { Screen } from "@nativescript/core"

@Component({
    selector: "ItemDetail",
    styleUrls: ['item-detail.component.css'],
    templateUrl: "./item-detail.component.html",
    providers: [DatePipe]
})
export class ItemDetailComponent implements OnInit {
messages: any[] = [];

constructor() { }

ngOnInit(): void {}

loadChat(){
      this._chatService.getChat(this.id).then((chat: any) => { 
            var chatData = chat.data()
           
            chatData["user"].forEach(user => {
                if(user != this.me){
                    this._userService.getUserObject(user).then((userObject:any) => {
                        this.user = userObject;
                    });
                }
            })
          
            try{
                chatData["messages"].forEach((msgs:any) => {
                    this.messages.push(msgs);
                }) 
                
            }catch{
                console.log("noch keine nachrichten verfasst");
            }

            this.unsubscribe = this._chatService.ChatCollection
            .doc(chat.id)
            .onSnapshot(doc => {
                try{
                    var lastElement = doc.data().messages[doc.data().messages.length-1];
                    lastElement.time = this.datePipe.transform(lastElement.time, 'h:mm a');
                    
                    if(this.messages[this.messages.length-1].msg == lastElement.msg){
                       
                    }else{
                        this.messages.push(lastElement);
                    }
                }catch{
                    console.log("noch keine nachrichten verfasst item-detail component")
                }
                
            }); 
            this.formatTime();
        })
    }
     sendMessage(){
        if(this.text == undefined){
            console.log("Sie haben keine Nachricht eingetippt");
        }else{
            this._chatService.addMessage(this.id, this.text, this.me);
            let counter = 0;
            setTimeout(() => {
                this.messages.forEach(elemt => {
                    counter ++;
                })
                this.listView.scrollToIndex(this.counter);
                this.clearText();
            }, 300)  
            setTimeout(() => {
                this.messages.forEach(elemt => {
                    counter ++;
                })
                this.listView.scrollToIndex(this.counter);
                this.clearText();
            }, 600)
        }
    }

因此,代码将添加到“messages: any[] = [];”中的每条新消息都附加了

HTML:

<ActionBar>
    <NavigationButton (tap)="onBackTap()" android.systemIcon="ic_menu_back"></NavigationButton>
    <Label [text]="user.name"></Label>
</ActionBar>

<ListView (loaded)="listViewLoaded($event)" class="chat-body" [items]="messages" separatorColor="transparent" style="height: 80%;margin-top: -200px" >
            <ng-template let-message="item" let-odd="odd" let-even="even">
                <GridLayout rows ="auto, *">
                    <Label style="padding-right:150px" *ngIf="message.sender == me" horizontalAlignment="right" class="chat-message-me" [text]="message.msg" textWrap="true"></Label>
                    <Label *ngIf="message.sender == me" horizontalAlignment="right" class="chat-timestamp" verticalAlignment="bottom" [text]="message.time"></Label>
                
                    <Label  style="padding-left:170px" *ngIf="message.sender != me" horizontalAlignment="left" class="chat-message-you" [text]="message.msg" textWrap="true"></Label>
                    <Label *ngIf="message.sender != me" horizontalAlignment="left" verticalAlignment="bottom" class="chat-timestamp" [text]="message.time"></Label>
                </GridLayout>
            </ng-template>
        
        </ListView>
    <StackLayout  class="nt-form chat-wrapper"  >
    <StackLayout loaded="test" id="chat-form" orientation="horizontal" class="nt-input input-field form">
  
   <TextField  
   #TextField
    (textChange)="onTextChange($event)" 
    [text]="inputText"
    width="800px"  
    class="-rounded-lg input" 
    hint="Nachricht" 
    style="background-color: #ffffff;"
></TextField>
        <button width="120px" class="-rounded-lg fa far fas fab" (tap)="sendMessage();" style="margin-left: 15px;" text="&#xf1d8;"></button>
    </StackLayout>
</StackLayout>

HTML 将其添加到视图中。这适用于我发送的每条消息:

但是如果其他人这样写的话:

(消息发送:“我是另一个人”)

但如果我上下滚动它就在那里。 如果我只向下滚动,则不会。

另外,如果我在从“其他人”发送消息后立即向下滚动,则会发生此错误:

System.err: An uncaught Exception occurred on "main" thread.
System.err: The content of the adapter has changed but ListView did not receive a notification. Make sure the content of your adapter is not modified from a background thread, but only from the UI thread. Make sure your adapter calls notifyDataSetChanged() when its content changes. [in ListView(4, class android.widget.ListView) with Adapter(class com.tns.gen.android.widget.BaseAdapter_vendor_126974_28_ListViewAdapter)]
System.err:
System.err: StackTrace:
System.err: java.lang.IllegalStateException: The content of the adapter has changed but ListView did not receive a notification. Make sure the content of 
your adapter is not modified from a background thread, but only from the UI thread. Make sure your adapter calls notifyDataSetChanged() when its content changes. [in ListView(4, class android.widget.ListView) with Adapter(class com.tns.gen.android.widget.BaseAdapter_vendor_126974_28_ListViewAdapter)]       
System.err:     at android.widget.ListView.layoutChildren(ListView.java:1717)
System.err:     at android.widget.AbsListView$CheckForTap.run(AbsListView.java:3490)
System.err:     at android.os.Handler.handleCallback(Handler.java:938)
System.err:     at android.os.Handler.dispatchMessage(Handler.java:99)
System.err:     at android.os.Looper.loop(Looper.java:223)
System.err:     at android.app.ActivityThread.main(ActivityThread.java:7656)
System.err:     at java.lang.reflect.Method.invoke(Native Method)
System.err:     at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592)
System.err:     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947)

据我了解,是UI刷新的问题。

ChatService 获取聊天:

getChat(RoomId){
        return new Promise((resolve, reject)=>{
            this.ChatCollection.doc(RoomId)
            .get()
            .then(msg => {
                resolve(msg);
            })
            .catch(err=>{
                console.log(err);
                reject(err);
            })
        })
    } 

【问题讨论】:

    标签: javascript firebase listview nativescript


    【解决方案1】:

    当值更改来自库时 UI 没有更新的问题是因为它在 Angular 的区域之外运行,这说明您必须滚动才能触发 UI 更新。

    对此的解决方法是在您调用更新数组时将ListView 封装在ngZone 内,以确保它在Angular 的区域内运行。

    import { NgZone } from '@angular/core';
    
    constructor(private ngZone: NgZone) {}
    
     this.unsubscribe = this._chatService.ChatCollection
                .doc(chat.id)
                .onSnapshot(doc => {
                    // NEW
                    this.ngZone.run(() => {
                      try{
                        var lastElement = doc.data().messages[doc.data().messages.length-1];
                        lastElement.time = this.datePipe.transform(lastElement.time, 'h:mm a');
                        
                        if(this.messages[this.messages.length-1].msg == lastElement.msg){
                           
                        }else{
                            this.messages.push(lastElement);
                        }
                      } catch{
                        console.log("noch keine nachrichten verfasst item-detail component")
                      }
                    });
                }); 
    
    

    【讨论】:

    • 谢谢。这就是答案。但是你怎么知道的。比如我怎样才能获得这些知识?我必须阅读完整的文档吗?因为我永远也猜不到。但再次感谢您
    • 经常遇到 Angular 在从第三方库更新后不更新 DOM 的问题 - 这很可能是区域问题 :)
    猜你喜欢
    • 1970-01-01
    • 2015-06-10
    • 2018-12-16
    • 1970-01-01
    • 2018-10-04
    • 1970-01-01
    • 1970-01-01
    • 2019-06-27
    相关资源
    最近更新 更多