我的编程空间,编程开发者的网络收藏夹
学习永远不晚

Flutter Boost 混合开发框架

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

Flutter Boost 混合开发框架

一、Flutter Boost简介

众所周知,Flutter是一个由C++实现的Flutter Engine和由Dart实现的Framework组成的跨平台技术框架。其中,Flutter Engine负责线程管理、Dart VM状态管理以及Dart代码加载等工作,而Dart代码所实现的Framework则负责上层业务开发,如Flutter提供的组件等概念就是Framework的范畴。

随着Flutter的发展,国内越来越多的App开始接入Flutter。为了降低风险,大部分App采用渐进式方式引入Flutter,在App里选几个页面用Flutter来编写,但都碰到了相同的问题,在原生页面和Flutter页面共存的情况下,如何管理路由,以及原生页面与Flutter页面之间的切换和通信都是混合开发中需要解决的问题。然而,官方没有提供明确的解决方案,只是在混合开发时,官方建议开发者,应该使用同一个引擎支持多窗口绘制的能力,至少在逻辑上做到FlutterViewController是共享同一个引擎里面的资源。换句话说,官方希望所有的绘制窗口共享同一个主Isolate,而不是出现多个主Isolate的情况。不过,对于现在已经出现的多引擎模式问题,Flutter官方也没有提供好的解决方案。除了内存消耗严重外,多引擎模式还会带来如下一些问题

  • 冗余资源问题。多引擎模式下每个引擎的Isolate是相互独立的,虽然在逻辑上这并没有什么坏处,但是每个引擎底层都维护了一套图片缓存等比较消耗内存的对象,因此设备的内存消耗是非常严重的。
  • 插件注册问题。在Flutter插件中,消息传递需要依赖Messenger,而Messenger是由FlutterViewController去实现的。如果一个应用中同时存在多个FlutterViewController,那么插件的注册和通信将会变得混乱且难以维护。
  • Flutter组件和原生页面的差异化问题。通常,Flutter页面是由组件构成的,原生页面则是由ViewController或者Activity构成的。逻辑上来说,我们希望消除Flutter页面与原生页面的差异,否则在进行页面埋点和其它一些操作时增加一些额外的工作量。
  • 增加页面通信的复杂度。如果所有的Dart代码都运行在同一个引擎实例中,那么它们会共享同一个Isolate,可以用统一的框架完成组件之间的通信,但是如果存在多个引擎实例会让Isolate的管理变得更加复杂。

如果不解决多引擎问题,那么混合项目的导航栈如下图所示。

目前,对于原生工程混编Flutter工程出现的多引擎模式问题,国内主要有两种解决方案,一种是字节跳动的修改Flutter Engine源码方案,另一种是闲鱼开源的FlutterBoost。由于字节跳动的混合开发的方案没有开源,所以现在能使用的就剩下FlutterBoost方案。

FlutterBoost是闲鱼技术团队开发的一个可复用页面的插件,旨在把Flutter容器做成类似于浏览器的加载方案。为此,闲鱼技术团队为希望FlutterBoost能完成如下的基本功能:

  • 可复用的通用型混合开发方案。
  • 支持更加复杂的混合模式,比如支持Tab切换的场景。
  • 无侵入性方案,使用时不再依赖修改Flutter的方案。
  • 支持对页面生命周期进行统一的管理。
  • 具有统一明确的设计概念。

并且,最近Flutter Boost升级了3.0版本,并带来了如下的一些更新:

  • 不侵入引擎,兼容Flutter的各种版本,Flutter sdk的升级不需要再升级FlutterBoost,极大降低升级成本。
  • 不区分Androidx和Support分支。
  • 简化架构和接口,和FlutterBoost2.0比,代码减少了一半。
  • 双端统一,包括接口和设计上的统一。
  • 支持打开Flutter页面,不再打开容器场景。
  • 页面生命周期变化通知更方便业务使用。
  • 解决了2.0中的遗留问题,例如,Fragment接入困难、页面关闭后不能传递数据、dispose不执行,内存占用过高等。

二、Flutter Boost集成

在原生项目中集成Flutter Boost只需要将Flutter Boost看成是一个插件工程即可。和其他Flutter插件的集成方式一样,使用FlutterBoost之前需要先添加依赖。使用Android Studio打开混合工程的Flutter工程,在pubspec.yaml中添加FlutterBoost依赖插件,如下所示。


