首页 文章 精选 留言 我的

精选列表

搜索[独立开发者],共10000篇文章
优秀的个人博客,低调大师

为安卓开发者介绍的移动开发框架 Flutter

我是TrueFace的高级软件工程师 Adel Boussaken。今天我要给大家介绍 Flutter 开发。欢迎加入 Dart 阵营。 我将跳过所有有关安装和运行 Flutter 应用程序的部分,直接进行操作,如果您不确定 Flutter 是什么,并且有许多问题,请阅读关于 Flutter 的演进之路。 Dart 如果你认为 Kotlin 是 Java 的替代,等到你看到 Dart 后,你会发现它是直截了当,没有样板代码的: 默认为public,通过前缀“_” 进行私有化; 集合;点击试用 一切都是对象 - 没有“primitives” 命名参数,可选参数,默认值:点击试用 属性 -无需在任何地方写“get”方法 级联 -一切都是构建者 使用strong mode类型推导 - 只需要在本地写“var” 命名构造函数,自动分配到字段;点击试用 字符串插值,几种类型的字符串;点击试用 dartfmt -如果不想格式化也可以不用这个工具 这里有一个 Dart 代码的例子,一个获取 IP 地址的私有方法: _getIPAddress() async { String url = 'https://httpbin.org/ip'; var httpClient = createHttpClient(); var response = await httpClient.read(url); Map data = JSON.decode(response); String ip = data['origin']; } 设计模式 我很确定你已将你的 Android 技巧从无序代码扩展到 MVC、MVP、MVVM,Dagger2、DataBinding 和Android 架构组件,Flutter 基本上就是一个 V(View),响应式视图,它可以是无状态或有状态的 widget,就连 AppCompatActivity 也是一个 widget。 让我们创建一个非常简单的 Activity,我们需要一个文本视图和一个更新该文本的按钮,下面是 Activity 代码(注意没有 XML): public class Click extends Activity { int count = 0; protected void onCreate(Bundle bundle) { super.onCreate(bundle); setContentView(R.layout.main); final Button button = (Button) findViewById(R.id.button); final TextView text = (TextView) findViewById(R.id.counter); button.setOnClickListener(new View.OnClickListener() { public void onClick(View v) { count++; text.setText("Button clicked " + counter + " times"); } }); } } 在 Flutter,你不需要操纵视图,就像 setText() 中的代码,你可以使用 state 来替代,并且 Flutter 将会处理好屏幕更新,在 Flutter 中和上述代码等价的是: import 'package:flutter/material.dart';class Activity extends StatefulWidget { @override ActivityState createState() => new ActivityState(); }class ActivityState extends State<Activity> { int counter = 0; @override Widget build(BuildContext context) { return new Scaffold( body: new Center( child: new Column( mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[ new Text( 'Button clicked ${counter} times', ), new FlatButton( child: new Text('Increment'), onPressed: () { setState(() { counter++; }); }, ), ], ), ), ); } } 你也注意到,我们在 setState 中增加了 counter 的值,一旦 onPressed 被触发(之后是 setState),Flutter 将会使用新的 counter 值来重新渲染整个 widget 和 text 对象。 分离 widget 和 state(对于 Android 开发人员来说)的最大优点是,如果你在 Java 代码中旋转设备或调整窗口大小(支持多窗口),则计数器的值将被重置为零,你必须编写大量重复代码来管理 Activity 的生命周期。而在 Flutter 中,这是不需要的,现成的功能,无需额外的代码。 虽然 Dart 最终编译为 native 代码,但它不会访问硬件设备,例如,如果你要获取用户位置,你必须使用平台通道编写特定平台的代码,与此同时,确实有很多插件来处理这些情况,但你依然希望登录Android Studio(或 Xcode)在代码之间完成该事项。 Async/Await 在 Android 开发中,UI 线程非常重要,完成速度稍慢的事情工作,会显示以下神秘行: I/Choreographer(1378): Skipped 55 frames! The application may be doing too much work on its main thread. 这种情况你只能使用线程来处理,如下所示: public void onClick(View v) { new Thread(new Runnable() { public void run() { // a potentially time consuming task final Bitmap bitmap = processBitMap("image.png"); mImageView.post(new Runnable() { public void run() { mImageView.setImageBitmap(bitmap); } }); } }).start(); } 上述代码可以很简单的使用 Dart 完成: onClick() async { Bitmap bitmap = await processBitMap("image.png"); // you don't want to update non-existent widget if (!mounted) return; setState(() { imageView = bitmap; }); } 这里发生了什么? async 修饰符标记的方法会安排稍后执行,该方法变成非阻塞的,因此你的应用程序不会丢失任何帧,await 修饰符挂起方法的执行,等待 processBitMap 完成,然后执行将会恢复。 Widget 目前有大量在 Android 之上运行的各种 OEM 软件和皮肤,这都是可以理解的,因为每个制造商都希望为其设备建立自己的附加值,我不能计算我究竟说了多少次“Funck S*ms*ng”,OEM 定制对 Android 开发人员引入了很多难题.。 Flutter,为了实现 120FPS 的目标,已决定开始在一个空的画布上,使用Skia2D 图形库绘制每个 widget,而不是重用 OEM widget,并实现大多数 Material Designa 和通用 layout。 这种方法,无法保证你的应用程序在多种设备上看起来是一样的,尽管并不是所有的 Flutter widget 都经过优化,可以在平板电脑上也可以在较小屏幕的设备上正常工作。 无论如何,这种方法也为 UI 设计的创新打开了新的大门,例如,以下的代码可以使得用户改变 Activity 的大小: class HeroScreen extends StatefulWidget { @override HeroState createState() => new HeroState(); }class HeroState extends State<HeroScreen> with SingleTickerProviderStateMixin { bool _scaling = false; Matrix4 _transformScale = new Matrix4.identity(); double scalePos = 1.0; set _scale(double value) => _transformScale = new Matrix4.identity()..scale(value, value, 1.0); @override Widget build(BuildContext context) { return new Scaffold( body: new GestureDetector( onScaleStart: (details) { setState(() { _scaling = true; }); }, onScaleUpdate: (details) { var n = details.scale; setState(() { scalePos = n; _scale = n; }); }, onScaleEnd: (details) { setState(() { _scaling = false; _scale = scalePos < 1 ? 1.0 : scalePos; }); }, child: new Container( color: Colors.black26, child: new Transform( transform: _transformScale, child: new Center( child: new Row( mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[ new Text(_scaling ? "Scaling" : "Scale me up"), ])))))); } } 这让我们得到一个非常有趣的小部件,这样去写可重复使用的小部件就太容易了, 我可以将以上不太友好的代码转换成可重用且干净的小部件: class Scale extends StatefulWidget { final Widget child; final GestureScaleStartCallback onStart; final GestureScaleEndCallback onEnd; final GestureScaleUpdateCallback onUpdate; Scale({Key key, this.child, this.onStart, this.onUpdate, this.onEnd}) : super(); @override ScaleState createState() => new ScaleState(); }class ScaleState extends State<Scale> with SingleTickerProviderStateMixin { Matrix4 _transformScale = new Matrix4.identity(); double scalePos = 1.0; set _scale(double value) => _transformScale = new Matrix4.identity()..scale(value, value, 1.0); @override Widget build(BuildContext context) { return new GestureDetector( onScaleStart: widget.onStart, onScaleUpdate: (details) { widget.onUpdate(details); var n = details.scale; setState(() { scalePos = n; _scale = n; }); }, onScaleEnd: (details) { widget.onEnd(details); setState(() { _scale = scalePos < 1 ? 1.0 : scalePos; }); }, child: new Container( color: Colors.black26, child: new Transform( transform: _transformScale, child: widget.child))); } } 重构后的代码如下: class HeroScreen extends StatefulWidget { @override HeroState createState() => new HeroState(); }class HeroState extends State<HeroScreen> with SingleTickerProviderStateMixin { bool _scaling = false; @override Widget build(BuildContext context) { return new Scaffold( body: new Scale( onStart: (details) => setState(() => _scaling = true), onUpdate: (details) {}, onEnd: (details) => setState(() => _scaling = false), child: new Container( color: Colors.black26, child: new Center( child: new Row( mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[ new Text(_scaling ? "Scaling" : "Scale me up"), ]))), )); } } Etc 即时运行称为热重新加载,需要不到一秒钟 Flutter 使用 CPU 绘制图形、使用GPU 渲染, 但是一些关于 3D 的 API 是不可用的 不用 XML 来设计布局 布局只需一次性计算树的大小 即使有语法错误,您的 APP 也不会崩溃 Flutter 小部件可以嵌入到 Android Activity 中 您不能在 Flutter 小部件中嵌入 Android 库 至少需要 60 FPS,除非你的机器正在做别的事情 受到 React 的启发设计 了API,但不是像 React 那样运行的 不需要任何 POJO 原文发布时间为:2017-10-10 本文作者:佚名 本文来自云栖社区合作伙伴“51CTO”,了解相关信息可以关注。

优秀的个人博客,低调大师

【开发者笔记】java 利用jna调用c#的dll

一、需求阐述: 如果我们的项目利用c#开发,到了开发后期需要和java组进行合作,其中有一部分业务逻辑利用c#已经code completed,那么我们可能会考虑用java来调用现成的c#dll实现需求。前几天工作上正好遇到这样一个问题,于是记下开发过程。 当然这只是个假设,具体情况具体分析,个人认为重构代码才是王道…… 二、原理说明: 其实具体原理我也没弄太明白,我就根据自己的理解来说吧,抛砖引玉。 因为c#代码是托管到.net平台上的,所以java不能直接调用c#代码,于是引入C++中间件,c++项目可以设置项目为clr公共运行时,从而通过引用的方式调用c#相应方法。而jna是可以直接调用c++生成的dll的,于是大致流程就走通了。c++调用写好的c#dll,java再调用c++生成的dll中间件,大致流程就是这样了,不过其中有很多坑,下面我会细说。 三、运行平台: 系统:Windows 10 x64 开发工具:Visual Studio 2015/2017(我笔记本和公司电脑安装不同版本,我都有实现过) MyEclipse2014 SDK:jdk-x86、jdk-x64 (dll分为x86和x64平台,和jdk的版本要对应,同一台电脑装两个版本的jdk比较烦,我采用的是系统配置jdk32位调试32位dll,然后myeclipse自带64位jdk调试64位dll) 四、准备工作: 1、首先准备上述运行平台,建议选择和系统位数一致的jdk(安装vs、myeclipse或eclipse或sts); 2、下载jna.jar :JNA下载(下载jna-4.4.0.jar 和 jna-platform-4.4.0) 五、开始CODE 5.1 生成c#DLL 5.1.1 以管理员方式启动vs(项目涉及到注册com组件,必须以管理员启动才能完成),新建c#项目 5.1.2 设置c#项目 首先,右键刚刚新建的Invoke项目,点击属性。 继续设置项目属性。 记得保存。 然后新建需要被调用的CSharp类代码。这里我们新建一些简单的方法,为了演示效果我们分别对int、string、bool进行操作。如图: 然后右键项目,点击生成。 第一步,完成,干得漂亮。 5.2 生成c++中间件 5.2.1 新建c++项目并设置属性 项目新建成功,右键项目,选择属性。 5.2.2 书写c++代码 添加cpp文件 编辑cpp文件 /********************************** 2017-9-5 21:02:51 声明需要被java调用的方法,该方法和java接口内部方法保持一致 预处理语句目的是暴露函数供外部调用。 ************************/ #ifdef MYLIBAPI #else #define MYLIBAPI extern "C" __declspec(dllimport) #endif MYLIBAPI int add(int a, int b); //添加函数声明 MYLIBAPI char* getString(char* str); MYLIBAPI int reverse(int flag); using namespace System; using namespace Invoke; //using namespace System::Runtime::InteropServices::m int add(int a, int b) { Method ^method = gcnew Method(); int result = method->add(a, b); return result; } char* getString(char* str) { String ^ paraStr = gcnew String(str); Method ^method = gcnew Method(); String ^resultString = method->getString(paraStr); char* result = (char*)(void*)System::Runtime::InteropServices::Marshal::StringToCoTaskMemAnsi(resultString); return result; } int reverse(int flag) { Method ^method = gcnew Method(); int result = method->reverse(flag); return result; } 好了,c++和c#全部工作完成,右键生成。 复制下dll生成文件全名,一会儿java里面用。 六、编写java代码 6.1 新建java project ,注意选择和dll平台一致的jdk。然后将之前下载的两个jna的jar加载到项目里面,如图: 6.2 开始写java 代码 package com.dyi.test; import com.sun.jna.Library; import com.sun.jna.Native; /** * 需要引入jna-4.4.0.jar 和 jna-platform-4.4.0 * 包下载地址:https://github.com/java-native-access/jna * @author stagebo * */ public class InvokeTest { /** * 调用示例 * @param args * @throws Exception */ public static void main(String[] args) throws Exception { System.out.println(System.getProperty("java.version"));//输出当前jdk版本号 System.out.println(System.getProperty("sun.arch.data.model"));//输出当前jdk所用平台 CLibrary1 clib = CLibrary1.INSTANCE; System.out.println("测试返回结果:"+clib.add(13, 13)); System.out.println("测试返回结果:"+clib.getString("this is java param.")); System.out.println("测试返回结果:"+clib.reverse(true)); } } /** * 必要接口,必须包含INSTANCE实例和需要调用的方法声明。 * @author stagebo * */ interface CLibrary1 extends Library { CLibrary1 INSTANCE = (CLibrary1) Native. loadLibrary("D:\\vs workplace\\java调用CSDLL示例\\x64\\Release\\CppDll", CLibrary1.class); /*需要调用的方法,方法名与c++方法名相同*/ int add(int a,int b); String getString(String a); boolean reverse(boolean flag); } 然后我们运行: 哦豁,报错了【无效的内存访问】,因为java找到了c++dll,但是没找到c#的dll,其中c++dll我们写的全路径名,可以直接找到,那么c#的dll怎么找呢。答案是将c#的dll复制到jdk的bin目录下,jvm就能找到了。 如图我们将Invoke.dll复制到jdk的bin目录下: 然后再运行: nice!对于常用类型中的int、string、boolean都可以顺利传递了,事实上其他类型的也可以实现,只要遵循不同语言之间的类型对应关系就可以了,具体的类型关系可以百度。 七、注意事项 7.1 java报错:Exception in thread "main" java.lang.Error: Invalid memory access 可能原因: 1、c#dll没有复制到jdk的bin目录; 2、java和c++之间数据类型不对应; 7.1.2 java报错:Exception in thread "main" java.lang.UnsatisfiedLinkError: Unable to load library 'D:\vs workplace\X86InvokeTest\Release\X86CPPDlls': Native library (win32-x86/D:\vs workplace\X86InvokeTest\Release\X86CPPDlls.dll) not found in resource path ([file:/G:/My%20Eclipse%20workplace/InvokeCSharpX86Test/bin/, file:/G:/My%20Eclipse%20workplace/InvokeCSharpX86Test/Lib/jna-4.4.0.jar, file:/G:/My%20Eclipse%20workplace/InvokeCSharpX86Test/Lib/jna-platform-4.4.0.jar]) 可能原因: 1、c++dll路径不正确,建议做test时用绝对路径,这样你在c++项目编译过后不用拷贝便可以在java程序里面直接调用; 2、jdk的平台和c++项目的平台不匹配,jdk是32位那么c++dll一定也是32位的,64位也同样; 7.1.3 windows64位下编译的32位dll测试失败,暂时不清楚是不是64位系统的原因,由于我电脑虚拟机没有装上,就没有去32位系统上测试了。 ================================2018-1-3 17:15:54 更新======================================================== 1、提供给测试项目开源地址: Github测试代码连接 Github测试代码连接2 2、怎么确定c#的dll是不是成功复制到jdk的bin目录呢?换言之怎么确定自己的bin目录在哪里呢?可以在eclipse中运行的时候通过控制台看到。 黑夜给了我黑色的眼睛,我却用它寻找光明

资源下载

更多资源
Mario

Mario

马里奥是站在游戏界顶峰的超人气多面角色。马里奥靠吃蘑菇成长,特征是大鼻子、头戴帽子、身穿背带裤,还留着胡子。与他的双胞胎兄弟路易基一起,长年担任任天堂的招牌角色。

腾讯云软件源

腾讯云软件源

为解决软件依赖安装时官方源访问速度慢的问题,腾讯云为一些软件搭建了缓存服务。您可以通过使用腾讯云软件源站来提升依赖包的安装速度。为了方便用户自由搭建服务架构,目前腾讯云软件源站支持公网访问和内网访问。

Nacos

Nacos

Nacos /nɑ:kəʊs/ 是 Dynamic Naming and Configuration Service 的首字母简称,一个易于构建 AI Agent 应用的动态服务发现、配置管理和AI智能体管理平台。Nacos 致力于帮助您发现、配置和管理微服务及AI智能体应用。Nacos 提供了一组简单易用的特性集,帮助您快速实现动态服务发现、服务配置、服务元数据、流量管理。Nacos 帮助您更敏捷和容易地构建、交付和管理微服务平台。

WebStorm

WebStorm

WebStorm 是jetbrains公司旗下一款JavaScript 开发工具。目前已经被广大中国JS开发者誉为“Web前端开发神器”、“最强大的HTML5编辑器”、“最智能的JavaScript IDE”等。与IntelliJ IDEA同源,继承了IntelliJ IDEA强大的JS部分的功能。

用户登录
用户注册