I'm encountering issues with accessing deactivated widget ancestors when disposing of the controller.
import 'package:exposed/constants/colors.dart';
import 'package:exposed/providers/commentprovider.dart';
import 'package:exposed/providers/userverifyprovider.dart';
import 'package:exposed/view/postScreen/comments/customtextcard.dart';
import 'package:exposed/helpers/styles.dart';
import 'package:exposed/services/firebaseServices/firebaseservice.dart';
import 'package:flutter/material.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:provider/provider.dart';
import '../../../../components/mybutton.dart';
import '../../../../components/mytextfield.dart';
class CommentsStream extends StatefulWidget {
final String postId;
const CommentsStream({super.key, required this.postId});
@override
State<CommentsStream> createState() => _CommentsStreamState();
}
class _CommentsStreamState extends State<CommentsStream> {
late FocusNode _focusNode;
@override
void didChangeDependencies() {
super.didChangeDependencies();
_focusNode = FocusNode();
Provider.of<CommentProvider>(context, listen: false).init();
}
@override
void dispose() {
_focusNode.dispose();
Provider.of<CommentProvider>(context, listen: false).disposed();
super.dispose();
}
@override
Widget build(BuildContext context) {
final user = Provider.of<UserIdProvider>(context);
return Scaffold(
appBar: AppBar(
title: Styles.heading(user.userId),
),
backgroundColor: AppColors.bgColor,
body: FocusScope(
autofocus: true,
child: StreamBuilder<QuerySnapshot>(
/* a streams of unique post comments. which takes a string parameter.
Inside getcomments: 'where' clause is used.*/
stream: FirestoreService().getcomments(widget.postId),
builder:
(BuildContext context, AsyncSnapshot<QuerySnapshot> snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return const Center(
child: CircularProgressIndicator(),
);
}
if (snapshot.hasError) {
return Center(
child: Text('Error: ${snapshot.error}'),
);
}
return snapshot.data!.docs.isNotEmpty
? ListView.builder(
shrinkWrap: true,
itemCount: snapshot.data!.docs.length,
itemBuilder: (context, index) {
/* A custom card for comments. has functionality to Focus
TextFeild*/
return Comments(
focusNode: _focusNode,
commentId: snapshot.data!.docs[index].id,
postId: widget.postId,
userName: snapshot.data!.docs[index].get('userId'),
text: snapshot.data!.docs[index].get('comment'),
avatarUrl:
'https://cdn.pixabay.com/photo/2015/10/07/12/17/post-976115_960_720.png');
},
)
: Center(
child: Styles.whiteheading('Be the first to comment'),
);
},
),
),
bottomNavigationBar: SizedBox(
height: Styles.getScreenheight(context) * .2,
child: Column(
children: [
Consumer<CommentProvider>(
builder: (context, value, child) {
/*A custom text feild which takes multiple needed parameters.
has a functionality to send comment and reply */
return MyTextFeild(
focusNode: _focusNode,
prefixicon: value.txtbtnstring == 'reply' &&
value.commentcontroller.text.isNotEmpty
? IconButton(
onPressed: () {
/* String value for a button inside text feild
because we wanted to switch it with reply*/
value.settxtbtnstring('comment');
},
icon: const Icon(Icons.cancel_outlined))
: const Icon(Icons.comment),
controller: value.commentcontroller,
validator: 'validator',
suffixIcon: MyButton(
text: value.txtbtnstring == 'reply' &&
value.commentcontroller.text.isNotEmpty
? 'reply'
: 'comment',
ontap: () {
/* postId can be accessed through
snapshot.data.docs[index].id it is stored in commentidreturn
variable which is from our provider class name CommentProvider
*/
value.txtbtnstring == 'reply' &&
value.commentcontroller.text.isNotEmpty
? FirestoreService().replyComment(
widget.postId,
value.personId,
value.commentcontroller.text,
value.commentidreturn)
: FirestoreService().addComment(widget.postId,
value.personId, value.commentcontroller.text);
value.commentcontroller.clear();
}),
label: 'comment');
},
)
],
),
),
);
}
}
ProviderClass:
import 'package:flutter/material.dart';
class CommentProvider extends ChangeNotifier {
String? _txtbtnstring;
String? _commentidreturn;
String? _personId;
late TextEditingController _commentcontroller;
String get txtbtnstring => _txtbtnstring ?? 'comment';
String get commentidreturn => _commentidreturn ?? '';
String get personId => _personId ?? '';
TextEditingController get commentcontroller => _commentcontroller;
void settxtbtnstring(String txtbtnstring) {
_txtbtnstring = txtbtnstring;
notifyListeners();
}
void setcommentidreturn(String commentidreturn) {
_commentidreturn = commentidreturn;
notifyListeners();
}
void setpersonid(String personId) {
_personId = personId;
notifyListeners();
}
void setcommentcontroller(TextEditingController commentcontroller) {
_commentcontroller = commentcontroller;
notifyListeners();
}
void init() {
_commentcontroller = TextEditingController();
}
void disposed() {
_commentcontroller.dispose();
}
void setcontrollertext(String controllertext) {
_commentcontroller.text = controllertext;
}
}
Using Provider: I attempted to use Provider to manage the state of the TextEditingController and dispose of it properly when needed. However, I encountered difficulties accessing the TextEditingController instance from another widget where disposal is required. I experimented with various combinations of initState(), dispose(), didChangeDependencies(), and other lifecycle methods to try to initialize and dispose of the TextEditingController at the appropriate times. However, I still encountered the error "Looking up a deactivated widget's ancestor is unsafe.