flutter_boost:
    git:
        url: 'https://github.com/alibaba/flutter_boost.git'
        ref: 'v3.0-hotfixes'

需要说明的是,此处的所依赖的FlutterBoost的版本与Flutter的版本是对应的,如果不对应使用过程中会出现版本不匹配的错误。然后,使用flutter packages get命令将FlutterBoost插件拉取到本地。

2.1 Android集成

使用Android Studio打开新建的原生Android工程,在原生Android工程的settings.gradle文件中添加如下代码。


setBinding(new Binding([gradle: this]))
evaluate(new File(
  settingsDir.parentFile,
  'flutter_library/.android/include_flutter.groovy'))

然后,打开原生Android工程app目录下的build.gradle文件,继续添加如下依赖脚本。


dependencies {
  implementation project(':flutter_boost')
  implementation project(':flutter')
}

重新编译构建原生Android工程,如果没有任何错误则说明Android成功了集成FlutterBoost。使用Flutter Boost 之前,需要先执行初始化。打开原生Android工程,新建一个继承FlutterApplication的Application,然后在onCreate()方法中初始化FlutterBoost,代码如下。


public class MyApplication extends FlutterApplication {


    @Override
    public void onCreate() {
        super.onCreate();

        FlutterBoost.instance().setup(this, new FlutterBoostDelegate() {

            @Override
            public void pushNativeRoute(String pageName, HashMap<String, String> arguments) {
                Intent intent = new Intent(FlutterBoost.instance().currentActivity(), NativePageActivity.class);
                FlutterBoost.instance().currentActivity().startActivity(intent);
            }

            @Override
            public void pushFlutterRoute(String pageName, HashMap<String, String> arguments) {
                Intent intent = new FlutterBoostActivity.CachedEngineIntentBuilder(FlutterBoostActivity.class, FlutterBoost.ENGINE_ID)
                        .backgroundMode(FlutterActivityLaunchConfigs.BackgroundMode.opaque)
                        .destroyEngineWithActivity(false)
                        .url(pageName)
                        .urlParams(arguments)
                        .build(FlutterBoost.instance().currentActivity());
                FlutterBoost.instance().currentActivity().startActivity(intent);
            }

        },engine->{
            engine.getPlugins();
        } );
    }
}

然后,打开原生Android工程下的AndroidManifest.xml文件,将Application替换成自定义的MyApplication,如下所示。


<manifest xmlns:android="http://schemas.android.com/apk/res/android"
          xmlns:tools="http://schemas.android.com/tools"
          package="com.idlefish.flutterboost.example">

    <application
        android:name="com.idlefish.flutterboost.example.MyApplication"
        android:label="flutter_boost_example"
        android:icon="@mipmap/ic_launcher">

        <activity
            android:name="com.idlefish.flutterboost.containers.FlutterBoostActivity"
            android:theme="@style/Theme.AppCompat"
            android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|layoutDirection|fontScale|screenLayout|density"
            android:hardwareAccelerated="true"
            android:windowSoftInputMode="adjustResize" >
            <meta-data android:name="io.flutter.embedding.android.SplashScreenDrawable" android:resource="@drawable/launch_background"/>

        </activity>
        <meta-data android:name="flutterEmbedding"
                   android:value="2">
        </meta-data>
    </application>
</manifest>

由于Flutter Boost 是以插件的方式集成到原生Android项目的,所以我们可以在Native 打开和关闭Flutter模块的页面。


FlutterBoost.instance().open("flutterPage",params);
FlutterBoost.instance().close("uniqueId");

而Flutter Dart的使用如下。首先,我们可以在main.dart文件的程序入口main()方法中进行初始化。


void main() {
  runApp(MyApp());
}
class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
   static Map<String, FlutterBoostRouteFactory>
       routerMap = {
    '/': (settings, uniqueId) {
      return PageRouteBuilder<dynamic>(
          settings: settings, pageBuilder: (_, __, ___)
          => Container());
    },
    'embedded': (settings, uniqueId) {
      return PageRouteBuilder<dynamic>(
          settings: settings,
          pageBuilder: (_, __, ___) =>
          EmbeddedFirstRouteWidget());
    },
    'presentFlutterPage': (settings, uniqueId) {
      return PageRouteBuilder<dynamic>(
          settings: settings,
          pageBuilder: (_, __, ___) =>
          FlutterRouteWidget(
                params: settings.arguments,
                uniqueId: uniqueId,
              ));
    }};
   Route<dynamic> routeFactory(RouteSettings settings, String uniqueId) {
    FlutterBoostRouteFactory func =routerMap[settings.name];
    if (func == null) {
      return null;
    }
    return func(settings, uniqueId);
  }

  @override
  void initState() {
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return FlutterBoostApp(
      routeFactory
    );
  }

