Rxjs 如果用户多次重新打开其应用程序,则NativeScript应用程序中可能存在内存泄漏

Rxjs 如果用户多次重新打开其应用程序,则NativeScript应用程序中可能存在内存泄漏,rxjs,nativescript,nativescript-angular,nativescript-firebase,Rxjs,Nativescript,Nativescript Angular,Nativescript Firebase,我不确定bug在哪里,也许我用错了rxjs。如果您想关闭并返回应用程序,ngDestroy无法取消订阅NativeScript中的观测值。我试着与takeUntil合作,但结果相同。如果用户多次关闭/打开应用程序,可能会导致内存泄漏(如果我正确理解移动环境)。有什么想法吗?下面的代码只是一个演示。我需要在我的应用程序的许多地方使用用户$ 通过Android sdk模拟器和真实设备进行测试 应用组件 import { Component, OnDestroy, OnInit } from '@an

我不确定bug在哪里,也许我用错了rxjs。如果您想关闭并返回应用程序,ngDestroy无法取消订阅NativeScript中的观测值。我试着与takeUntil合作,但结果相同。如果用户多次关闭/打开应用程序,可能会导致内存泄漏(如果我正确理解移动环境)。有什么想法吗?下面的代码只是一个演示。我需要在我的应用程序的许多地方使用用户$

通过Android sdk模拟器和真实设备进行测试

应用组件

import { Component, OnDestroy, OnInit } from '@angular/core';
import { Subscription, Observable } from 'rxjs';
import { AppService } from './app.service';

import { AuthenticationService } from './authentication.service';
@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.scss'],
})
export class AppComponent implements OnDestroy, OnInit {
  public user$: Observable<any>;

  private subscriptions: Subscription[] = [];

  constructor(private appService: AppService, private authenticationService: AuthenticationService) {}

  public ngOnInit(): void {
    this.user$ = this.authenticationService.user$;

    this.subscriptions.push(
      this.authenticationService.user$.subscribe((user: any) => {
        console.log('user', !!user);
      })
    );
  }

  public ngOnDestroy(): void {
    if (this.subscriptions) {
      this.subscriptions.forEach((subscription: Subscription) => subscription.unsubscribe());
    }
  }

  async signIn() {
    await this.appService.signIn();
  }

  async signOut() {
    await this.appService.signOut();
  }
}
从'@angular/core'导入{Component,OnDestroy,OnInit};
从“rxjs”导入{Subscription,Observable};
从“/app.service”导入{AppService};
从“/authentication.service”导入{AuthenticationService};
@组成部分({
选择器:'应用程序根',
templateUrl:“./app.component.html”,
样式URL:['./app.component.scss'],
})
导出类AppComponent实现OnDestroy、OnInit{
公共用户$:可观察;
私人订阅:订阅[]=[];
构造函数(私有appService:appService,私有authenticationService:authenticationService){}
public ngOnInit():void{
this.user$=this.authenticationService.user$;
这个是.subscriptions.push(
this.authenticationService.user$.subscribe((用户:任意)=>{
console.log('user',!!user);
})
);
}
公共Ngondestory():void{
if(this.subscriptions){
this.subscriptions.forEach((subscription:subscription)=>subscription.unsubscripte());
}
}
异步登录(){
等待这个.appService.sign();
}
异步签出(){
等待这个.appService.signOut();
}
}
认证服务

import { Injectable } from '@angular/core';
import { Observable } from 'rxjs';
import { shareReplay } from 'rxjs/operators';
import { AppService } from './app.service';

@Injectable({
  providedIn: 'root',
})
export class AuthenticationService {
  public user$: Observable<any>;

  constructor(private appService: AppService) {
    this.user$ = this.appService.authState().pipe(shareReplay(1)); // I'm using this.users$ in many places in my app, so I need to use sharereplay
  }
}
从'@angular/core'导入{Injectable};
从“rxjs”导入{Observable};
从“rxjs/operators”导入{shareReplay};
从“/app.service”导入{AppService};
@注射的({
providedIn:'根',
})
导出类身份验证服务{
公共用户$:可观察;
构造函数(专用appService:appService){
this.user$=this.appService.authState().pipe(shareReplay(1));//我在我的应用程序的许多地方都使用了这个.users$,所以我需要使用shareReplay
}
}
应用服务

