A开始执行这个方法~
B开始执行这个方法~
后面执行这句话~
C开始
继续执行这句哈11111~
start结束
- 当使用async作为方法名后缀声明时,说明这个方法的返回值是一个Future;
- 当执行到该方法代码用await关键字标注时,会暂停该方法其他部分执行;
- 当await关键字引用的Future执行完成,下一行代码会立即执行。
也就是首先执行_startMethod
这个方法用async声明了,因为方法里调用了_method_A
,所以先输出print(“A开始执行这个方法~”);,后面执行_method_B()
,这个方法用await关键字声明,所以会暂停print(“start结束”);的执行,然后继续执行_method_B()
将 print(“B开始执行这个方法");**输出,下一行遇到**await**关键字,会暂停其他代码的执行。当**await**关键字引用的**Future**执行完成(也就是执行**print("后面执行这句话”),_method_C()
方法会立即执行,然后执行继续执行这句哈11111~,最后执行print(“start结束”);
3.Stream
Stram
是接收异步事件数据,和Future
不同的是,它可以接收多个异步操作的结果,那么Stram
常用于在多次读取数据的异步任务场景,直接上例子:
void create(){
Stream.fromFutures([
//2秒后返回结果
Future.delayed(new Duration(seconds: 2),(){
return “Android”;
}),
//3秒后抛出一个异常
Future.delayed(new Duration(seconds: 3),(){
return AssertionError(“error”);
}),
//4秒后返回结果
Future.delayed(new Duration(seconds: 4),(){
return “Flutter”;
})
]).listen((result){
//打印接收的结果
print(result);
},onError: (e){
//错误回调
print(e.message);
},onDone: (){
});
}
上面可以发现Stream
可以通过触发成功或者失败传递结果或者错误。
四、文件操作
有很多时候需要将文件保存到本地,这时候就需要用文件读写接口来实现,PathProvider
插件提供一种平台透明的方式来访问设备文件系统上的常用位置。该类当前支持两个文件系统位置:
- 临时目录:系统可随时清除的临时目录(缓存)。在iOS上,这对应于
NSTemporaryDirectory()
返回的值。在Android上,这是getCacheDir()
返回的值。 - 文档目录:应用程序的目录,用于存储只有自己可以访问的文件,只有当应用程序被卸载时,系统才会清除目录。在iOS上,这对应于
NSDocumentDirectory
。在Android上,这是AppData
目录。
在Flutter
里实现文件读写,需要使用path_provider
和Dart
里的I/O
模块,两者的职责并不一样,path_provider
是负责查找iOS或者Android下的目录文件,而I/O
是负责文件的读写操作。
1.获取本地路径
下面使用path_provider
来查找本地的路径,首先在pubspec.xml
文件添加依赖:
dependencies:
flutter:
sdk: flutter
The following adds the Cupertino Icons font to your application.
Use with the CupertinoIcons class for iOS style icons.
path_provider: ^0.4.1 -->添加依赖
或者临时目录,文档目录,sd卡目录如下:
import ‘dart:io’;
import ‘dart:async’;
import ‘package:flutter/material.dart’;
import ‘package:path_provider/path_provider.dart’;
…
class _LoadFileState extends State{
@override
void initState(){
super.initState();
}
@override
Widget build(BuildContext context){
return new Scaffold(
appBar: new AppBar(
title: new Text(“LoadFile”),
),
body: new Center(
child: RaisedButton(
child: Text(“获取文件路径”),
//点击调用获取文件路径方法
onPressed: loadPath,
),
),
);
}
}
loadPath() async{
try{
//临时目录
var _tempDir = await getTemporaryDirectory();
//获取具体路径
String tempDirPath = _tempDir.path;
//文档目录
var _document = await getApplicationDocumentsDirectory();
String documentPath = _document.path;
//sd卡目录
var _sdCard = await getExternalStorageDirectory();
String sdCardPath = _sdCard.path;
//打印路径
print(“临时目录:”+ tempDirPath);
print(“文档目录:”+ documentPath);
print(“sd卡目录:”+ sdCardPath);
}catch(err){
print(err);
}
}
输出结果(Android)如下:
I/flutter (19375): 临时目录:/data/user/0/com.example.loadflie/cache
I/flutter (19375): 文档目录:/data/user/0/com.example.loadflie/app_flutter
I/flutter (19375): sd卡目录:/storage/emulated/0
2.读取本地文件内容
读取文件少不了权限的问题,在Dart Packages可以找到simple_permissions
这个库来简化申请权限的步骤,按照上面说明跟着操作就可以:
上面的意思是在AndroidManifest
和Info.plist
文件下添加权限,身为Android coder对AndroidManifest
这个文件很熟悉,这个文件是对Android而言,而Info.plist
应该是对于iOS
而言,那下面先在Android上试试看,首先,在pubspec.yaml
上添加依赖:
simple_permissions: ^0.1.9
记得点击Packages get
命令。 接着在AndroidManifest
清单文件上添加对文件的读写权限:
下面在手机sd card内部存储新建一个txt文件,尝试获取其内容:
import ‘package:simple_permissions/simple_permissions.dart’;//记得加上这句话
…
//读取文件方法
readData() async {
try {
//申请读文件的权限
var permission =
SimplePermissions.requestPermission(Permission.ReadExternalStorage);
var sdCardPath = getExternalStorageDirectory();
//当获取到路径的时候
sdCardPath.then((filePath) {
//获得读取文件权限
permission.then((permission_status) async {
//获取文件内容
var data = await File(filePath.path + “/flutter.txt”).readAsString();
print(data);
});
});
} catch (e) {
print(e);
}
}
按钮点击方法改为readData
:
child: RaisedButton(
child: Text(“获取文件路径”),
onPressed: readData
),
点击按钮结果运行:
选择始终运行: 输出就是flutter.txt
文件内容:
I/flutter (24038): flutter is very good.
注意如果不加读写权限,会抛出异常:
I/flutter (25428): FileSystemException: Cannot open file, path = ‘/storage/emulated/0/flutter.txt’ (OS Error: Permission denied, errno = 13)
3.写入文件操作
//把内容写入文件操作
writeData() async{
try {
//申请读文件的权限
var permission =
SimplePermissions.requestPermission(Permission.WriteExternalStorage);
var sdCardPath = getExternalStorageDirectory();
//当获取到路径的时候
sdCardPath.then((filePath) {
//获得读取文件权限
permission.then((permission_status) async {
//把内容写进文件
var data = await File(filePath.path + “/flutter.txt”).writeAsString(“点滴之行,看世界”);
print(data);
});
});
} catch (e) {
print(e);
}
}
打开sd card的flutter.txt
文件看看内容:
发现,把之前的内容覆盖了!那么如何实现所写入的内容不覆盖原来文件的内容呢?这时候需要用到append
模式,很简单,把默认的FileMode mode: FileMode.write
方式改为FileMode mode: FileMode.append
,代码如下:
//把内容写进文件 现在以追加的方式
var data = await File(filePath.path + “/flutter.txt”).writeAsString(“Flutter is very good”,
mode: FileMode.append);
运行结果:
好了,简单的读写文件就实现了。
五、sqflite数据库
Android
和iOS
中都会有SQLite
,那么Flutter
有没有呢?答案是肯定有的。Flutter
中的SQLite
数据库是同时支持Android
和iOS
的,它的名字叫sqflite
,支持事务和批量操作,支持插入/查询/更新/删除操作等,是轻量级的关系型数据库。 下面先简单实现一个登录界面,进行简单的数据操作:
//用无状态控件显示
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
//主题色
theme: ThemeData(
//设置为蓝色
primarySwatch: Colors.red),
//这是一个Widget对象,用来定义当前应用打开的时候,所显示的界面
home: DataBaseWidget(),
);
}
}
//主框架
class DataBaseWidget extends StatefulWidget {
@override
State createState() {
return new _DataBaseState();
}
}
class _DataBaseState extends State {
@override
Widget build(BuildContext context) {
return new Scaffold(
//appBar
appBar: AppBar(
title: Text(“Sqlite简单操作”),
//标题居中
centerTitle: true,
),
body: new ListView(
children: [
//用户输入用户信息widget
Padding(
padding: const EdgeInsets.only(left: 16, right: 16),
child: InputMessageWidget(),
),
//数据库表的一些基本操作,增,删,改,查
Padding(
padding: const EdgeInsets.all(16),
child: SqliteHandleWidget(),
),
],
),
);
}
}
用户输入信息的Widget
如何:
//用户名和密码
class InputMessageWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
//这个是为了用户输入结束后,让密码输入框获取到焦点
FocusNode secondTextFieldNode = FocusNode();
return Column(
children: [
TextField(
//文字内容改变触发
onChanged: (user) {
//获取用户名
username = user;
},
//输入法装饰器
decoration: InputDecoration(
//标签
labelText: ‘名字’,
//hint 提示用户输入什么
hintText: ‘请输入英文或者数字’),
//最大为一行
maxLines: 1,
//文字提交触发
onSubmitted: (result) {
FocusScope.of(context).reparentIfNeeded(secondTextFieldNode);
},
),
TextField(
onChanged: (pwd) {
//获取用户密码
password = pwd;
},
//是否隐藏输入 false 表示不隐藏,true表示隐藏
obscureText: true,
maxLines: 1,
decoration: InputDecoration(
labelText: ‘密码’,
hintText: ‘请输入密码’,
),
//键盘输入类型
keyboardType: TextInputType.text,
onSubmitted: (data) {},
),
],
);
}
}
对数据库表操作的按钮布局如下:
//数据库组件操作
class SqliteHandleWidget extends StatefulWidget {
@override
State createState() {
return new _SqliteHandleWidgetState();
}
}
class _SqliteHandleWidgetState extends State {
//数据库名称
String myDataBase = “usermessage.db”;
//数据库路径
String myDataBasePath = “”;
//数据库中的表 简单一点,就创建三个字段,分别是主键,用户名,密码
String sql_createUserTable = “CREATE TABLE user(”
“id INTEGER PRIMARY KEY,”
“username TEXT,”
“password TEXT)”;
//查找数据库表的数目
String sql_queryCount = ‘SELECT COUNT(*) FROM user’;
//具体查找数据库表的所有信息
String sql_queryMessage = ‘SELECT * FROM user’;
//这是从数据库表返回数据
var _data;
@override
Widget build(BuildContext context) {
return Column(
//交叉轴设置中间
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Container(
height: 40.0,
child: RaisedButton(
textColor: Colors.black,
child: Text(“创建数据库表”),
onPressed: null,
),
),
Row(
//主轴方向中心对齐
mainAxisAlignment: MainAxisAlignment.center,
children: [
new RaisedButton(
textColor: Colors.black,
child: new Text(‘增’),
onPressed: null),
new RaisedButton(
textColor: Colors.black,
child: new Text(‘删’),
onPressed: null),
new RaisedButton(
textColor: Colors.black,
child: new Text(‘改’),
onPressed: null),
],
),
Row(
//主轴方向中心对齐
mainAxisAlignment: MainAxisAlignment.center,
children: [
new RaisedButton(
textColor: Colors.black,
child: new Text(‘查条数’),
onPressed: null),
new RaisedButton(
textColor: Colors.black,
child: new Text(‘查信息’),
onPressed: null),
],
),
Padding(
padding: const EdgeInsets.all(16.0),
child: new Text(‘具体结果是:$_data’),
),
],
);
}
}
在上面_SqliteHandleWidgetState
赋值数据库名字为usermessage.db
,创建数据库表user
语句很简单,就三个字段,分别是主键,用户名,用户密码,界面如下:
界面弄好了,下面就一步一步来。
1.创建数据库和数据表
首先添加依赖:可以到Dart包管理网站去查找sqlite依赖最新版本。
sqflite: ^1.1.0
并在文件引入:
import ‘package:path_provider/path_provider.dart’;
import ‘dart:io’;
import ‘package:sqflite/sqflite.dart’;
import ‘package:path/path.dart’;
注意:对于数据库的操作都是耗时操作,都要通过异步来处理。
//创建数据库
Future createDataBase(String db_name) async {
//在文档目录建立
var document = await getApplicationDocumentsDirectory();
//获取路径 join是path包下的方法,就是将两者路径连接起来
String path = join(document.path, db_name);
//逻辑是如果数据库存在就把它删除然后创建
var _directory = new Directory(dirname(path));
bool exists = await _directory.exists();
if (exists) {
//必存在 这里是为了每次创建数据库表先表删除则删除数据库表
await deleteDatabase(path);
} else {
try {
//不存在则创建目录 如果[recursive]为false,则只有路径中的最后一个目录是
//创建。如果[recursive]为真,则所有不存在的路径
//被创建。如果目录已经存在,则不执行任何操作。
await new Directory(dirname(path)).create(recursive: true);
} catch (e) {
print(e);
}
}
return path;
}
//创建数据库表方法
cratedb_table() async {
//得到数据库的路径
myDataBasePath = await createDataBase(myDataBase);
//打开数据库
Database my_db = await openDatabase(myDataBasePath);
//创建数据库表
await my_db.execute(sql_createUserTable);
//关闭数据库
await my_db.close();
setState(() {
_data = “创建usermessage.db成功,创建user表成功~”;
});
}
给按钮添加点击方法:
child: RaisedButton(
textColor: Colors.black,
child: Text(“创建数据库表”),
onPressed: cratedb_table,
),
运行,安装完apk,用Device File Exploder
来看看内部存储文件:
下面点击创建数据库,后synchronize
来刷新一下:
发现在app_flutter
下多了usermessage.db
文件,确实数据库创建成功了,那继续下面的操作。
2.增加数据
下面实现增加数据,可以用rawInsert
或者db.insert
方式对数据库表数据进行增加(插入),实际上都是通过insert into
方式来插入数据表,下面就用rawInsert
方式来增加一条数据:
//增加方法
addData() async {
//首先打开数据库
Database my_db = await openDatabase(myDataBasePath);
//插入数据
String add_sql = “INSERT INTO user(username,password) VALUES(‘
u
s
e
r
n
a
m
e
′
,
′
username','
username′,′password’)”;
await my_db.transaction((tran) async{
await tran.rawInsert(add_sql);
});
//关闭数据库
await my_db.close();
setState(() {
_data = “增加一条数据成功,名字是:
u
s
e
r
n
a
m
e
,
密码是:
username,密码是:
username,密码是:password”;
});
}
3.查询具体数据
为了配合增加数据,把查询数据库表的功能实现:
//查询具体数值
queryDetail() async{
//打开数据库
Database my_db = await openDatabase(myDataBasePath);
//将数据放到集合里面显示
List
查询数据表很简单,实际上只用rawQuery
这个方法,把增加和查询方法绑定到按钮点击上:
new RaisedButton(
textColor: Colors.black, child: new Text(‘改’), onPressed: null),
…
new RaisedButton(
textColor: Colors.black,
child: new Text(‘查信息’),
onPressed: queryDetail),
验证结果,流程是:
- 先输入用户名和密码
- 点击增加
- 点击查信息: 运行结果如下:
4.删除数据
下面实现删除数据:
//删除一条数据
delete() async {
Database my_db = await openDatabase(myDataBasePath);
//根据id来删除 也可以根据其他信息来删除 例如名字
String delete_ssql = “DELETE FROM user WHERE id = ?”;
//返回所更改的数目
int delete_count = await my_db.rawDelete(delete_ssql,[‘1’]);
//关闭数据库
await my_db.close();
//状态更新
setState(() {
if(delete_count == 1){
_data = “删除成功~”;
} else {
_data = “删除失败,请看错误日志~”;
}
});
}
记得给删除按钮绑定方法,运行结果就不贴了。
5.修改数据
修改数据我相信在平时开发中是用的最频繁的操作了,直接上实现例子:
//修改数据方法
update() async{
//数据库
Database my_db = await openDatabase(myDataBasePath);
String update_sql = “UPDATE user SET username = ? WHERE id = ?”;
await my_db.rawUpdate(update_sql,[‘paul’,‘1’]);
await my_db.close();
setState(() {
_data = “数据修改成功,请查阅~”;
});
}
上面用了rawUpdate
对数据库表进行内容数据更新,也可以用db.update
来更新,自己可以根据需求变更去修改固定字段或者整条数据。上面我是根据id
这个条件来修改一条数据,将id
为1的数据的名字改为paul
。
6.查询条数
//查询有几条
query_num() async{
//数据库
Database my_db = await openDatabase(myDataBasePath);
//用sqflite包的方法firstInValue
int data_count = Sqflite.firstIntValue(await my_db.rawQuery(sql_queryCount));
await my_db.close();
setState(() {
_data = “数据条数:$data_count”;
});
}
对本地数据库的基本操作实现了一遍,下面学习网络请求操作。
六、网络请求操作
Flutter
的请求网络有多种方式,一种是使用dart io
中的HttpClient
发起的请求,一种是使用dio
库,另一种是使用http
库,先学一下get
和post
,put
、delete
就等后面用到在学。下面就实践:
1.dart io发起的请求
1.1.get请求
import ‘dart:io’;//导IO包
import ‘dart:convert’;//解码和编码JSON
void main() {
_get();
}
_get() async{
var responseBody;
//1.创建HttpClient
var httpClient = new HttpClient();
//2.构造Uri
var requset = await httpClient.getUrl(Uri.parse(“http://gank.io/api/data/%E7%A6%8F%E5%88%A9/10/1”));
//3.关闭请求,等待响应
var response = await requset.close();
//4.进行解码,获取数据
if(response.statusCode == 200){
//拿到请求的数据
responseBody = await response.transform(utf8.decoder).join();
//先不解析打印数据
print(responseBody);
}else{
print(“error”);
}
}
结果如下:
1.2.post请求
_post() async{
var responseBody;
//1.创建HttpClient
var httpClient = new HttpClient();
//2.构造Uri
var requset = await httpClient.postUrl(Uri.parse(“http://www.wanandroid.com/user/login?username=1&password=123456”));
//3.关闭请求,等待响应
var response = await requset.close();
//4.进行解码,获取数据
if(response.statusCode == 200){
//拿到请求的数据
responseBody = await response.transform(utf8.decoder).join();
//先不解析打印数据
print(responseBody);
}else{
print(“error”);
}
}
返回结果如下:
2.dio请求
dio是一个强大的Dart Http
请求库,支持Restful API
、FormData
、拦截器、错误处理、转换器、设置Http代理、请求取消、Cookie
管理、文件上传和下载、超时等。在pub.flutter-io.cn/packages搜最新的依赖包,这个网址太好用,你想搜一些三方库里面都有:
在pubspec.yaml
添加依赖:
dio: ^2.0.14
导入依赖:
import ‘package:dio/dio.dart’;
2.1.get请求
//dio get请求
dio_get() async{
try{
Response response;
//等待返回response
response = await Dio().get(“http://gank.io/api/data/%E7%A6%8F%E5%88%A9/10/1”);
if(response.statusCode == 200){
print(response);
}else{
print(“error”);
}
}catch(e){
print(e);
}
}
2.2.post请求
dio_post() async{
try{
Response response;
response = await Dio().post(“http://www.wanandroid.com/user/login?username=1&password=123456”);
if(response.statusCode == 200){
print(response);
}else{
print(“error”);
}
}catch(e){
print(e);
}
}
效果同样是ok的。
3.http库
继续去上面链接搜最新的包,是http 0.12.0+1
,在pubspec.yaml
下添加依赖,在文件导入包:
import ‘package:http/http.dart’ as my_http;
上面这次导入库的方式有一点点区别,多了as
这个关键字,这是什么意思呢?通过as
是为了解决变量名冲突的方法,因为导入不同的库有可能遇到不同库之间因为导入变量名冲突的问题。
3.1.get请求
//http库的get请求方式
http_get() async{
try{
//因为导入http 用了as xxx方式,所以对象请求都用xxx.get方式
var response = await my_http.get(“http://gank.io/api/data/%E7%A6%8F%E5%88%A9/10/1”);
if(response.statusCode == 200){
//打印返回的数据
print(response.body);
}else{
print(“error”);
}
}catch(e){
print(e);
}
}
3.2.post请求
//http库的post请求方式
http_post() async{
try{
//因为导入http 用了as xxx方式,所以对象请求都用xxx.get方式
var response = await my_http.post(“http://www.wanandroid.com/user/login?username=1&password=123456”);
if(response.statusCode == 200){
//打印返回的数据
print(response.body);
}else{
print(“error”);
}
}catch(e){
print(e);
}
}
以上三种库的get
和psot
方式都实践了一遍,在平时开发中最好用dio
库和http
库,因为dart io
中是使用HttpClient
发起的请求,HttpClient
本身功能较弱,很多常用功能不支持。
七、JSON
现在很难想象移动应用程序不需要与后台交互或者存储结构化数据。现在开发,数据传输方式基本都是用JSON
,在Flutter
中是没有GSON/Jackson/Moshi
这些库,因为这些库需要运行时反射,在Flutter
是禁用的。运行时反射会干扰Dart
的_tree shaking_。使用_tree shaking_,可以在发版时"去除"未使用的代码,来优化软件的大小。由于反射会默认使用所有代码,因此_tree shaking_会很难工作,这些工具无法知道哪些widget
在运行时未被使用,因此冗余代码很难剥离,使用反射时,应用尺寸无法轻松进行优化,虽然不能在Flutter
使用运行时反射,但有些库提供了类型简单易用的API
,但它们是基于代码生成的。下面学学在Flutter
中如何操作JSON
数据的使用JSON
有两个常规策略:
- 手动序列化和反序列化
- 通过代码生成自动序列化和反序列化 不同的项目有不同的复杂度和场景,针对于小的项目,使用代码生成器可能会杀猪用牛刀了。对于具有多个
JSON model
的复杂应用程序,手动序列化可能会比较繁琐,且容易出错。
1.手动序列化JSON
Flutter
中基本的JSON序列化非常简单,Flutter
有一个内置的dart:convert
库,其中包含一个简单的JSON解码器和编码器。下面简单实现一下:
1.1.内连序列化JSON
首先记得导库:
import ‘dart:convert’;
然后根据字符串解析:
//内连序列化JSON
decodeJson() {
var data= ‘{“name”: “Knight”,“email”: “Knight@163.com”}’;
Map<String,dynamic> user = json.decode(data);
//输出名字
print(“Hello,my name is ${user[‘name’]}”);
//输出邮箱
print(“Hello,This is my email ${user[‘email’]}”);
}
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数Android工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!
由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新
如果你觉得这些内容对你有帮助,可以添加V获取:vip204888 (备注Android)
尾声
评论里面有些同学有疑问关于如何学习material design控件,我的建议是去GitHub搜,有很多同行给的例子,这些栗子足够入门。
有朋友说要是动真格的话,需要NDK以及JVM等的知识,首现**NDK并不是神秘的东西,**你跟着官方的步骤走一遍就知道什么回事了,无非就是一些代码格式以及原生/JAVA内存交互,进阶一点的有原生/JAVA线程交互,线程交互确实有点蛋疼,但平常避免用就好了,再说对于初学者来说关心NDK干嘛,据鄙人以前的经历,只在音视频通信和一个嵌入式信号处理(离线)的两个项目中用过,嵌入式信号处理是JAVA->NDK->.SO->MATLAB这样调用的我原来MATLAB的代码,其他的大多就用在游戏上了吧,一般的互联网公司会有人给你公司的SO包的。
至于JVM,该掌握的那部分,相信我,你会掌握的,不该你掌握的,有那些专门研究JVM的人来做,不如省省心有空看看计算机系统,编译原理。
一句话,平常多写多练,这是最基本的程序员的素质,尽量挤时间,读理论基础书籍,JVM不是未来30年唯一的虚拟机,JAVA也不一定再风靡未来30年工业界,其他的系统和语言也会雨后春笋冒出来,但你理论扎实会让你很快理解学会一个语言或者框架,你平常写的多会让你很快熟练的将新学的东西应用到实际中。
初学者,一句话,多练。
一个人可以走的很快,但一群人才能走的更远。如果你从事以下工作或对以下感兴趣,欢迎戳这里加入程序员的圈子,让我们一起学习成长!
AI人工智能、Android移动开发、AIGC大模型、C C#、Go语言、Java、Linux运维、云计算、MySQL、PMP、网络安全、Python爬虫、UE5、UI设计、Unity3D、Web前端开发、产品经理、车载开发、大数据、鸿蒙、计算机网络、嵌入式物联网、软件测试、数据结构与算法、音视频开发、Flutter、IOS开发、PHP开发、.NET、安卓逆向、云计算
栗子足够入门。
有朋友说要是动真格的话,需要NDK以及JVM等的知识,首现**NDK并不是神秘的东西,**你跟着官方的步骤走一遍就知道什么回事了,无非就是一些代码格式以及原生/JAVA内存交互,进阶一点的有原生/JAVA线程交互,线程交互确实有点蛋疼,但平常避免用就好了,再说对于初学者来说关心NDK干嘛,据鄙人以前的经历,只在音视频通信和一个嵌入式信号处理(离线)的两个项目中用过,嵌入式信号处理是JAVA->NDK->.SO->MATLAB这样调用的我原来MATLAB的代码,其他的大多就用在游戏上了吧,一般的互联网公司会有人给你公司的SO包的。
至于JVM,该掌握的那部分,相信我,你会掌握的,不该你掌握的,有那些专门研究JVM的人来做,不如省省心有空看看计算机系统,编译原理。
一句话,平常多写多练,这是最基本的程序员的素质,尽量挤时间,读理论基础书籍,JVM不是未来30年唯一的虚拟机,JAVA也不一定再风靡未来30年工业界,其他的系统和语言也会雨后春笋冒出来,但你理论扎实会让你很快理解学会一个语言或者框架,你平常写的多会让你很快熟练的将新学的东西应用到实际中。
初学者,一句话,多练。
一个人可以走的很快,但一群人才能走的更远。如果你从事以下工作或对以下感兴趣,欢迎戳这里加入程序员的圈子,让我们一起学习成长!
AI人工智能、Android移动开发、AIGC大模型、C C#、Go语言、Java、Linux运维、云计算、MySQL、PMP、网络安全、Python爬虫、UE5、UI设计、Unity3D、Web前端开发、产品经理、车载开发、大数据、鸿蒙、计算机网络、嵌入式物联网、软件测试、数据结构与算法、音视频开发、Flutter、IOS开发、PHP开发、.NET、安卓逆向、云计算