当然,还可以监听页面的生命周期,如下所示。


class SimpleWidget extends StatefulWidget {
  final Map params;
  final String messages;
  final String uniqueId;

  const SimpleWidget(this.uniqueId, this.params, this.messages);

  @override
  _SimpleWidgetState createState() => _SimpleWidgetState();
}

class _SimpleWidgetState extends State<SimpleWidget>
    with PageVisibilityObserver {
  static const String _kTag = 'xlog';
  @override
  void didChangeDependencies() {
    super.didChangeDependencies();
    print('$_kTag#didChangeDependencies, ${widget.uniqueId}, $this');

  }

  @override
  void initState() {
    super.initState();
   PageVisibilityBinding.instance.addObserver(this, ModalRoute.of(context));
   print('$_kTag#initState, ${widget.uniqueId}, $this');
  }

  @override
  void dispose() {
    PageVisibilityBinding.instance.removeObserver(this);
    print('$_kTag#dispose, ${widget.uniqueId}, $this');
    super.dispose();
  }

  @override
  void onForeground() {
    print('$_kTag#onForeground, ${widget.uniqueId}, $this');
  }

  @override
  void onBackground() {
    print('$_kTag#onBackground, ${widget.uniqueId}, $this');
  }

  @override
  void onAppear(ChangeReason reason) {
    print('$_kTag#onAppear, ${widget.uniqueId}, $reason, $this');
  }

  void onDisappear(ChangeReason reason) {
    print('$_kTag#onDisappear, ${widget.uniqueId}, $reason, $this');
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('tab_example'),
      ),
      body: SingleChildScrollView(
          physics: BouncingScrollPhysics(),
          child: Container(
              child: Column(
            crossAxisAlignment: CrossAxisAlignment.start,
            children: <Widget>[
              Container(
                margin: const EdgeInsets.only(top: 80.0),
                child: Text(
                  widget.messages,
                  style: TextStyle(fontSize: 28.0, color: Colors.blue),
                ),
                alignment: AlignmentDirectional.center,
              ),
              Container(
                margin: const EdgeInsets.only(top: 32.0),
                child: Text(
                  widget.uniqueId,
                  style: TextStyle(fontSize: 22.0, color: Colors.red),
                ),
                alignment: AlignmentDirectional.center,
              ),
              InkWell(
                child: Container(
                    padding: const EdgeInsets.all(8.0),
                    margin: const EdgeInsets.all(30.0),
                    color: Colors.yellow,
                    child: Text(
                      'open flutter page',
                      style: TextStyle(fontSize: 22.0, color: Colors.black),
                    )),
                onTap: () => BoostNavigator.of().push("flutterPage",
                    arguments: <String, String>{'from': widget.uniqueId}),
              )
              Container(
                height: 300,
                width: 200,
                child: Text(
                  '',
                  style: TextStyle(fontSize: 22.0, color: Colors.black),
                ),
              )
            ],
          ))),
    );
  }
}

然后,运行项目,就可以从原生页面跳转到Flutter页面,如下图所示效果。

2.2 iOS集成

和Android的集成步骤一样,使用Xcode打开原生iOS工程,然后在iOS的AppDelegate文件中初始化Flutter Boost ,如下所示。


@interface AppDelegate ()

@end

@implementation AppDelegate

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
  MyFlutterBoostDelegate* delegate=[[MyFlutterBoostDelegate alloc ] init];
    [[FlutterBoost instance] setup:application delegate:delegate callback:^(FlutterEngine *engine) {
    } ];

    return YES;
}
@end

下面是自定义的FlutterBoostDelegate的代码,如下所示。


@interface MyFlutterBoostDelegate : NSObject<FlutterBoostDelegate>
@property (nonatomic,strong) UINavigationController *navigationController;
@end

@implementation MyFlutterBoostDelegate

