From ead86a689028acd25a03c8659e7496bf93143b9b Mon Sep 17 00:00:00 2001 From: hezhengyi Date: Wed, 23 Oct 2024 20:04:09 +0800 Subject: [PATCH 1/2] =?UTF-8?q?[testpicture]=E4=BF=AE=E6=94=B9=E5=A4=96?= =?UTF-8?q?=E6=8E=A5=E7=BA=B9=E7=90=86=E5=9B=BE=E7=89=87demo?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: hezhengyi --- .../resources/rawfile => assets/images}/1.png | Bin .../rawfile => assets/images}/2.jpeg | Bin .../rawfile => assets/images}/3.jpeg | Bin .../resources/rawfile => assets/images}/4.jpg | Bin .../resources/rawfile => assets/images}/6.jpg | Bin ohos/testpicture/lib/PicturePage.dart | 109 +++++++++---- ohos/testpicture/lib/main.dart | 45 +++++- ohos/testpicture/lib/pull_list_page.dart | 147 ++++++++++++++++++ .../main/ets/pictureplugin/PicturePlugin.ets | 8 +- ohos/testpicture/pubspec.yaml | 2 + 10 files changed, 274 insertions(+), 37 deletions(-) rename ohos/testpicture/{ohos/entry/src/main/resources/rawfile => assets/images}/1.png (100%) rename ohos/testpicture/{ohos/entry/src/main/resources/rawfile => assets/images}/2.jpeg (100%) rename ohos/testpicture/{ohos/entry/src/main/resources/rawfile => assets/images}/3.jpeg (100%) rename ohos/testpicture/{ohos/entry/src/main/resources/rawfile => assets/images}/4.jpg (100%) rename ohos/testpicture/{ohos/entry/src/main/resources/rawfile => assets/images}/6.jpg (100%) create mode 100644 ohos/testpicture/lib/pull_list_page.dart diff --git a/ohos/testpicture/ohos/entry/src/main/resources/rawfile/1.png b/ohos/testpicture/assets/images/1.png similarity index 100% rename from ohos/testpicture/ohos/entry/src/main/resources/rawfile/1.png rename to ohos/testpicture/assets/images/1.png diff --git a/ohos/testpicture/ohos/entry/src/main/resources/rawfile/2.jpeg b/ohos/testpicture/assets/images/2.jpeg similarity index 100% rename from ohos/testpicture/ohos/entry/src/main/resources/rawfile/2.jpeg rename to ohos/testpicture/assets/images/2.jpeg diff --git a/ohos/testpicture/ohos/entry/src/main/resources/rawfile/3.jpeg b/ohos/testpicture/assets/images/3.jpeg similarity index 100% rename from ohos/testpicture/ohos/entry/src/main/resources/rawfile/3.jpeg rename to ohos/testpicture/assets/images/3.jpeg diff --git a/ohos/testpicture/ohos/entry/src/main/resources/rawfile/4.jpg b/ohos/testpicture/assets/images/4.jpg similarity index 100% rename from ohos/testpicture/ohos/entry/src/main/resources/rawfile/4.jpg rename to ohos/testpicture/assets/images/4.jpg diff --git a/ohos/testpicture/ohos/entry/src/main/resources/rawfile/6.jpg b/ohos/testpicture/assets/images/6.jpg similarity index 100% rename from ohos/testpicture/ohos/entry/src/main/resources/rawfile/6.jpg rename to ohos/testpicture/assets/images/6.jpg diff --git a/ohos/testpicture/lib/PicturePage.dart b/ohos/testpicture/lib/PicturePage.dart index ff6bdd68..a1fc7e13 100644 --- a/ohos/testpicture/lib/PicturePage.dart +++ b/ohos/testpicture/lib/PicturePage.dart @@ -19,16 +19,19 @@ import 'package:flutter/services.dart'; class PicBean { String name; int id; + int index = 0; PicBean(this.name, this.id); -} -List pics = [ - PicBean("1.png", 0), - PicBean("2.jpeg", 0), - PicBean("3.jpeg", 0), - PicBean("4.jpg", 0), - PicBean("6.jpg", 0), -]; + setIndex(int index) { + this.index = index; + return this; + } + + @override + String toString() { + return "PicBean(name=$name, id=$id, index=$index)"; + } +} class PicturePage extends StatefulWidget { const PicturePage({super.key}); @@ -36,9 +39,20 @@ class PicturePage extends StatefulWidget { State createState() => _PicturePageState(); } -const MethodChannel _channel = MethodChannel('PictureChannel'); - class _PicturePageState extends State { + List pics = [ + PicBean("assets/images/1.png", 0), + PicBean("assets/images/2.jpeg", 0), + PicBean("assets/images/3.jpeg", 0), + PicBean("assets/images/4.jpg", 0), + PicBean("assets/images/6.jpg", 0), + PicBean("assets/images/1.png", 0), + PicBean("assets/images/2.jpeg", 0), + PicBean("assets/images/3.jpeg", 0), + PicBean("assets/images/4.jpg", 0), + PicBean("assets/images/6.jpg", 0), + ]; + @override Widget build(BuildContext context) { return Scaffold( @@ -46,24 +60,48 @@ class _PicturePageState extends State { title: const Text("daex_texture"), ), body: ListView.builder( - itemCount: pics.length, + itemCount: pics.length + 1, itemBuilder: (context, index) { + if (index == pics.length) { + return _buildBottom(context); + } PicBean picBean = pics[index]; return PictureWidget(bean: picBean); }, ), - floatingActionButton: FloatingActionButton( - onPressed: () { - Navigator.push(context, MaterialPageRoute( - builder: (BuildContext context) { - return const PicturePage(); - }, - )); - }, - child: const Icon(Icons.add), - ), ); } + + @override + void initState() { + debugPrint("_PicturePageState initState"); + super.initState(); + } + + @override + void dispose() { + debugPrint("_PicturePageState dispose"); + super.dispose(); + } +} + +_buildBottom(BuildContext context) { + return Center( + child: ElevatedButton( + onPressed: () { + _gotoNextPage(context); + }, + child: const Text("跳转"), + ), + ); +} + +_gotoNextPage(BuildContext context) { + Navigator.push(context, MaterialPageRoute( + builder: (BuildContext context) { + return const PicturePage(); + }, + )); } class PictureWidget extends StatefulWidget { @@ -82,24 +120,16 @@ class _PictureWidgetState extends State { @override void initState() { super.initState(); - registerTextures(); + registerTexture(bean.name).then((value) { + bean.id = value; + setState(() {}); + }); } @override void dispose() { + unregisterTexture(bean.id); super.dispose(); - unregisterTextures(); - } - - void registerTextures() async { - var id = await _channel.invokeMethod("registerTexture", {'pic': bean.name}); - setState(() { - bean.id = id; - }); - } - - void unregisterTextures() async { - await _channel.invokeMethod('unregisterTexture', {'textureId': bean.id}); } @override @@ -125,3 +155,14 @@ class _PictureWidgetState extends State { ); } } + +const MethodChannel _channel = MethodChannel('PictureChannel'); + +Future registerTexture(String picName) async { + int id = await _channel.invokeMethod("registerTexture", {'pic': picName}); + return id; +} + +Future unregisterTexture(int textureId) async { + await _channel.invokeMethod('unregisterTexture', {'textureId': textureId}); +} diff --git a/ohos/testpicture/lib/main.dart b/ohos/testpicture/lib/main.dart index 33779c2a..447376e7 100644 --- a/ohos/testpicture/lib/main.dart +++ b/ohos/testpicture/lib/main.dart @@ -14,6 +14,7 @@ */ import 'package:flutter/material.dart'; +import 'package:testpicture/pull_list_page.dart'; import 'PicturePage.dart'; @@ -41,8 +42,50 @@ class MyApp extends StatelessWidget { // is not restarted. primarySwatch: Colors.blue, ), - home: const PicturePage(), + home: const HomePage(), ); } } +class HomePage extends StatelessWidget { + const HomePage({super.key}); + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar(title: const Text("testpicture")), + body: Column( + children: [ + ElevatedButton( + onPressed: () { + _toPage1(context); + }, + child: const Text("跳转Page1"), + ), + ElevatedButton( + onPressed: () { + _toPage2(context); + }, + child: const Text("跳转Page2"), + ), + ], + ), + ); + } + + void _toPage1(BuildContext context) { + Navigator.push(context, MaterialPageRoute( + builder: (BuildContext context) { + return const PicturePage(); + }, + )); + } + + void _toPage2(BuildContext context) { + Navigator.push(context, MaterialPageRoute( + builder: (BuildContext context) { + return const PullListPage(title: '图片列表动态加载'); + }, + )); + } +} diff --git a/ohos/testpicture/lib/pull_list_page.dart b/ohos/testpicture/lib/pull_list_page.dart new file mode 100644 index 00000000..05adbe57 --- /dev/null +++ b/ohos/testpicture/lib/pull_list_page.dart @@ -0,0 +1,147 @@ +/* +* Copyright (c) 2023 Hunan OpenValley Digital Industry Development Co., Ltd. +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +import 'package:flutter/material.dart'; + +import 'PicturePage.dart'; + +class PullListPage extends StatefulWidget { + const PullListPage({super.key, required this.title}); + final String title; + + @override + _PullListPageState createState() => _PullListPageState(); +} + +class _PullListPageState extends State { + List list = []; //列表要展示的数据 + List picNams = [ + "assets/images/1.png", + "assets/images/2.jpeg", + "assets/images/3.jpeg", + "assets/images/4.jpg", + "assets/images/6.jpg", + ]; + final ScrollController _scrollController = ScrollController(); //listview的控制器 + bool isLoading = false; //是否正在加载数据 + + _createPicBean(int i) { + return PicBean(picNams[i % picNams.length], 0).setIndex(i); + } + + @override + void initState() { + super.initState(); + getData(); + _scrollController.addListener(() { + if (_scrollController.position.pixels == + _scrollController.position.maxScrollExtent) { + // 滑动到了最底部 + _getMore(); + } + }); + } + + /// 初始化list数据 加延时模仿网络请求 + Future getData() async { + await Future.delayed(const Duration(seconds: 2), () { + setState(() { + list = List.generate(15, (i) => _createPicBean(i)); + }); + }); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text(widget.title), + ), + body: RefreshIndicator( + onRefresh: _onRefresh, + child: ListView.builder( + itemBuilder: _renderRow, + itemCount: list.length + 1, + controller: _scrollController, + ), + ), + ); + } + + Widget _renderRow(BuildContext context, int index) { + if (index < list.length) { + return Column( + children: [ + Text(list[index].name), + PictureWidget(bean: list[index]), + ], + ); + } + return _getMoreWidget(); + } + + /// 下拉刷新方法,为list重新赋值 + Future _onRefresh() async { + await Future.delayed(const Duration(seconds: 3), () { + setState(() { + list = List.generate(20, (i) => _createPicBean(i)); + }); + }); + } + + /// 上拉加载更多 + Future _getMore() async { + if (!isLoading) { + setState(() { + isLoading = true; + }); + await Future.delayed(const Duration(seconds: 1), () { + setState(() { + list.addAll(List.generate(5, (i) => _createPicBean(i))); + isLoading = false; + }); + }); + } + } + + /// 加载更多时显示的组件,给用户提示 + Widget _getMoreWidget() { + return Center( + child: Padding( + padding: const EdgeInsets.all(10.0), + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: const [ + Text( + '加载中...', + style: TextStyle(fontSize: 16.0), + ), + CircularProgressIndicator( + strokeWidth: 1.0, + ) + ], + ), + ), + ); + } + + @override + void dispose() { + debugPrint("PullListPage, dispose"); + _scrollController.dispose(); + super.dispose(); + } +} diff --git a/ohos/testpicture/ohos/entry/src/main/ets/pictureplugin/PicturePlugin.ets b/ohos/testpicture/ohos/entry/src/main/ets/pictureplugin/PicturePlugin.ets index 47786d78..3cfc9d91 100644 --- a/ohos/testpicture/ohos/entry/src/main/ets/pictureplugin/PicturePlugin.ets +++ b/ohos/testpicture/ohos/entry/src/main/ets/pictureplugin/PicturePlugin.ets @@ -66,7 +66,8 @@ export class PicturePlugin implements FlutterPlugin, MethodCallHandler { } async registerPicturePixMap(pictureName: string) { - let fileData = await this.binding!.getApplicationContext().resourceManager.getRawFileContent(pictureName); + let fileData = await this.binding!.getApplicationContext().resourceManager + .getRawFileContent(`flutter_assets/${pictureName}`); let buffer : ArrayBuffer = fileData?.buffer as ArrayBuffer ?? new ArrayBuffer(0); let imageSource : image.ImageSource = image.createImageSource(buffer); let imageInfo = await imageSource.getImageInfo(); @@ -75,7 +76,7 @@ export class PicturePlugin implements FlutterPlugin, MethodCallHandler { Log.d(TAG, "getPixelBytesNumber " + pixelMap.getPixelBytesNumber()); let textureId = this.textureRegistry!.registerPixelMap(pixelMap); - Log.d(TAG, "textureId= " + textureId); + Log.d(TAG, "register textureId= " + textureId); this.pixelMapCache.set(textureId, pixelMap); return textureId; @@ -83,6 +84,9 @@ export class PicturePlugin implements FlutterPlugin, MethodCallHandler { unregisterPicturePixelMap(textureId: number): void { let pixelMap = this.pixelMapCache.remove(textureId); + if (pixelMap) { + Log.d(TAG, "unregister textureId= " + textureId); + } pixelMap?.release(); this.textureRegistry!.unregisterTexture(textureId); } diff --git a/ohos/testpicture/pubspec.yaml b/ohos/testpicture/pubspec.yaml index 0b8fe79d..38e00455 100644 --- a/ohos/testpicture/pubspec.yaml +++ b/ohos/testpicture/pubspec.yaml @@ -75,6 +75,8 @@ flutter: # assets: # - images/a_dot_burr.jpeg # - images/a_dot_ham.jpeg + assets: + - assets/images/ # An image asset can refer to one or more resolution-specific "variants", see # https://flutter.dev/assets-and-images/#resolution-aware -- Gitee From a832c985866210d5cb458d3d2e538317fa6dc3d3 Mon Sep 17 00:00:00 2001 From: hezhengyi Date: Thu, 24 Oct 2024 09:20:45 +0800 Subject: [PATCH 2/2] =?UTF-8?q?[testpicture]=E4=BF=AE=E6=94=B9=E5=A4=96?= =?UTF-8?q?=E6=8E=A5=E7=BA=B9=E7=90=86=E5=9B=BE=E7=89=87demo=E7=9A=84?= =?UTF-8?q?=E5=86=85=E5=AD=98=E6=B3=84=E9=9C=B2=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: hezhengyi --- ohos/testpicture/lib/PicturePage.dart | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/ohos/testpicture/lib/PicturePage.dart b/ohos/testpicture/lib/PicturePage.dart index a1fc7e13..aca5b8cb 100644 --- a/ohos/testpicture/lib/PicturePage.dart +++ b/ohos/testpicture/lib/PicturePage.dart @@ -114,6 +114,7 @@ class PictureWidget extends StatefulWidget { class _PictureWidgetState extends State { final PicBean bean; + bool isDisposed = false; _PictureWidgetState(this.bean); @@ -122,13 +123,25 @@ class _PictureWidgetState extends State { super.initState(); registerTexture(bean.name).then((value) { bean.id = value; - setState(() {}); + if (isDisposed) { + // 已执行了 dispose 方法 + // dispose 执行后再调用 setState 会报错 + // 此时需要执行 unregisterTexture ,避免内存泄露 + unregisterTexture(value); + } else { + setState(() {}); + } + }).catchError((e) { + debugPrint("registerTexture error: $e"); }); } @override void dispose() { - unregisterTexture(bean.id); + isDisposed = true; + unregisterTexture(bean.id).then((value) => {}).catchError((e) { + debugPrint("unregisterTexture error: $e"); + }); super.dispose(); } -- Gitee