主頁 > 移動端開發 > Flutter 專案實戰 Dio網路請求 四

Flutter 專案實戰 Dio網路請求 四

2022-01-01 08:57:56 移動端開發

/ HTTP | HTTPS /

HTTP是一個客戶端(用戶)和 服務端(網站)之間請求和應答的標準,通常使用TCP協議,客戶端發起一個HTTP請求到服務器上指定埠(默認埠為80),客戶端 (用戶代理程式) 向應答服務器 (源服務器) 發起請求 , 從服務器獲取需要的資源 (包括 : 檔案、影像 、文本、視頻 等等) ,客戶端和服務端之間 可能存在多個中間層 (例如 : 代理服務器、網關) ,HTTP可以在任何互聯網協議或其他網路上實作 , 使用TCP作為其傳輸層 ,

?

請求方式

GET 請求

向服務端發起請求用于從服務端讀取資料 ,瀏覽器發出的GET只能由一個url觸發,GET上要在url之外帶一些引數就只能依靠url上附帶querystring,

使用場景

例如: https://host:port/path?querystring=value1&queryString=value2

https://tieba.baidu.com/f?ie=utf-8&kw=%E5%A4%A7%E4%BD%AC&fr=search

https://tieba.baidu.com/f?ie=utf-8&kw=%E5%A4%A7%E7%A5%9E&fr=search

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<MyHomePage> {
  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-browser?

HTTPS的主要作用是

對資料進行加密,并建立一個資訊安全通道,來保證傳輸程序中的資料安全

對網站服務器進行真實身份認證

SSL/TLS 協議采用非對稱加密方式,服務端會生成公鑰和私鑰,公鑰用來加密資訊,可以提供給所有需要進行通信的客戶端,私鑰保存在本地,不能泄露,客戶端使用這份公鑰對資訊進行加密,將請求發送給服務器,服務器用私鑰解密,反之,服務器對客戶端的回傳,則使用客戶端提供的公鑰進行加密,客戶端使用本地對應的私鑰來解密,保證了通信的安全,

基于 SSL/TLS 進行 一次的 HTTPS 會話的程序,簡單地說可以分成3步

客戶端向服務器端索要并驗證公鑰,

雙方協商生成”對話密鑰”,

雙方采用”對話密鑰”進行加密通信,

?

HTTP 協議采用明文傳輸資訊,存在資訊竊聽、資訊篡改和資訊劫持的風險,使用 HTTPS 則有以下幾個方面的優勢:

保護站點安全、保護用戶隱私、未來的趨勢所在

升級HTTPS :

獲取證書、在服務器安裝證書、重定向配置、修改資源鏈接

/ 網路請求神器DIO /

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<Interceptor>? 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,
    data,
    Map<String, dynamic>? params,
    Options? options,
    HttpSuccessCallback? successCallback,
    HttpFailureCallback? errorCallback,
    @required String? tag,
  }) async {
    //檢查網路是否連接
    ConnectivityResult connectivityResult =
        await (Connectivity().checkConnectivity());
    if (connectivityResult == ConnectivityResult.none) {
      if (errorCallback != null) {
        errorCallback(HttpError(HttpError.NETWORK_ERROR, "網路例外,請稍后重試!"));
      }
      return;
    }
    //設定默認值
    params = params ?? {};
    method = method ?? 'GET';
    options?.method = method;
    options = options ?? Options(method: method,);
    ///請求頭
    options.headers = await _headers();
    try {
      CancelToken cancelToken;
      cancelToken =
          (_cancelTokens[tag] == null ? CancelToken() : _cancelTokens[tag])!;
      _cancelTokens[tag!] = cancelToken;
      Response response = await _client!.request(url!,
          data: data,
          queryParameters: params,
          options: options,
          cancelToken: cancelToken);
      var _responseData = response.data;
      print('回應的資料:$_responseData');
      int statusCode = _responseData["code"];
      if (statusCode == 200) {
        //成功
        successCallback!(_responseData["data"]);
      } else {
        //失敗
        String message = _responseData["msg"].toString();
        errorCallback!(HttpError('$statusCode', message));
      }
    } on DioError catch (e, s) {
      if (e.type != DioErrorType.cancel) {
        errorCallback!(HttpError.dioError(e));
      }
    } catch (e, s) {
      errorCallback!(HttpError(HttpError.UNKNOWN, "未知錯誤,請稍后重試!"));
    }
  }