- (void) pushNativeRoute:(FBCommonParams*) params{
    BOOL animated = [params.arguments[@"animated"] boolValue];
    BOOL present= [params.arguments[@"present"] boolValue];
    UIViewControllerDemo *nvc = [[UIViewControllerDemo alloc] initWithNibName:@"UIViewControllerDemo" bundle:[NSBundle mainBundle]];
    if(present){
        [self.navigationController presentViewController:nvc animated:animated completion:^{
        }];
    }else{
        [self.navigationController pushViewController:nvc animated:animated];
    }
}

- (void) pushFlutterRoute:(FBCommonParams*)params {

    FlutterEngine* engine =  [[FlutterBoost instance ] getEngine];
    engine.viewController = nil;

    FBFlutterViewContainer *vc = FBFlutterViewContainer.new ;

    [vc setName:params.pageName params:params.arguments];

    BOOL animated = [params.arguments[@"animated"] boolValue];
    BOOL present= [params.arguments[@"present"] boolValue];
    if(present){
        [self.navigationController presentViewController:vc animated:animated completion:^{
        }];
    }else{
        [self.navigationController pushViewController:vc animated:animated];

    }
}

- (void) popRoute:(FBCommonParams*)params
         result:(NSDictionary *)result{

    FBFlutterViewContainer *vc = (id)self.navigationController.presentedViewController;

    if([vc isKindOfClass:FBFlutterViewContainer.class] && [vc.uniqueIDString isEqual: params.uniqueId]){
        [vc dismissViewControllerAnimated:YES completion:^{}];
    }else{
        [self.navigationController popViewControllerAnimated:YES];
    }

}

@end

如果要在原生iOS代码中打开或关闭Flutter页面,可以使用下面的方式。


[[FlutterBoost instance] open:@"flutterPage" arguments:@{@"animated":@(YES)}  ];
[[FlutterBoost instance] open:@"secondStateful" arguments:@{@"present":@(YES)}];

三、Flutter Boost架构

对于混合工程来说,原生端和Flutter端对于页面的定义是不一样的。对于原生端而言,页面通常指的是一个ViewController或者Activity,而对于Flutter来说,页面通常指的是Flutter组件。FlutterBoost框架所要做的就是统一混合工程中页面的概念,或者说弱化Flutter组件对应容器页面的概念。换句话说,当有一个原生页面存在的时候,FlutteBoost就能保证一定有一个对应的Flutter的容器页面存在。

FlutterBoost框架其实就是由原生容器通过消息驱动Flutter页面容器,从而达到原生容器与Flutter容器同步的目的,而Flutter渲染的内容是由原生容器去驱动的,下面是Flutter Boost 给的一个Flutter Boost 的架构示意图。

可以看到,Flutter Boost插件分为平台和Dart两端,中间通过Message Channel连接。平台侧提供了Flutter引擎的配置和管理、Native容器的创建/销毁、页面可见性变化通知,以及Flutter页面的打开/关闭接口等。而Dart侧除了提供类似原生Navigator的页面导航接口的能力外,还负责Flutter页面的路由管理。

总的来说,正是基于共享同一个引擎的方案,使得FlutterBoost框架有效的解决了多引擎的问题。简单来说,FlutterBoost在Dart端引入了容器的概念,当存在多个Flutter页面时,FlutterBoost不需要再用栈的结构去维护现有页面,而是使用扁平化键值对映射的形式去维护当前所有的页面,并且每个页面拥有一个唯一的id

四、FlutterBoost3.0更新

4.1 不入侵引擎

为了解决官方引擎复用引起的问题,FlutterBoost2.0拷贝了Flutter引擎Embedding层的一些代码进行改造,这使得后期的升级成本极高。而FlutterBoost3.0采用继承的方式扩展FlutterActivity/FlutterFragment等组件的能力,并且通过在适当时机给Dart侧发送appIsResumed消息解决引擎复用时生命周期事件错乱导致的页面卡死问题,并且,FlutterBoost 3.0 也兼容最新的官方发布的 Flutter 2.0。

4.2 不区分Androidx和Support分支

