Taolin的博客

生命不息 奋斗不止


  • 首页

  • 归档

  • 分类

  • 标签

  • 关于

Flutter PlatformView避坑指南 —— UI刷新

发表于 2022-02-25   |   分类于 flutter   |  

本文记录在flutter中嵌入原生系统时view遇到的刷新问题和尝试过的解决方案。

1. 什么是Platform view ?

由于 Flutter 诞生于 Android 、iOS 非常成熟的时代背景,为了能让一些现有的 native 控件直接引用到 Flutter app 中,Flutter 团队提供了 AndroidView 、UIKitView 两个 widget 来满足需求,比如说 Flutter 中的 Webview、MapView,这样无需使用 Flutter 重新开发一套。


其实 Platform view 就是 AndroidView 和 UIKitView 的总称,允许将 native view 嵌入到了 flutter widget 体系中,完成 Dart 代码对 native view 的控制。

2. 使用Platform view遇到的问题

项目中需要实现视频通话的功能,效果见下图。由于使用的视频通话sdk没有flutter版本的,且sdk只提供渲染后的视图view,不提供视频数据。所以只能考虑在flutter中嵌入原生系统Platform view。

实现步骤以Android平台为例,我们需要先对视频通话sdk进行一次封装以便flutter层能调用。
首先在原生系统层将视频通话视图列表缓存到一个列表中,列表的每个item包含一个通话视图、视图id及其他信息,通话视图通过Platformview的方式暴露给flutter层。
然后把每个视图的id列表,通过MethodChannel的方式传递给flutter层。flutter层获取到视图的id列表,通过给Platformview传递视图id来获取某个item的通话视图,再将该视图显示到具体的位置。

实际测试发现,视频通话列表可以正常显示,但在列表数量变化时(比如有人加入了视频通话),视图列表出现错乱。

异常log如下:

03.png

从log可以看到,报错是因为flutter加载原生view时,该原生view还被另一个父view引用;Android中规定一个view只能有一个父view,所以这里报错。

阅读全文 »

Android应用静默安装实现方案

发表于 2020-06-05   |   分类于 android   |  

Android系统为了保证用户的体验,随着SDK版本的增加,对应用的权限控制越来越严;其中对应用静默安装这块体现的很明显。

下面就介绍从Android7.0以下到Android9.0以上,如何一步步的绕开Android系统的限制,实现app的静默安装。

1. 通过shell命令安装

1.1. Android7.0以下

Android7.0以下,用下面的shell命令通过adb调用或者代码中调用,都能正常运行,需要注意的是apk的路径必须是绝对路径

pm install -r -d /sdcard/Download/demo.apk

1.2. Android7.0到Android9.0以下

应用安装的限制有所加强,通过adb shell安装命令如下,跟Android7.0以下一样

pm install -r -d /sdcard/Download/demo.apk

但是在代码中调用就不一样,需要用-i参数指定一个系统进程来安装,如下com.android.settings是一个系统应用

pm install -r -d -i com.android.settings /sdcard/Download/demo.apk

1.3. Android9.0及以上

阅读全文 »

Android系统卡顿如何优化

发表于 2020-06-04   |   分类于 android   |  

1. 问题背景

在某次对Android系统测试中,出现系统响应比较慢,操作卡顿的情况。

操作卡顿,第一反应当然是看看CPU和内存的消耗是否正常,根据命令打印显示,CPU偶尔占用比较高,内存消耗也不算太高,分析了本地的log记录,也没有看出什么问题。

只能试着重现问题,看出现问题的概率高不高,如果不高的话,可能考虑此问题先放一放。

2. 问题复现 — monkey压测

压测使用的工具是monkey,它可以对整个系统或指定的单个应用进行随机的压力测试。

如下的脚本是分别对白板和设置进行monkey压测

  • -p 指定测试的App包名
  • – ignore开头的参数,是测试过程中忽略掉对应的事件
  • – throttle 是执行每次测试的间隔时间,太快的话,可能会导致系统响应不过来,容易引起anr
  • -v -v -v 三个v,表示记录最详细的日志
  • 最后面的数字代表要测试的次数
  • nohup 最后加一个&,是指脚本在后台运行
# 比如对设置压测
nohup monkey -p com.android.settings --ignore-crashes --ignore-timeouts --ignore-native-crashes --ignore-security-exceptions --throttle 100 -v -v -v 1000000 &

通过使用monkey压测,确实能复现系统卡顿的问题,但接下来不知道怎么分析。遂去咨询系统开发的同事,他们分析了一些系统参数后,结合以往的经验,提出是因为系统产生了大量的内存碎片,这些内存碎片虽然是可用内存,但是内存空间不连续,无法被系统直接使用,导致内存不足,系统卡顿。

3. 内存分布 — buddyinfo