取消網路請求、自定義header

 ///取消網路請求
   ///取消網路請求
  void cancel(String tag) {

    print('取消網路請求前 cancelToken集合$_cancelTokens');

    if (_cancelTokens.containsKey(tag)) {
      if (!_cancelTokens[tag]!.isCancelled) {
        _cancelTokens[tag]!.cancel();
      }
      _cancelTokens.remove(tag);

      print('取消網路請求后 cancelToken集合$_cancelTokens');
    }


  }

  ///請求頭
  Future<Map<String, String>> _headers() async {
    Map<String, String> _headers = new HashMap();
    String _token = '';
    _headers.addAll({"token": _token});
    return _headers;
  }

GET 請求

 ///Get網路請求
  ///
  ///[url] 網路請求地址不包含域名
  ///[params] url請求引數支持restful
  ///[options] 請求配置
  ///[successCallback] 請求成功回呼
  ///[errorCallback] 請求失敗回呼
  ///[tag] 請求統一標識,用于取消網路請求
  get({
    required String url,
    required Map<String, dynamic> params,
    Options? options,
    required HttpSuccessCallback successCallback,
    required HttpFailureCallback errorCallback,
    required String tag,
  }) async {
    return _request(
      url: url,
      params: params,
      method: 'get',
      options: options,
      successCallback: successCallback,
      errorCallback: errorCallback,
      tag: tag,
    );
  }

發起GET請求

class _MyHomePageState extends State<MyHomePage> {
  var _tag;
  void _testDioHeadReq() async {
    _tag = '${{DateTime.now().millisecondsSinceEpoch}}';
    HttpManager().get(
        url: '',
        params: {},
        successCallback: (_data) {
          print('回應資料:$_data');
          ///取消請求
          HttpManager().cancel(_tag);
        },
        errorCallback: (_data) {
          print('回應資料錯誤:$_data');
        },

        ///請求tag可以用時間戳進行定義
        tag: '$_tag');

  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: _testDioHeadReq,
        tooltip: 'TestDioHeadReq',
        child: Icon(Icons.add),
      ),
    );
  }
}

請求結果 :

POST 請求

///post網路請求
  ///[url] 網路請求地址不包含域名
  ///[data] post 請求引數
  ///[params] url請求引數支持restful
  ///[options] 請求配置
  ///[successCallback] 請求成功回呼
  ///[errorCallback] 請求失敗回呼
  ///[tag] 請求統一標識,用于取消網路請求
  void post({
    String? url,
    data,
    Map<String, dynamic>? params,
    Options? options,
    HttpSuccessCallback? successCallback,
    HttpFailureCallback? errorCallback,
    @required String? tag,
  }) async {
    _request(
      url: url!,
      data: data,
      method: POST,
      params: params!,
      options: options!,
      successCallback: successCallback!,
      errorCallback: errorCallback!,
      tag: tag!,
    );
  }

修改main()函式初始化 網路請求域名前綴 (BaseUrl)

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]);
  await SystemChrome.setEnabledSystemUIOverlays(SystemUiOverlay.values);

  ///網路請求管理初始化
  HttpManager().init(baseUrl: 'https://tieba.baidu.com/f');
  runApp(MyApp());
}
var _tag;
  void _testDioHeadReq() async {
    _tag = '${{DateTime.now().millisecondsSinceEpoch}}';
    HttpManager().post(
        url: '',
        params: {'ie':'utf-8','kw':'大佬','fr':'search'},
        successCallback: (_data) {
          print('回應資料:$_data');
          ///取消請求
          HttpManager().cancel(_tag);
        },
        errorCallback: (_data) {
          print('回應資料錯誤:$_data');
        },

        ///請求tag可以用時間戳進行定義
        tag: '$_tag');

  }

請求結果 :

flutter_test_dio案例下載

后續

接下來的日子,我會在博客里面演練MVC、MVP、MVVM與Dio結合進行網路請求

參考HTTP狀態碼

Flutter實戰MVC、MVP、MVVM

轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/399589.html

標籤:其他

上一篇:Android【SQLite資料庫存盤】