FlutterBoost2.0通过自己实现FlutterActivityAndFragmentDelegate.Host接口来扩展FlutterActivity和FlutterFragment的能力,而getLifecycle是必须实现的接口,这就导致对androidx的依赖。这也是为什么FlutterBoostView的实现没有被放入FlutterBoost3.0插件中的原因。而FlutterBoost3.0通过继承的方式扩展FlutterActivity/FlutterFragment的能力的额外收益就是,可以做到不依赖androidx。

4.3 双端设计统一,接口统一

很多Flutter开发者只会一端,只会Android 或者只会IOS,但他需要接入双端,所以双端统一能降低他的 学习成本和接入成本。FlutterBoost3.0,在设计上 Android和IOS都做了对齐,特别接口上做到了参数级的对齐。

4.4 支持 【打开flutter页面不再打开容器】 场景

在Flutter模块内部,Flutter 页面跳转Flutter 页面是可以不需要再打开Flutter容器的,不打开容器,能节省内存开销。在FlutterBoost3.0上,打开容器和不打开容器的区别表现在用户接口上仅仅是withContainer参数是否为true就好。


InkWell(
  child: Container(
      color: Colors.yellow,
      child: Text(
        '打开外部路由',
        style: TextStyle(fontSize: 22.0, color: Colors.black),
      )),
  onTap: () => BoostNavigator.of().push("flutterPage",
      arguments: <String, String>{'from': widget.uniqueId}),
),
InkWell(
  child: Container(
      color: Colors.yellow,
      child: Text(
        '打开内部路由',
        style: TextStyle(fontSize: 22.0, color: Colors.black),
      )),
  onTap: () => BoostNavigator.of().push("flutterPage",
      withContainer: true,
      arguments: <String, String>{'from': widget.uniqueId}),
)

4.5 生命周期的精准通知

在FlutterBoost2.0上,每个页面都会收到页面生命周期通知,而FlutterBoost3.0只会通知页面可见性实际发生了变化的页面,接口也更符合flutter的设计。

4.6 其他Issue

除了上面的一些特性外,Flutter Boost 3.0版本还解决了如下一些问题:

  • 页面关闭后参数的传递,之前只有iOS支持,android不支持,目前在dart侧实现,Ios 和Android 都支持。
  • 解决了Android 状态栏字体和颜色问题。
  • 解决了页面回退willpopscope不起作用问题。
  • 解决了不在栈顶的页面也收到生命周期回调的问题
  • 解决了多次setState耗性能问题。
  • 提供了Framgent 多种接入方式的Demo,方便tab 场景的接入。
  • 生命周期的回调代码,可以用户代码里面with的方式接入,使用更简单。
  • 全面简化了,接入成本,包括 dart侧,android侧和ios
  • 丰富了demo,包含了基本场景,方便用户接入 和测试回归

到此这篇关于Flutter Boost 混合开发框架的文章就介绍到这了,更多相关Flutter Boost内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!,希望大家以后多多支持编程网!

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

Flutter Boost 混合开发框架

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

Flutter Boost 混合开发框架

目录一、Flutter Boost简介二、Flutter Boost集成2.1 Android集成2.2 iOS集成三、Flutter Boost架构四、FlutterBoost3.0更新4.1 不入侵引擎4.2 不区分Androidx和S
2022-05-20

android混合开发框架有哪些优势

Android混合开发框架的优势有以下几点:1. 跨平台开发:Android混合开发框架可以通过一套代码同时在Android和其他平台上运行,如iOS、Web等,节省开发成本和时间。2. 前端技术支持:Android混合开发框架通常基于前端
2023-10-19

Flutter混合开发的方法是什么

今天小编给大家分享一下Flutter混合开发的方法是什么的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。为什么要混合方案具有一
2023-06-04

Linux下怎么部署Flutter开发框架

这篇文章主要介绍了Linux下怎么部署Flutter开发框架的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇Linux下怎么部署Flutter开发框架文章都会有所收获,下面我们一起来看看吧。Flutter是Goo
2023-06-27

混合开发要不要用vue

混合开发是近年来移动应用开发的重要趋势之一,它可以帮助开发者快速构建出具有丰富体验的移动应用。而在混合开发中,选用什么框架至关重要,其中Vue作为一款易用、高效、灵活的前端框架,自然也成为了许多开发者的选择之一。那么,混合开发到底需不需要使用Vue呢?首先,我们需要了解混合开发和Vue的基本概念。混合开发是指通过Web技术实现跨平台移动应用开发的一种方式,它可以将Web技术和原
2023-05-20