系统开发的同事提出是因为系统产生了大量的内存碎片导致卡顿,但需要进一步验证才能确定。
通过cat /proc/buddyinfo 可以查看系统当前的内存分布情况

阅读全文 »

kotlin协程入门

发表于 2020-06-04   |   分类于 kotlin   |  

1. 认识协程

1.1 进程

早期的计算机运行程序还是只能一次运行一个任务,之后进程的出现实现了近似同步的执行效果,其本质上是程序的交替执行。为了保证进程中的程序能够正常执行,还会有一些存储进程状态的保存集。随着硬件的发展和多CPU的出现,能够同时执行的进程数量逐渐增多。这就带来了一个问题,即用来存储进程状态的集合所占用的资源比一个进程可以执行的资源还要多,相当于整个系统大半的进行都是用来保存进程的状态。

1.2 线程

线程的提出有效的解决了这个问题。进程不再频繁的切换,而是先执行,遇到阻塞的话暂时不管,继续执行其他的任务,当其他任务执行完之后再回过头来看阻塞任务是否执行完。多线程的缺陷在于无法自主控制调度,除开一定会执行的主线程之外,其他线程的执行顺序都无法控制,在Java上是由Java虚拟机调度,其他平台大多是由系统控制。

1.3 协程

线程执行过程中发生线程切换的时候会损耗一定的资源,这部分资源用来保存线程的状态。执行过程中如果发生了磁盘读写或网络请求这样的IO操作的时候线程的执行会被阻塞,但同时该线程还会持有CPU资源,这就造成了一定了资源浪费。理想的情况是在发送阻塞的时候,该线程主动交出CPU给其他线程使用或者给内部的其他任务。

这种方式其实就是协程的体系。通过提升CPU利用率,减少线程切换,进而提升程序运行效率。

延伸开来协程主要有三个特性。

  • 第一个是可控制,不同于线程协程能做到可被控制的发起子任务;
  • 第二个是轻量级,协程非常小、占用资源比线程还少,在JVM平台上它的本质就是一次方法的调用;
  • 第三个是语法糖,目前能够使用协程的语言都提供了很好的语法糖支持,使多任务或多线程切换不在使用回调语法。
阅读全文 »

如何解决view嵌套时的滑动冲突问题

发表于 2019-04-03   |   分类于 android   |  

在Android UI开发中,对滑动事件的处理是不可少的,其中对View嵌套时的滑动冲突问题处理则相对比较麻烦,下面就介绍一个这样的案例。

1. 滑动冲突问题

两个可以滑动的View嵌套,如何实现里面的View滑到尽头后,继续滑动时,事件交给外层View继续滑动。

2. 问题分析

  1. 根据Android的事件分发机制,里面的子view要想处理事件,就要接收到Action Down事件,所以父view不能拦截Down事件。
  2. 父View要能处理后续的Move事件,那么他就需要拦截Move事件。
  3. 子View滑动到尽头了,要交给父view,那么子View就需要能控制父View是否进行事件拦截。

3. 解决思路

  1. 父View不能拦截Down事件,但要拦截Move事件,可以在onInterceptTouchEvent中判断事件是Down事件时,返回false,其余事件返回true。
  2. 子View在接收到Down事件时,需要调用父View的requestDisallowInterceptTouchEvent为false,让父View不拦截事件,那么子View可以处理后续的Move事件,实现子View滑动。
  3. 当子View滑动到尽头后,再调用父View的requestDisallowInterceptTouchEvent为true,让父View拦截事件,即事件交给父View处理。
阅读全文 »

Linux shell 如何提取文件名和文件目录

发表于 2016-09-03   |   分类于 shell   |  

很多时候在使用Linux的shell时,我们都需要对文件名或目录名进行处理,通常的操作是由路径中提取出文件名,从路径中提取出目录名,提取文件后缀名等等。例如,从路径/dir1/dir2/file.txt中提取也文件名file.txt,提取出目录/dir1/dir2,提取出文件后缀txt等。

下面介绍两种常用的方法来进行相关的操作。

1. 使用${}

