总结
最后为了帮助大家深刻理解Android相关知识点的原理以及面试相关知识,这里放上相关的我搜集整理的14套腾讯、字节跳动、阿里、百度等2021最新面试真题解析,我把技术点整理成了视频和PDF(实际上比预期多花了不少精力),包知识脉络 + 诸多细节。
网上学习 Android的资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
https://tieba.baidu.com/f?ie=utf-8&kw=%E7%BE%8E%E5%A5%B3&fr=search
https://tieba.baidu.com/f?ie=utf-8&kw=%E5%B8%85%E5%93%A5&fr=search
class MyHomePage extends StatefulWidget {
MyHomePage({Key? key, required this.title}) : super(key: key);
final String title;
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State {
void _testDioHeadReq() async {
Response _headReq = await Dio().get(‘https://www.baidu.com/’);
print(‘HEAD请求获取到到 数据:${_headReq.data}\n’);
print(‘HEAD请求获取到到 extra:${_headReq.extra}\n’);
print(‘HEAD请求获取到到 headers:${_headReq.headers}\n’);
print(‘HEAD请求获取到到 isRedirect:${_headReq.isRedirect}\n’);
print(‘HEAD请求获取到到 statusCode:${_headReq.statusCode}\n’);
print(‘HEAD请求获取到到 statusMessage:${_headReq.statusMessage}\n’);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
floatingActionButton: FloatingActionButton(
onPressed: _testDioHeadReq,
tooltip: ‘TestDioHeadReq’,
child: Icon(Icons.add),
),
);
}
}
HEAD
向服务端发起请求用于从服务端读取数据 。与GET的区别就是不会获取到数据 (响应体) , 只会获取到请求头 (header) 、状态码 (statusCode)、提示信息 (statusMessage) 等 响应头
HEAD请求常常被忽略,但是能提供很多有用的信息,特别是在有限的速度和带宽下。主要有以下特点:只请求资源的首部 、检查超链接的有效性 、检查网页是否被修改
多用于自动搜索机器人获取网页的标志信息,获取rss种子信息,或者传递安全认证信息等
Response _headReq = await Dio().head(‘https://www.baidu.com/’);
print(‘HEAD请求获取到到 数据:${_headReq.data}\n’);
print(‘HEAD请求获取到到 extra:${_headReq.extra}\n’);
print(‘HEAD请求获取到到 headers:${_headReq.headers}\n’);
print(‘HEAD请求获取到到 isRedirect:${_headReq.isRedirect}\n’);
print(‘HEAD请求获取到到 statusCode:${_headReq.statusCode}\n’);
print(‘HEAD请求获取到到 statusMessage:${_headReq.statusMessage}\n’);
POST 请求
向指定资源提交数据 , 请求服务器处理 (例如提交表单或者上传文件) 。数据被包含在请求体中 , 数据被包含在请求本文中。这个请求可能会创建新的资源或修改现有资源 。表单数据被浏览器编码到body里然后发送请求 。
body主要有四种格式 :
application/x-www-form-urlencode (传递简单数据 / 格式 : 是"key1=value1&key2=value2") ,对于二进制文件这种数据的传输效率很低 。默认传递数据的格式 。消息包大,耗流量 。
try {
Response _headReq = await Dio().post(
///请求地址
‘https://tieba.baidu.com/f’,
///请求参数
data: {‘ie’: ‘utf-8’, ‘kw’: ‘大佬’, ‘fr’: ‘search’},
///请求头
options: new Options(
contentType: Headers.formUrlEncodedContentType,
),
);
print(‘HEAD请求获取到到 数据:${_headReq.data}\n’);
print(‘HEAD请求获取到到 extra:${_headReq.extra}\n’);
print(‘HEAD请求获取到到 headers:${_headReq.headers}\n’);
print(‘HEAD请求获取到到 isRedirect:${_headReq.isRedirect}\n’);
print(‘HEAD请求获取到到 statusCode:${_headReq.statusCode}\n’);
print(‘HEAD请求获取到到 statusMessage:${_headReq.statusMessage}\n’);
} catch (e) {
print(‘请求异常:’ + e.toString());
}
multipart/form-data
multipart/form-data
定义在 rfc2388 中 , 用以支持向服务器发送二进制数据。这种编码方式,通常是用在客户端向服务端传送大文件数据,如:图片或者文件。
boundary 是一个占位符,代表我们规定的具体分割符;可以自己任意规定,但为了避免和正常文本重复了。
Boundary 参数设置注意事项:
必须以英文中间双横杠--
开头,这个--
称为前导连字符
除了前导连字符以外的部分不能超过70
个字符
不能包含HTTP
协议或者URL
禁用的特殊意义的字符,例如英文冒号(:
)等
FormData _formData = new FormData.fromMap({
‘file’: await MultipartFile.fromFile(
///手机存储卡上图片路径
‘filePath’,
///图片名称
filename: ‘fileName’,
),
});
Response _headReq = await Dio().post(‘url’,
data: _formData,
options: Options(method: ‘POST’, contentType: ‘multipart/form-data;boundary=xxxx’));
print(‘HEAD请求获取到到 数据:${_headReq.data}\n’);
application/json
客户端向服务端传递序列化的JSON字符串。方便的提交复杂的结构化数据,特别适合 RESTful 的接口。各大抓包工具如 Chrome 自带的开发者工具、Firebug、Fiddler,都会以树形结构展示 JSON 数据,非常友好。
Response _headReq = await Dio().post(‘https://www.wanandroid.com’,
data: {‘username’: ‘’, ‘password’: ‘’,},
options: Options(contentType: ‘application/json’,),);
print(‘HEAD请求获取到到 数据:${_headReq.data}\n’);
text/xml
传输和存储数据,它非常适合万维网传输。以纯文本形式进行编码,其中不包含任何控件或格式字符, 大部分情况不会使用 。
PUT 请求
创建或者替换目标资源 。put调用一次和多次是等价的。而连续调用多次POST方法可能会有副作用,比如将一个订单重复提交多次。
DELETE 请求
向服务端请求删除某个已存在的资源 。
CONNECT
HTTP 协议中,CONNECT
方法可以开启一个客户端与所请求资源之间的双向沟通的通道 。
connect是为了建立http tunnel , 只有在受限制的网络环境中(防火墙、NAT、代理器)并且是https通信时,客户端使用http connect请求代理服务器,代理服务器使用connect方法与目标服务器建立http tunnel,通道建立后,客户端与服务器进行通信,代理服务器就像透明一样,只是接收、转发tcp stream。
建立http tunnel 的理由 ?
这是因为,网络环境受限,客户端无法直接访问某些网络,所以只能通过代理服务器访问网络,然后,将内容转发给客户端,从宏观上看,客户端与服务器端就像建立了一条隧道一样。
但是由于http tunnnel可控性不强,所以,服务器通常会限制"可connect的端口"(一般只开放SSL的443端口)
HTTPS (HTTP over SSL/TLS) 是 HTTP 的安全版本,在 HTTP 上加了一层处理加密信息的模块。SSL/TLS 全称安全传输层协议 Transport Layer Security, 是介于 TCP 和 HTTP 之间的一层安全协议,不影响原有的 TCP 协议和 HTTP 协议,所以使用HTTPS基本上不需要对 HTTP 页面进
行太多的改造。浏览器访问支持 HTTPS 的站点时,在地址栏的前面会有一把绿色的锁一样的标
识,表明 HTTPS 生效了。
HTTPS的主要作用是
对数据进行加密,并建立一个信息安全通道,来保证传输过程中的数据安全
对网站服务器进行真实身份认证
SSL/TLS 协议采用非对称加密方式,服务端会生成公钥和私钥,公钥用来加密信息,可以提供给所有需要进行通信的客户端,私钥保存在本地,不能泄露。客户端使用这份公钥对信息进行加密,将请求发送给服务器,服务器用私钥解密。反之,服务器对客户端的返回,则使用客户端提供的公钥进行加密,客户端使用本地对应的私钥来解密,保证了通信的安全。
基于 SSL/TLS 进行 一次的 HTTPS 会话的过程,简单地说可以分成3步
客户端向服务器端索要并验证公钥。
双方协商生成”对话密钥”。
双方采用”对话密钥”进行加密通信。
HTTP 协议采用明文传输信息,存在信息窃听、信息篡改和信息劫持的风险,使用 HTTPS 则有以下几个方面的优势:
保护站点安全、保护用户隐私、未来的趋势所在
升级HTTPS :
获取证书、在服务器安装证书、重定向配置、修改资源链接
pubspec.yaml 文件配置dio插件依赖
dio版本号建议配置成any , 以后即便更新了flutter sdk 也不用手动去配置版本号
查看flutter sdk、dart sdk 版本号
网络请求创建 单利模式
确保某一个类只有一个实例,而且自行实例化并向整个应用提供这个实例。
适用于
全局日志的 Logger 类、应用全局的配置数据对象类,单业务管理类。
创建实例时占用资源较多,或实例化耗时较长的类。
等等…
class HttpManager {
///存储网络请求的token,方便网络请求完成后取消网络请求
Map<String, CancelToken> _cancelTokens = Map<String, CancelToken>();
///超时时间
static const int CONNECT_TIMEOUT = 30000;
static const int RECEIVE_TIMEOUT = 30000;
Dio? _client;
static final HttpManager _instance = HttpManager._internal();
factory HttpManager() => _instance;
Dio get client => _client!;
/// 创建 dio 实例对象
HttpManager._internal() {
if (_client == null) {
/// 全局属性:请求前缀、连接超时时间、响应超时时间
BaseOptions options = BaseOptions(
connectTimeout: CONNECT_TIMEOUT,
receiveTimeout: RECEIVE_TIMEOUT,
);
_client = Dio(options);
}
}
}
创建网络请求HttpError
通过网络请求状态码来提示用户 (网络错误、解析错误、证书错误、协议错误、响应超时、发送超时、网络请求错误 等…)
/// 网络请求错误
class HttpError {
///HTTP 状态码
static const int UNAUTHORIZED = 401;
static const int FORBIDDEN = 403;
static const int NOT_FOUND = 404;
static const int REQUEST_TIMEOUT = 408;
static const int INTERNAL_SERVER_ERROR = 500;
static const int BAD_GATEWAY = 502;
static const int SERVICE_UNAVAILABLE = 503;
static const int GATEWAY_TIMEOUT = 504;
///未知错误
static const String UNKNOWN = “UNKNOWN”;
///解析错误
static const String PARSE_ERROR = “PARSE_ERROR”;
///网络错误
static const String NETWORK_ERROR = “NETWORK_ERROR”;
///协议错误
static const String HTTP_ERROR = “HTTP_ERROR”;
///证书错误
static const String SSL_ERROR = “SSL_ERROR”;
///连接超时
static const String CONNECT_TIMEOUT = “CONNECT_TIMEOUT”;
///响应超时
static const String RECEIVE_TIMEOUT = “RECEIVE_TIMEOUT”;
///发送超时
static const String SEND_TIMEOUT = “SEND_TIMEOUT”;
///网络请求取消
static const String CANCEL = “CANCEL”;
String? code;
String? message;
HttpError(this.code, this.message);
HttpError.dioError(DioError error) {
message = error.message;
switch (error.type) {
case DioErrorType.connectTimeout:
code = CONNECT_TIMEOUT;
message = “网络连接超时,请检查网络设置”;
break;
case DioErrorType.receiveTimeout:
code = RECEIVE_TIMEOUT;
message = “服务器异常,请稍后重试!”;
break;
case DioErrorType.sendTimeout:
code = SEND_TIMEOUT;
message = “网络连接超时,请检查网络设置”;
break;
case DioErrorType.response:
code = HTTP_ERROR;
message = “服务器异常,请稍后重试!”;
break;
case DioErrorType.cancel:
code = CANCEL;
message = “请求已被取消,请重新请求”;
break;
case DioErrorType.other:
code = UNKNOWN;
message = “未知错误,请稍后重试!”;
break;
}
}
@override
String toString() {
return ‘HttpError{code: $code, message: $message}’;
}
}
main()函数初始化 网络请求公共参数
///初始化公共属性
///
/// [baseUrl] 地址前缀
/// [connectTimeout] 连接超时赶时间
/// [receiveTimeout] 接收超时赶时间
/// [interceptors] 基础拦截器
void init(
{String? baseUrl,
int? connectTimeout,
int? receiveTimeout,
List? interceptors}) {
_client?.options = _client!.options.copyWith(
baseUrl: baseUrl,
connectTimeout: connectTimeout,
receiveTimeout: receiveTimeout,
);
if (interceptors != null && interceptors.isNotEmpty) {
_client!.interceptors…addAll(interceptors);
}
}
void main() async{
WidgetsFlutterBinding.ensureInitialized();
await SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]);
await SystemChrome.setEnabledSystemUIOverlays(SystemUiOverlay.values);
///网络请求管理初始化
HttpManager().init(baseUrl: ‘网络请求域名前缀’);
runApp(MyApp());
}
创建POST和GET统一网络请求
///统一网络请求
///[url] 网络请求地址不包含域名
///[data] post 请求参数
///[params] url请求参数支持restful
///[options] 请求配置
///[successCallback] 请求成功回调
///[errorCallback] 请求失败回调
///[tag] 请求统一标识,用于取消网络请求
void _request({
String? url,
String? method,
尾声
最后,我再重复一次,如果你想成为一个优秀的 Android 开发人员,请集中精力,对基础和重要的事情做深度研究。
对于很多初中级Android工程师而言,想要提升技能,往往是自己摸索成长,不成体系的学习效果低效漫长且无助。 整理的这些架构技术希望对Android开发的朋友们有所参考以及少走弯路,本文的重点是你有没有收获与成长,其余的都不重要,希望读者们能谨记这一点。
这里,笔者分享一份从架构哲学的层面来剖析的视频及资料分享给大家梳理了多年的架构经验,筹备近6个月最新录制的,相信这份视频能给你带来不一样的启发、收获。
Android进阶学习资料库
一共十个专题,包括了Android进阶所有学习资料,Android进阶视频,Flutter,java基础,kotlin,NDK模块,计算机网络,数据结构与算法,微信小程序,面试题解析,framework源码!
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
于取消网络请求
void _request({
String? url,
String? method,
尾声
最后,我再重复一次,如果你想成为一个优秀的 Android 开发人员,请集中精力,对基础和重要的事情做深度研究。
对于很多初中级Android工程师而言,想要提升技能,往往是自己摸索成长,不成体系的学习效果低效漫长且无助。 整理的这些架构技术希望对Android开发的朋友们有所参考以及少走弯路,本文的重点是你有没有收获与成长,其余的都不重要,希望读者们能谨记这一点。
这里,笔者分享一份从架构哲学的层面来剖析的视频及资料分享给大家梳理了多年的架构经验,筹备近6个月最新录制的,相信这份视频能给你带来不一样的启发、收获。
[外链图片转存中…(img-1t24f6lT-1715887029873)]
Android进阶学习资料库
一共十个专题,包括了Android进阶所有学习资料,Android进阶视频,Flutter,java基础,kotlin,NDK模块,计算机网络,数据结构与算法,微信小程序,面试题解析,framework源码!
[外链图片转存中…(img-4xNyrvSi-1715887029874)]
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!