下一篇:Android【GridView使用】

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 【從零開始擼一個App】Dagger2

    Dagger2是一個IOC框架,一般用于Android平臺,第一次接觸的朋友,一定會被搞得暈頭轉向。它延續了Java平臺Spring框架代碼碎片化,注解滿天飛的傳統。嘗試將各處代碼片段串聯起來,理清思緒,真不是件容易的事。更不用說還有各版本細微的差別。 與Spring不同的是,Spring是通過反射 ......

    uj5u.com 2020-09-10 06:57:59 more
  • Flutter Weekly Issue 66

    新聞 Flutter 季度調研結果分享 教程 Flutter+FaaS一體化任務編排的思考與設計 詳解Dart中如何通過注解生成代碼 GitHub 用對了嗎?Flutter 團隊分享如何管理大型開源專案 插件 flutter-bubble-tab-indicator A Flutter librar ......

    uj5u.com 2020-09-10 06:58:52 more
  • Proguard 常用規則

    介紹 Proguard 入口,如何查看輸出,如何使用 keep 設定入口以及使用實體,如何配置壓縮,混淆,校驗等規則。

    ......

    uj5u.com 2020-09-10 06:59:00 more
  • Android 開發技術周報 Issue#292

    新聞 Android即將獲得類AirDrop功能:可向附近設備快速分享檔案 谷歌為安卓檔案管理應用引入可安全隱藏資料的Safe Folder功能 Android TV新主界面將顯示電影、電視節目和應用推薦內容 泄露的Android檔案暗示了傳說中的谷歌Pixel 5a與折疊屏新機 谷歌發布Andro ......

    uj5u.com 2020-09-10 07:00:37 more
  • AutoFitTextureView Error inflating class

    報錯: Binary XML file line #0: Binary XML file line #0: Error inflating class xxx.AutoFitTextureView 解決: <com.example.testy2.AutoFitTextureView android: ......

    uj5u.com 2020-09-10 07:00:41 more
  • 根據Uri,Cursor沒有獲取到對應的屬性

    Android: 背景:呼叫攝像頭,拍攝視頻,指定保存的地址,但是回傳的Cursor檔案,只有名稱和大小的屬性,沒有其他諸如時長,連ID屬性都沒有 使用 cursor.getInt(cursor.getColumnIndexOrThrow(MediaStore.Video.Media.DURATIO ......

    uj5u.com 2020-09-10 07:00:44 more
  • Android連載29-持久化技術

    一、持久化技術 我們平時所使用的APP產生的資料,在記憶體中都是瞬時的,會隨著斷電、關機等丟失資料,因此android系統采用了持久化技術,用于存盤這些“瞬時”資料 持久化技術包括:檔案存盤、SharedPreference存盤以及資料庫存盤,還有更復雜的SD卡記憶體儲。 二、檔案存盤 最基本存盤方式, ......

    uj5u.com 2020-09-10 07:00:47 more
  • Android Camera2Video整合到自己專案里

    背景: Android專案里呼叫攝像頭拍攝視頻,原本使用的 MediaStore.ACTION_VIDEO_CAPTURE, 后來因專案需要,改成了camera2 1.Camera2Video 官方demo有點問題,下載后,不能直接整合到專案 問題1.多次拍攝視頻崩潰 問題2.雙擊record按鈕, ......

    uj5u.com 2020-09-10 07:00:50 more
  • Android 開發技術周報 Issue#293

    新聞 谷歌為Android TV開發者提供多種新功能 Android 11將自動填表功能整合到鍵盤輸入建議中 谷歌宣布Android Auto即將支持更多的導航和數字停車應用 谷歌Pixel 5只有XL版本 搭載驍龍765G且將比Pixel 4更便宜 [圖]Wear OS將迎來重磅更新:應用啟動時間 ......

    uj5u.com 2020-09-10 07:01:38 more
  • 海豚星空掃碼投屏 Android 接收端 SDK 集成 六步驟

    掃碼投屏,開放網路,獨占設備,不需要額外下載軟體,微信掃碼,發現設備。支持標準DLNA協議,支持倍速播放。視頻,音頻,圖片投屏。好點意思。還支持自定義基于 DLNA 擴展的操作動作。好像要收費,沒體驗。 這里簡單記錄一下集成程序。 一 跟目錄的build.gradle添加私有mevan倉庫 mave ......

    uj5u.com 2020-09-10 07:01:43 more
最新发布
  • 歡迎頁輪播影片

    如圖,引導開始,球從上落下,同時淡入文字,然后文字開始輪播,最后一頁時停止,點擊進入首頁。 在來看看效果圖。 重力球先不講,主要歡迎輪播簡單實作 首先新建一個類 TextTranslationXGuideView,用于影片展示 文本是類似的,最后會有個圖片箭頭影片,布局很簡單,就是一個 TextVi ......

    uj5u.com 2023-04-20 08:40:31 more
  • 【FAQ】關于華為推送服務因營銷訊息頻次管控導致服務通訊類訊息

    一. 問題描述 使用華為推送服務下發IM訊息時,下發訊息請求成功且code碼為80000000,但是手機總是收不到訊息; 在華為推送自助分析(Beta)平臺查看發現,訊息發送觸發了頻控。 二. 問題原因及背景 2023年1月05日起,華為推送服務對咨詢營銷類訊息做了單個設備每日推送數量上限管理,具體 ......

    uj5u.com 2023-04-20 08:40:11 more
  • 歡迎頁輪播影片

    如圖,引導開始,球從上落下,同時淡入文字,然后文字開始輪播,最后一頁時停止,點擊進入首頁。 在來看看效果圖。 重力球先不講,主要歡迎輪播簡單實作 首先新建一個類 TextTranslationXGuideView,用于影片展示 文本是類似的,最后會有個圖片箭頭影片,布局很簡單,就是一個 TextVi ......

    uj5u.com 2023-04-20 08:39:36 more
  • 【FAQ】關于華為推送服務因營銷訊息頻次管控導致服務通訊類訊息

    一. 問題描述 使用華為推送服務下發IM訊息時,下發訊息請求成功且code碼為80000000,但是手機總是收不到訊息; 在華為推送自助分析(Beta)平臺查看發現,訊息發送觸發了頻控。 二. 問題原因及背景 2023年1月05日起,華為推送服務對咨詢營銷類訊息做了單個設備每日推送數量上限管理,具體 ......

    uj5u.com 2023-04-20 08:39:13 more
  • iOS從UI記憶體地址到讀取成員變數(oc/swift)

    開發除錯時,我們發現bug時常首先是從UI顯示發現例外,下一步才會去定位UI相關連的資料的。XCode有給我們提供一系列debug工具,但是很多人可能還沒有形成一套穩定的除錯流程,因此本文嘗試解決這個問題,順便提出一個暴論:UI顯示例外問題只需要兩個步驟就能完成定位作業的80%: 定位例外 UI 組 ......

    uj5u.com 2023-04-19 09:16:23 more
  • FIDE重磅更新!性能飛躍!體驗有禮!

    FIDE 開發者工具重構升級啦!實作500%性能提升,誠邀體驗! 一直以來不少開發者朋友在社區反饋,在使用 FIDE 工具的程序中,時常會遇到諸如加載不及時、代碼預覽/渲染性能不如意的情況,十分影響開發體驗。 作為技術團隊,我們深知一件趁手的開發工具對開發者的重要性,因此,在2023年開年,FinC ......

    uj5u.com 2023-04-19 09:16:15 more
  • 游戲內嵌社區服務開放,助力開發者提升玩家互動與留存

    華為 HMS Core 游戲內嵌社區服務提供快速訪問華為游戲中心論壇能力,支持玩家直接在游戲內瀏覽帖子和交流互動,助力開發者擴展內容生產和觸達的場景。 一、為什么要游戲內嵌社區? 二、游戲內嵌社區的典型使用場景 1、游戲內打開論壇 您可以在游戲內繪制論壇入口,為玩家提供沉浸式發帖、瀏覽、點贊、回帖、 ......

    uj5u.com 2023-04-19 09:15:46 more
  • iOS從UI記憶體地址到讀取成員變數(oc/swift)

    開發除錯時,我們發現bug時常首先是從UI顯示發現例外,下一步才會去定位UI相關連的資料的。XCode有給我們提供一系列debug工具,但是很多人可能還沒有形成一套穩定的除錯流程,因此本文嘗試解決這個問題,順便提出一個暴論:UI顯示例外問題只需要兩個步驟就能完成定位作業的80%: 定位例外 UI 組 ......

    uj5u.com 2023-04-19 09:14:53 more
  • FIDE重磅更新!性能飛躍!體驗有禮!

    FIDE 開發者工具重構升級啦!實作500%性能提升,誠邀體驗! 一直以來不少開發者朋友在社區反饋,在使用 FIDE 工具的程序中,時常會遇到諸如加載不及時、代碼預覽/渲染性能不如意的情況,十分影響開發體驗。 作為技術團隊,我們深知一件趁手的開發工具對開發者的重要性,因此,在2023年開年,FinC ......

    uj5u.com 2023-04-19 09:14:08 more
  • 游戲內嵌社區服務開放,助力開發者提升玩家互動與留存

    華為 HMS Core 游戲內嵌社區服務提供快速訪問華為游戲中心論壇能力,支持玩家直接在游戲內瀏覽帖子和交流互動,助力開發者擴展內容生產和觸達的場景。 一、為什么要游戲內嵌社區? 二、游戲內嵌社區的典型使用場景 1、游戲內打開論壇 您可以在游戲內繪制論壇入口,為玩家提供沉浸式發帖、瀏覽、點贊、回帖、 ......

    uj5u.com 2023-04-19 09:08:34 more