1.1. 提取文件名${var##*/}

该命令的作用是去掉变量var从左边算起的最后一个/字符及其左边的内容,返回从左边算起的最后一个/(不含该字符)的右边的内容。使用例子及结果如下:

taolin@pc:~$ var=/dir1/dir2/file.txt
taolin@pc:~$ echo ${var##*/}
file.txt

从运行结果可以看到,使用该命令,可以提取出我们需要的文件名file.txt。

若使用时在shell程序文件中,可以使用变量来保存这个结果,再加以利用,如file=${var##*/}

1.2. 提取文件后缀${var##*.}

该命令的作用是去掉变量var从左边算起的最后一个.字符及其左边的内容,返回从左边算起的最后一个.(不含该字符)的右边的内容。使用例子及结果如下:

taolin@pc:~$ var=/dir1/dir2/file.txt
taolin@pc:~$ echo ${var##*.}
txt

从运行结果可以看到,使用该命令,可以提取出我们需要的文件后缀。

如果文件的后缀不仅有一个,例如,file.tar.gz,命令${var##*.}仅能提取最后一个后缀,而我想提取tar.gz时该怎么办?那么就要用下面所说的${var#*.}命令了。

阅读全文 »

Android官方MVP架构示例项目解析

发表于 2016-08-17   |   分类于 android架构   |  
mvp architecture

前段时间Google在Github推出了一个项目,专门展示Android引用各种各样的MVP架构,算是官方教程了。趁着还新鲜,让我们来抛砖引玉一探究竟,看看在Google眼里什么样算是好的MVP架构。

App架构在Android开发者中一直是讨论比较多的一个话题,目前讨论较多的有MVP、MVVM、Clean这三种。google官方对于架构的态度一直是非常开放的,让开发者自主选择组织和架构app的方式,期望能留给开发者更多的灵活性。

由于没有一套权威的架构实现,现在很多App项目中在架构方面都有或多或少的问题。第一种常见问题是没有架构,需求中的一个页面对应项目中的一个activity或一个fragment,所有的界面响应代码、业务逻辑代码、数据请求代码等等都集中在其中。第二种常见的问题是架构实现的不断变化,不断在各种架构间摇摆,一直找不到一个适合自己的架构。

就在近日,google在官方示例中给出了一系列不同架构的app实现,这对于一直困惑于到底该用何种架构的android开发者来说确实是福音,开发者只要根据自己项目的情况,在不同的实现中选择一种即可,当然google也明确表示了这些示例只是用来做参考,而并不是要为了当做标准,下面先为大家简单介绍下此项目。

阅读全文 »

Android应用添加插件容器widget host功能

发表于 2016-08-16   |   分类于 android   |  

项目中遇到这样的问题,我们有一款大屏Android设备,为了充分利用大屏的优势,我们开发了一套操作界面(Launcher),所有的功能都在这个Launcher界面的一个个独立的panel中,要使用哪个功能,直接操作对应的panel就可以了,panel可以随意拖动。(如下图所示)
img1.png

随着功能模块越来越多,代码结构变得复杂,不好维护,后面我们就规划把其中一些模块用widget的方式实现,这样差不多有一半的模块可以分离出来,但整体效果不变。
这些功能模块要想通过widget的方式添加进来,Launcher就得实现widget容器的功能。

下面介绍如何让Android app支持widget容器功能

阅读全文 »

Android res资源文件如何混淆

发表于 2016-08-15   |   分类于 android   |  

由于apk的反编译比较简单,发布没有混淆过的apk,基本就等于把源码公开了。
对于release版的app,对代码进行混淆是有必要的,市场上发布的apk大部分也都进行了混淆,不过一般都只是对java代码进行混淆。通过没有混淆的资源文件,代码也很容易被破解,为了提高apk的破解难度,res资源文件也应该进行混淆。

下面介绍如何用AndResGuard对资源文件进行混淆

1. 添加依赖包

在Project根目录下build.gradle中添加dependency:

buildscript {
repositories {
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:2.1.0'
//添加AndResGuard依赖
classpath 'com.tencent.mm:AndResGuard-gradle-plugin:1.1.9'
}
}
阅读全文 »

Android java代码如何混淆

发表于 2016-07-18   |  

1. 前期准备

本篇文章中介绍的混淆技术都是基于Android Studio的,Eclipse的用法也基本类似,但是就不再为Eclipse专门做讲解了。
我们要建立一个Android Studio项目,并在项目中添加一些能够帮助我们理解混淆知识的代码。这里我准备好了一些,我们将它们添加到Android Studio当中。
首先新建一个MyFragment类,代码如下所示:

public class MyFragment extends Fragment {
private String toastTip = "toast in MyFragment";
@Override
public View onCreateView(LayoutInflater inflater, Nullable ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_layout, container, false);
methodWithGlobalVariable();
methodWithLocalVariable();
return view;
}
public void methodWithGlobalVariable() {
Toast.makeText(getActivity(), toastTip, Toast.LENGTH_SHORT).show();
}
public void methodWithLocalVariable() {
String logMessage = "log in MyFragment";
logMessage = logMessage.toLowerCase();
System.out.println(logMessage);
}
}

可以看到,MyFragment是继承自Fragment的,并且MyFragment中有一个全局变量。onCreateView()方法是Fragment的生命周期函数,这个不用多说,在onCreateView()方法中又调用了methodWithGlobalVariable()和methodWithLocalVariable()方法,这两个方法的内部分别引用了一个全局变量和一个局部变量。

阅读全文 »
12
Taolin

Taolin

生命不息 奋斗不止

18 日志
9 分类
48 标签
github weibo
© 2022 Taolin
由 Hexo 强力驱动
主题 - NexT.Mist