android怎么与HTML混合开发

今天就跟大家聊聊有关android怎么与HTML混合开发,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。1、关于HTML5种cookie网页中可能会用到 用户信息等很多参数,可以提前把
2023-06-09

js 和Android 混合开发原理

文章目录建立项目主要编译的目录结构 :src 文件混合App开发原理1、在MainActive文件中2、在AndroidManifest文件中(Android的一些配置信息)js调用Android中的功能Android调用js中的功能总结:
2022-06-06

H5混合开发app怎么升级

这篇文章给大家分享的是有关H5混合开发app怎么升级的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。当我们的app开发完成之后,无可避免的以后会进行产品升级,那么我们希望在客户的手机上让app进行自动升级,可以分为
2023-06-09

Android开发方式之Java+html+javascript混合开发

android开发,除了使用原生态的开发方式之外,还可以使用java+html+javascript混合开发的方式来开发,这样可以节省大量的开发时间,同时还可以使不同设备的用户获得相同的用户体验。好了,废话不多说,先来看看今天要做什么。
2022-06-06

编程热搜

  • Android:VolumeShaper
    VolumeShaper(支持版本改一下,minsdkversion:26,android8.0(api26)进一步学习对声音的编辑,可以让音频的声音有变化的播放 VolumeShaper.Configuration的三个参数 durati
    Android:VolumeShaper
  • Android崩溃异常捕获方法
    开发中最让人头疼的是应用突然爆炸,然后跳回到桌面。而且我们常常不知道这种状况会何时出现,在应用调试阶段还好,还可以通过调试工具的日志查看错误出现在哪里。但平时使用的时候给你闹崩溃,那你就欲哭无泪了。 那么今天主要讲一下如何去捕捉系统出现的U
    Android崩溃异常捕获方法
  • android开发教程之获取power_profile.xml文件的方法(android运行时能耗值)
    系统的设置–>电池–>使用情况中,统计的能耗的使用情况也是以power_profile.xml的value作为基础参数的1、我的手机中power_profile.xml的内容: HTC t328w代码如下:
    android开发教程之获取power_profile.xml文件的方法(android运行时能耗值)
  • Android SQLite数据库基本操作方法
    程序的最主要的功能在于对数据进行操作,通过对数据进行操作来实现某个功能。而数据库就是很重要的一个方面的,Android中内置了小巧轻便,功能却很强的一个数据库–SQLite数据库。那么就来看一下在Android程序中怎么去操作SQLite数
    Android SQLite数据库基本操作方法
  • ubuntu21.04怎么创建桌面快捷图标?ubuntu软件放到桌面的技巧
    工作的时候为了方便直接打开编辑文件,一些常用的软件或者文件我们会放在桌面,但是在ubuntu20.04下直接直接拖拽文件到桌面根本没有效果,在进入桌面后发现软件列表中的软件只能收藏到面板,无法复制到桌面使用,不知道为什么会这样,似乎并不是很
    ubuntu21.04怎么创建桌面快捷图标?ubuntu软件放到桌面的技巧
  • android获取当前手机号示例程序
    代码如下: public String getLocalNumber() { TelephonyManager tManager =
    android获取当前手机号示例程序
  • Android音视频开发(三)TextureView
    简介 TextureView与SurfaceView类似,可用于显示视频或OpenGL场景。 与SurfaceView的区别 SurfaceView不能使用变换和缩放等操作,不能叠加(Overlay)两个SurfaceView。 Textu
    Android音视频开发(三)TextureView
  • android获取屏幕高度和宽度的实现方法
    本文实例讲述了android获取屏幕高度和宽度的实现方法。分享给大家供大家参考。具体分析如下: 我们需要获取Android手机或Pad的屏幕的物理尺寸,以便于界面的设计或是其他功能的实现。下面就介绍讲一讲如何获取屏幕的物理尺寸 下面的代码即
    android获取屏幕高度和宽度的实现方法
  • Android自定义popupwindow实例代码
    先来看看效果图:一、布局
  • Android第一次实验
    一、实验原理 1.1实验目标 编程实现用户名与密码的存储与调用。 1.2实验要求 设计用户登录界面、登录成功界面、用户注册界面,用户注册时,将其用户名、密码保存到SharedPreference中,登录时输入用户名、密码,读取SharedP
    Android第一次实验

目录