import { Injectable, NgZone } from '@angular/core';
import { addAuthStateListener, login, LoginType, logout, User } from 'nativescript-plugin-firebase';
import { BehaviorSubject, Observable } from 'rxjs';
import { distinctUntilChanged } from 'rxjs/operators';

const user$ = new BehaviorSubject<User>(null);

@Injectable({
  providedIn: 'root',
})
export class AppService {
  constructor(private ngZone: NgZone) {
    addAuthStateListener({
      onAuthStateChanged: ({ user }) => {
        this.ngZone.run(() => {
          user$.next(user);
        });
      },
    });
  }

  public authState(): Observable<User> {
    return user$.asObservable().pipe(distinctUntilChanged());
  }

  async signIn() {
    return await login({ type: LoginType.PASSWORD, passwordOptions: { email: 'xxx', password: 'xxx' } }).catch(
      (error: string) => {
        throw {
          message: error,
        };
      }
    );
  }

  signOut() {
    logout();
  }
}
从'@angular/core'导入{Injectable,NgZone};
从“nativescript plugin firebase”导入{addAuthStateListener,login,LoginType,logout,User};
从“rxjs”导入{BehaviorSubject,Observable};
从'rxjs/operators'导入{distinctUntilChanged};
const user$=new BehaviorSubject(null);
@注射的({
providedIn:'根',
})
导出类应用程序服务{
建造商(专用ngZone:ngZone){
addAuthStateListener({
onAuthStateChanged:({user})=>{
此.ngZone.run(()=>{
用户$.next(用户);
});
},
});
}
公共authState():可观察{
返回用户$.asObservable().pipe(distinctUntilChanged());
}
异步登录(){
返回等待登录({type:LoginType.PASSWORD,passwordOptions:{email:'xxx',PASSWORD:'xxx'})。捕获(
(错误:字符串)=>{
扔{
信息:错误,
};
}
);
}
签出(){
注销();
}
}

ngondestory
在组件销毁时调用(遵循常规的角度工作流)。如果您已经在应用程序中向前导航,以前的视图将仍然存在,并且不太可能被破坏

如果您看到多个
ngOnInit
而没有任何
ngondestory
,那么您已经通过一些导航实例化了多个组件,与您的订阅无关。在调用
ngondestory
后,您不应该期望组件的同一实例被重用,因此将
推送到
订阅[]
数组将只有一个对象

如果要终止应用程序(即强制退出刷走),则会抛出整个JavaScript上下文并清理内存。你不会冒泄露到应用程序上下文之外的风险

顺便说一句,您正在使订阅跟踪变得复杂(而不仅仅是我在上面描述的只推一次订阅的方式)。
订阅
是可以同时附加其他
订阅
对象以终止的对象

const订阅:订阅=新订阅();
subscription.add(间隔(100).subscripte((n:number)=>console.log(`firstsub`));
subscription.add(interval(200).subscripte((n:number)=>console.log(`secondsub`));
subscription.add(interval(300).subscripte((n:number)=>console.log(`third sub`));
计时器(5000).subscribe(()=>subscription.unsubscribe());//终止所有添加的订阅
请注意直接在
中添加subscribe调用。add
中不要使用闭包。令人烦恼的是,这与您要向订阅添加完成块时要执行的函数调用完全相同,而是传递一个块:

subscription.add(()=>console.log(`Everyone's done.`));

好吧,我不是说终止整个应用程序,而是说将该应用程序移动到我的移动设备的后台。注销后,用户订阅发出的次数与我将应用程序移动到后台和之前的次数相同。因此,如果我将应用程序移动到后台并打开该应用程序5次,那么如果我注销我的用户,则此.authenticationService.user$(点击或订阅)emits 5 console.logs:/我想rxjs可能有问题,但找不到问题:/我在您发布的代码中没有看到任何可能导致此问题的内容。如果您可以发布一个,我可能可以了解您看到的内容。我尝试过,但play.nativescript.com不允许我安装nativescript插件firebase插件(“操场上不支持具有本机依赖项的插件。”)。我试图在没有firebase的工具中模拟简单的应用程序,但我无法模仿本地行为(例如,ngOnInit被称为仅firs