<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Posts on Zhangli&#39;s Blog</title>
    <link>https://zhanglihow.github.io/post/</link>
    <description>Recent content in Posts on Zhangli&#39;s Blog</description>
    <generator>Hugo -- gohugo.io</generator>
    <language>zh_CH</language>
    <copyright>© This post is licensed under a Creative Commons Attribution-NonCommercial 4.0 International License，please give source if you likes to quote or reproduce.</copyright>
    <lastBuildDate>Thu, 27 Feb 2020 11:41:16 +0800</lastBuildDate>
    
	<atom:link href="https://zhanglihow.github.io/post/index.xml" rel="self" type="application/rss+xml" />
    
    
    <item>
      <title>Sip语音通话</title>
      <link>https://zhanglihow.github.io/post/sip%E8%AF%AD%E9%9F%B3%E9%80%9A%E8%AF%9D/</link>
      <pubDate>Thu, 27 Feb 2020 11:41:16 +0800</pubDate>
      
      <guid>https://zhanglihow.github.io/post/sip%E8%AF%AD%E9%9F%B3%E9%80%9A%E8%AF%9D/</guid>
      <description>SipVoice 项目地址：SipVoice
该 demo 基于https://github.com/VoiSmart/pjsip-android 项目实现语音对讲对讲功能。
还有很多关于 pjsip 的功能和 API 请移步 pjsip-android。
正常运行该 Demo ，需要已有 Sip 服务端，Constants 中配置 ip 和端口。
解决了一个坑，通话2分钟必定断开，在 pjsip-android 提了 issues ,https://github.com/VoiSmart/pjsip-android/issues/89
估计他们使用的服务器不要客户端发心跳，所以一直没有找到答案，不过还是非常感谢 pjsip-android 的团队。
后面通过抓win软件的包，与同事沟通，找资料等方式，得知客户端需要主动发心跳，这才解决。
https://blog.csdn.net/netnote/article/details/3857191
这篇文章也给了我启示
sip是支持发送自定义数据的：  SipCall.sendRequest () 
详情看demo中的 CallOutActivity 的 160行
​
demo 中，实现了基本的语音对讲的功能，拨号，接听，静音，外放，计时等&amp;hellip;
拨号方：
接听方：
有个免费试用的sip服务器：https://www.myvoipapp.com/download/index.html
demo中修改了代码，只需要更改ip，完美运行。
如果有帮助，github点个star吧，老哥。</description>
    </item>
    
    <item>
      <title>到站提醒的Demo</title>
      <link>https://zhanglihow.github.io/post/%E5%88%B0%E7%AB%99%E6%8F%90%E9%86%92%E7%9A%84demo/</link>
      <pubDate>Wed, 26 Dec 2018 10:08:09 +0800</pubDate>
      
      <guid>https://zhanglihow.github.io/post/%E5%88%B0%E7%AB%99%E6%8F%90%E9%86%92%E7%9A%84demo/</guid>
      <description>关于一个到站提醒的Demo 大概的实现过程是这样的： 1，保存用户输入目的地的站名和拼音，并点击开启监听按钮；
2，开启间隔定位，获取第一次信息，得到当前城市code，然后去获取这个站名的信息（经纬度）；
3，继续定位获取当前的经纬度，比较与目的地的直线距离；
4，如果小于预设值，则认为是进入该预设值的范围，就停止定位，开启录音；
5，录音5秒，然后利用讯飞语音转文字，再转为拼音，与目的地的拼音进行匹配；
6，如果与目的地的拼音匹配率超过50%（比方：目的地是5个字，识别的语音有3个字是相同的，就认为是匹配上了），然后开启震动和弹出通知栏告知用户到站下车 (匹配的算法可能还有待优化，能够拼音模糊匹配就更好了)

涉及到的技术点： 1，定位，计算距离，站点信息 用的都是高德地图
2，语音识别，用的是讯飞语音
3，录音用的是 Android 的 AudioRecorder
4，汉字转拼音用的是 Android 的 HanziToPinyin

Android 下录音的两个类 AudioRecorder 和 MediaRecord AudioRecord 是一个比较偏底层的API,它可以获取到一帧帧 PCM 数据；MediaRecord 录制的音频文件是经过压缩后的。
（讯飞语音文件语音转文字支持两种格式 pcm 和 wav ,wav可直接在手机播放，所以这里录音用的是 AudioRecorder 文件格式是 pcm ，后转为wav）
PCM是一种没有压缩且无损的编码方式，WAV是微软开发的一种无损的音频文件格式 ， 而WAV是通过PCM数据的基础上添加头部信息而生成的一种音频格式，音质与CD接近

AudioRecorder 的几个需要注意的参数设置 录音采样率设置为：1600Hz (每秒录取声音的次数)
声音来源设置为：MediaRecorder.AudioSource.VOICE_COMMUNICATION(麦克风音频源针对语音通信进行了调整，会比设置为MIC好一些)
采样位数设置为：16bit (AudioFormat.ENCODING_PCM_16BIT 每秒录取声音的精度)
声道数设置为: 单声道(MONO)
音频文件的音质比特率:（kbps)=【采样率】（kHz）×（bit采样位数）×【声道数量】

这里的录音过程是这样：录5秒，停止，开始语音识别文件，识别完成后匹配，然后再启动录音
停止录音需要注意一下，
使用 audioRecord.stop()这个方法即可
最终停止才用 audioRecord.release() 
录音大概就是这样 
讯飞的语音识别目前有几个问题 1，语音识别率不是太高</description>
    </item>
    
    <item>
      <title>监听到局域网内的设备信息</title>
      <link>https://zhanglihow.github.io/post/%E7%9B%91%E5%90%AC%E5%88%B0%E5%B1%80%E5%9F%9F%E7%BD%91%E5%86%85%E7%9A%84%E8%AE%BE%E5%A4%87%E4%BF%A1%E6%81%AF/</link>
      <pubDate>Fri, 14 Sep 2018 17:55:05 +0800</pubDate>
      
      <guid>https://zhanglihow.github.io/post/%E7%9B%91%E5%90%AC%E5%88%B0%E5%B1%80%E5%9F%9F%E7%BD%91%E5%86%85%E7%9A%84%E8%AE%BE%E5%A4%87%E4%BF%A1%E6%81%AF/</guid>
      <description>项目上有个需要实现的功能，
涉及到几个设备：路由器，全景相机，手机。
路由器发出WIFI供全景相机和手机连接，手机需要拿到全景相机的IP去控制全景相机。
路由器是华为的，有个它自己的App，抓包发现了路由器下连接上的设备信息。
但是华为加密是比较严格的，请求时App端会生成一个密钥供服务端验证，除非华为将这个工具发给我，不然是行不通的，不用想华为也不会告诉我。
还好Google已经有这个功能的一套方案了 https://developer.android.com/training/connect-devices-wirelessly/nsd
试验了2K多次的开关监听，没有一次错误，还是很稳定的。
代码很简单，demo地址：https://github.com/zhanglihow/GetWifiIpDemo</description>
    </item>
    
    <item>
      <title>java.net.BindException Address already in use bind 错误</title>
      <link>https://zhanglihow.github.io/post/java.net.bindexception-address-already-in-use-bind-%E9%94%99%E8%AF%AF/</link>
      <pubDate>Fri, 17 Aug 2018 16:13:00 +0800</pubDate>
      
      <guid>https://zhanglihow.github.io/post/java.net.bindexception-address-already-in-use-bind-%E9%94%99%E8%AF%AF/</guid>
      <description>运行Java项目时，遇到了这个报错
该错误是端口号被占用，查看你项目的端口号 application.properties —&amp;gt; server.port=8088
然后控制栏输入 netstat -ano
然后去任务管理器处，找到 pid=3216 的进程，kill它。
重新运行你的项目，完成。</description>
    </item>
    
    <item>
      <title>仿知乎广告效果</title>
      <link>https://zhanglihow.github.io/post/%E4%BB%BF%E7%9F%A5%E4%B9%8E%E5%B9%BF%E5%91%8A%E6%95%88%E6%9E%9C/</link>
      <pubDate>Tue, 14 Aug 2018 10:13:27 +0800</pubDate>
      
      <guid>https://zhanglihow.github.io/post/%E4%BB%BF%E7%9F%A5%E4%B9%8E%E5%B9%BF%E5%91%8A%E6%95%88%E6%9E%9C/</guid>
      <description>先放一张知乎的广告截图：
说下我的实现吧，主要利用RecyclerView，在需要出现广告的时候，将这个item透明化，显示 ImageView 就达到这种效果了。最主要是这个RecyclerView的分隔条，用了个三方的才最终达到理想的效果。
可能还是会和原知乎有点不一样，图片广告完全没动，所以这只是好奇实现了一下。
demo地址：https://github.com/zhanglihow/ZhihuRecycler
在网上看到hongyang的实现，自定义了个IamgeView,比较接近了一些。https://github.com/hongyangAndroid/demo_rvadimage</description>
    </item>
    
    <item>
      <title>栈和队列基础题</title>
      <link>https://zhanglihow.github.io/post/%E6%A0%88%E5%92%8C%E9%98%9F%E5%88%97%E5%9F%BA%E7%A1%80%E9%A2%98/</link>
      <pubDate>Mon, 23 Jul 2018 18:31:23 +0800</pubDate>
      
      <guid>https://zhanglihow.github.io/post/%E6%A0%88%E5%92%8C%E9%98%9F%E5%88%97%E5%9F%BA%E7%A1%80%E9%A2%98/</guid>
      <description>1，设计一个有getMin功能的栈 题目：实现一个特殊的栈，在实现栈的基本功能的基础上，再实现返回栈中的最小值 要求： 1，pop、push、getMin操作的时间复杂度都是O（1） 2，设计的栈类型可以使用现成的栈的结构 public class Stack1 { private Stack&amp;lt;Integer&amp;gt; stackMin; private Stack&amp;lt;Integer&amp;gt; stackData; public Stack1(){ stackMin=new Stack&amp;lt;&amp;gt;(); stackData=new Stack&amp;lt;&amp;gt;(); } public int getMin(){ if(stackMin.isEmpty()){ throw new RuntimeException(&amp;quot;stack is null&amp;quot;); } return stackMin.peek(); } //方案一 //节省空间，pop步骤多 public void push(int newNum){ if(stackMin.isEmpty()){ stackMin.push(newNum); }else{ if(getMin()&amp;lt;=newNum){ stackMin.push(newNum); } } stackData.push(newNum); } public int pop(){ if(stackData.isEmpty()){ throw new RuntimeException(&amp;quot;stack is null&amp;quot;); } int value=stackData.pop(); if(value==getMin()){ stackMin.pop(); } return value; } //-------------------------- //方案2 //比方案1多费空间，但省时间 public void push2(int newNum){ if(stackMin.</description>
    </item>
    
    <item>
      <title>Python 自动识别抖音小姐姐并点赞</title>
      <link>https://zhanglihow.github.io/post/python-%E8%87%AA%E5%8A%A8%E8%AF%86%E5%88%AB%E6%8A%96%E9%9F%B3%E5%B0%8F%E5%A7%90%E5%A7%90%E5%B9%B6%E7%82%B9%E8%B5%9E/</link>
      <pubDate>Wed, 13 Jun 2018 16:50:33 +0800</pubDate>
      
      <guid>https://zhanglihow.github.io/post/python-%E8%87%AA%E5%8A%A8%E8%AF%86%E5%88%AB%E6%8A%96%E9%9F%B3%E5%B0%8F%E5%A7%90%E5%A7%90%E5%B9%B6%E7%82%B9%E8%B5%9E/</guid>
      <description>代码基本为原作者 tomxin7 所写，我改了一些逻辑处理和更新API。 效果 抖音经常能刷到很多高质量的视频，特别是我们使用的越多，头条的算法给我们推荐的内容越精准。**那么我们可不可以写一个小型的程序，根据自己设置的特征筛选视频并且自动点赞存入我们的收藏夹中呢？比如漂亮的小姐姐，帅气的小哥哥或者是可爱的喵星人。。。 **
图片压缩的有点厉害
原理说明 本程序与抖音无关，主要供学习用途 1，将手机打开抖音的推荐视频界面
2，用 ADB 工具获取当前手机截图，并用 ADB 将截图 pull 上来
adb shell screencap -p /sdcard/autojump.png adb pull /sdcard/autojump.png .  3，将图片进行压缩,并调用百度人脸识别API（目前使用的是v3的API）
4，获得百度返回的数据进行判断分析
5，如果满足要求，使用ADB点赞
6，上滑切换新视频
使用教程 1、获取源码 git命令
git clone https://github.com/zhanglihow/DouYinFaceTech.git  2、依赖 Python：3.6.3 ADB下载：http://adbshell.com/downloads 依赖：pip install pillow  3、准备 使用数据线连接手机与电脑，并开启调试模式 申请百度人脸检测的Key FaceMain.py中替换token的host链接  4、运行 手机打开抖音首页 DouYinFaceTech目录下直接运行FaceMain.py  5、可能遇到的问题 1，运行py文件不成功，出现cmd后闪退，建议这样运行有错误提示
cd 项目目录 python FaceMain.py  2，检测到中意的人脸后代码执行 GetDouYinImg.py 的 click_like() 方法时，手机未能点击成功
def click_like(): os.system(&amp;quot;adb shell input tap 950 850&amp;quot;)#点击事件  需要对应你的手机来更改位置</description>
    </item>
    
    <item>
      <title>Flutter--使用 Server酱 推送微信消息给个人</title>
      <link>https://zhanglihow.github.io/post/flutter-%E4%BD%BF%E7%94%A8-server%E9%85%B1-%E6%8E%A8%E9%80%81%E5%BE%AE%E4%BF%A1%E6%B6%88%E6%81%AF%E7%BB%99%E4%B8%AA%E4%BA%BA/</link>
      <pubDate>Wed, 06 Jun 2018 15:12:45 +0800</pubDate>
      
      <guid>https://zhanglihow.github.io/post/flutter-%E4%BD%BF%E7%94%A8-server%E9%85%B1-%E6%8E%A8%E9%80%81%E5%BE%AE%E4%BF%A1%E6%B6%88%E6%81%AF%E7%BB%99%E4%B8%AA%E4%BA%BA/</guid>
      <description>server酱：http://sc.ftqq.com/3.version
Server酱 设计的非常简单，你只需要用 Github 账号登录，然后绑定微信同时关注公众号，就可以通过 Http 服务，向绑定的微信号发送通知消息。
发送消息只需要向以下URL发一个GET或者POST请求：
https://sc.ftqq.com/[SCKEY].send  接受两个参数：
text：消息标题，最长为256，必填。
desp：消息内容，最长64Kb，可空，支持MarkDown。
之前想基于 Haven  ，做一个在家发现异常然后给我发通知的一个Demo，苦于邮件发送太麻烦，于是搁置了。但现在看来使用这个好像很不错。
于是用Flutter写了这样一个Demo，就当熟悉下Flutter吧。
使用到了 Flutter 的 Url跳转，Http请求，数据本地持久化SharedPreferences，及一些基础控件。
代码：https://github.com/zhanglihow/serverchan_flutter_demo
​
​
参考：
Flutter交互控件 Flutter 网络操作 Flutter 本地存储</description>
    </item>
    
    <item>
      <title>Java 反射与 open-sdk 来使用 Android hide 方法</title>
      <link>https://zhanglihow.github.io/post/java-%E5%8F%8D%E5%B0%84%E4%B8%8E-open-sdk-%E6%9D%A5%E4%BD%BF%E7%94%A8-android-hide-%E6%96%B9%E6%B3%95/</link>
      <pubDate>Sun, 08 Apr 2018 12:07:47 +0800</pubDate>
      
      <guid>https://zhanglihow.github.io/post/java-%E5%8F%8D%E5%B0%84%E4%B8%8E-open-sdk-%E6%9D%A5%E4%BD%BF%E7%94%A8-android-hide-%E6%96%B9%E6%B3%95/</guid>
      <description>一直有个问题，就是清除非本APP 连接的wifi保存的密码，很想像Android系统那样可以直接在WIFI设置那里直接取消保存，于是做了以下尝试。
是在sdk 19以上哦，19以下（包括）是可以直接清除的。
清除wifi密码比较通常的用法是：
WifiManager mWifiManager = (WifiManager)getApplicationContext().getSystemService(Context.WIFI_SERVICE); mWifiManager.removeNetwork(config.networkId); mWifiManager.saveConfiguration();  这样可以清除掉本来是你这个APP连接的WIFI，意思是这个WIFI是别人连接上的你是不能清除掉的。
目前也没有看到其他三方App能够做到这样。
于是开始寻找其他方法。
然后看到了 WifiManager 的这个方法 froget（看起来好像很有希望哦）:
说的是替代 removeNetwork 和 saveConfiguration 方法，可是这是hide的，我们显式是调用不了的。
那先试试反射吧。 首先去拿到WifiManager：
 Class&amp;lt;?&amp;gt; clazz = null; try { clazz = Class.forName(&amp;quot;android.net.wifi.WifiManager&amp;quot;); } catch (ClassNotFoundException e) { e.printStackTrace(); KLog.e(e); }  然后构造forget方法：
 Class&amp;lt;?&amp;gt; actionListener = null; try { actionListener = Class.forName(&amp;quot;android.net.wifi.WifiManager$ActionListener&amp;quot;); } catch (ClassNotFoundException e) { e.printStackTrace(); KLog.e(e); } KLog.e(&amp;quot;actionListener:&amp;quot; + actionListener); Method method = null; try { method = clazz.</description>
    </item>
    
    <item>
      <title>打开Flutter的Demo flutter_gallery失败</title>
      <link>https://zhanglihow.github.io/post/%E6%89%93%E5%BC%80flutter%E7%9A%84demo-flutter_gallery%E5%A4%B1%E8%B4%A5/</link>
      <pubDate>Mon, 26 Mar 2018 17:29:33 +0800</pubDate>
      
      <guid>https://zhanglihow.github.io/post/%E6%89%93%E5%BC%80flutter%E7%9A%84demo-flutter_gallery%E5%A4%B1%E8%B4%A5/</guid>
      <description>如果是git 一直超时，那么科学上网后可解决，不能科学上网的就看下面。
找到目录下的 pubspec.yaml：
将 git 替换为这个
url: https://github.com/zhanglihow/gallery-assets ref: d318485f208376e06d7e330d9f191141d14722b8  像这样：
然后点击右上角的 packges get
运行成功</description>
    </item>
    
    <item>
      <title>Flutter之搜索电影</title>
      <link>https://zhanglihow.github.io/post/flutter%E4%B9%8B%E6%90%9C%E7%B4%A2%E7%94%B5%E5%BD%B1/</link>
      <pubDate>Wed, 21 Mar 2018 18:27:57 +0800</pubDate>
      
      <guid>https://zhanglihow.github.io/post/flutter%E4%B9%8B%E6%90%9C%E7%B4%A2%E7%94%B5%E5%BD%B1/</guid>
      <description>搜索使用的是豆瓣电影API https://developers.douban.com/wiki/?title=movie_v2#subject
效果 ​
代码：
https://github.com/zhanglihow/search_movie
参考：
https://github.com/Norbert515/BookSearch https://github.com/WuXiaolong/flutter_movie</description>
    </item>
    
    <item>
      <title>Android连接Theta系列（二）</title>
      <link>https://zhanglihow.github.io/post/android%E8%BF%9E%E6%8E%A5theta%E7%B3%BB%E5%88%97%E4%BA%8C/</link>
      <pubDate>Mon, 19 Mar 2018 09:33:18 +0800</pubDate>
      
      <guid>https://zhanglihow.github.io/post/android%E8%BF%9E%E6%8E%A5theta%E7%B3%BB%E5%88%97%E4%BA%8C/</guid>
      <description>接着上面的Theta第一篇
我们先来改造展示全景相片的View，没有圆球效果，只是将Demo版的View伸展到全屏。
找到 GLRenderer 这个类的 onSurfaceChanged 这个方法，改为：
 /** * onSurfaceChanged Method * @param gl GLObject (not used) * @param width Screen width * @param height Screen height */ @Override public void onSurfaceChanged(final GL10 gl, final int width, final int height) { int _height = height; mScreenAspectRatio = (float) width / (float) (_height == 0 ? 1 : _height); GLES20.glViewport(0, _height, width, _height); Matrix.setLookAtM(mViewMatrix, 0, mCameraPosX, mCameraPosY, mCameraPosZ, mCameraDirectionX, mCameraDirectionY, mCameraDirectionZ, 0.</description>
    </item>
    
    <item>
      <title>Android连接Theta系列（一）</title>
      <link>https://zhanglihow.github.io/post/android%E8%BF%9E%E6%8E%A5theta%E7%B3%BB%E5%88%97%E4%B8%80/</link>
      <pubDate>Mon, 19 Mar 2018 09:32:58 +0800</pubDate>
      
      <guid>https://zhanglihow.github.io/post/android%E8%BF%9E%E6%8E%A5theta%E7%B3%BB%E5%88%97%E4%B8%80/</guid>
      <description>Theta 是一个全景相机 ，是由日本理光出品的，目前最新的型号是 RICOH THETA V。 推荐下载官方App：理光景达S。
先说一下怎么在APP中去控制它，Theta开启会发出一个wifi，然后手机连入这个wifi,通过App发出http请求来控制theta。 然后可以进行以下操作：
1，获取预览实时图像
2，设置拍照参数
3，拍照
4，取回所拍的照片等等
理光开发平台有demo和连接的API:https://developers.theta360.com/en/docs/
但是~
该demo非常简陋，API文档非常不完善，对比官方App就知道有多坑人了。 由此我踩了很多坑，http请求基本通过手机抓包获取，其中艰辛可见一斑。
推荐手机抓包工具：PacketCapture theta官网的Demo下载地址：https://developers.theta360.com/en/docs/sdk/download.html
连上Theta的wifi 开启Demo，可以看到这样的画面
1，通过 ShowLiveViewTask 获取实时画面数据流，通过 MJpegView 展示出来。
2，点击图片列表下载到手机上。
3，拍照、查看拍照的全景照片 Demo和官方App还是有很大的差别的，全景照片的展示没有那么炫酷，而且尺寸触摸的流畅度也差很远，官方只是说他们是和谷歌的全景照片一样的控件，意思就是说不会开源给你用的。</description>
    </item>
    
    <item>
      <title>GreenDao数据库升级</title>
      <link>https://zhanglihow.github.io/post/greendao%E6%95%B0%E6%8D%AE%E5%BA%93%E5%8D%87%E7%BA%A7/</link>
      <pubDate>Fri, 05 Jan 2018 15:17:22 +0800</pubDate>
      
      <guid>https://zhanglihow.github.io/post/greendao%E6%95%B0%E6%8D%AE%E5%BA%93%E5%8D%87%E7%BA%A7/</guid>
      <description>在将apk发包出去后需要改动Entity的元素，就需要升级数据库。
这时看具体需求，一是不需要原有数据，清除数据库；二是需要保留原有数据。
greendao默认使用的是第一种：
Daomaster:
 public static class DevOpenHelper extends OpenHelper { public DevOpenHelper(Context context, String name) { super(context, name); } public DevOpenHelper(Context context, String name, CursorFactory factory) { super(context, name, factory); } @Override public void onUpgrade(Database db, int oldVersion, int newVersion) { Log.i(&amp;quot;greenDAO&amp;quot;, &amp;quot;Upgrading schema from version &amp;quot; + oldVersion + &amp;quot; to &amp;quot; + newVersion + &amp;quot; by dropping all tables&amp;quot;); dropAllTables(db, true); onCreate(db); } }  这里只说第二种情况。</description>
    </item>
    
    <item>
      <title>获得当前手机的内存状态</title>
      <link>https://zhanglihow.github.io/post/%E8%8E%B7%E5%BE%97%E5%BD%93%E5%89%8D%E6%89%8B%E6%9C%BA%E7%9A%84%E5%86%85%E5%AD%98%E7%8A%B6%E6%80%81/</link>
      <pubDate>Mon, 16 Oct 2017 16:58:50 +0800</pubDate>
      
      <guid>https://zhanglihow.github.io/post/%E8%8E%B7%E5%BE%97%E5%BD%93%E5%89%8D%E6%89%8B%E6%9C%BA%E7%9A%84%E5%86%85%E5%AD%98%E7%8A%B6%E6%80%81/</guid>
      <description>ActivityManager mActivityManager = (ActivityManager)mApplication.getSystemService(ACTIVITY_SERVICE); int memory = mActivityManager.getMemoryClass(); float totalMemory = (float) (Runtime.getRuntime().totalMemory() * 1.0/ (1024 * 1024)); float freeMemory = (float) (Runtime.getRuntime().freeMemory() * 1.0/ (1024 * 1024)); Log.e(&amp;quot;内存&amp;quot;,&amp;quot;最大分配内存：&amp;quot;+memory+&amp;quot; 当前分配的总内存：&amp;quot;+totalMemory+&amp;quot; 剩余内存：&amp;quot;+freeMemory);  </description>
    </item>
    
    <item>
      <title>读取点云.OBJ文件，画出顶点平面图</title>
      <link>https://zhanglihow.github.io/post/%E8%AF%BB%E5%8F%96%E7%82%B9%E4%BA%91.obj%E6%96%87%E4%BB%B6%E7%94%BB%E5%87%BA%E9%A1%B6%E7%82%B9%E5%B9%B3%E9%9D%A2%E5%9B%BE/</link>
      <pubDate>Wed, 16 Aug 2017 14:52:20 +0800</pubDate>
      
      <guid>https://zhanglihow.github.io/post/%E8%AF%BB%E5%8F%96%E7%82%B9%E4%BA%91.obj%E6%96%87%E4%BB%B6%E7%94%BB%E5%87%BA%E9%A1%B6%E7%82%B9%E5%B9%B3%E9%9D%A2%E5%9B%BE/</guid>
      <description>基于一款开源应用 Rtabmap https://github.com/introlab/rtabmap
是基于 Google 的 Tango 手机使用的
通过摄像头和红外摄像头扫描立体空间，并实时显示在手机上，扫描后可保存所扫描的点云数据， .ply文件或.ob文件。
下图是扫描中截得图
3D Builder软件打开 .obj 文件是这样（和上图不是一个文件）
Android studio 打开 .obj 文件如下图
我这里只需要平面图 就是v顶点 其余的不需要
下面开始：
首先是读取.obj文件 文件在手机内
 public void startRead(final String uri) { mRootView.showLoading(); new Thread(new Runnable() { @Override public void run() { KLog.e(&amp;quot;start read&amp;quot;); long start = System.currentTimeMillis(); getObjXy(uri); long end = System.currentTimeMillis(); KLog.e(&amp;quot;用时：&amp;quot; + ((end - start) / 1000) + &amp;quot; s&amp;quot;); //画点 drawpoint(); } }).start(); }   /** * 读取 obj 的 xy点 * * @param uri */ private void getObjXy(String uri) { String fileStr = uri.</description>
    </item>
    
    <item>
      <title>Hugo搭建个人博客</title>
      <link>https://zhanglihow.github.io/post/hugo%E6%90%AD%E5%BB%BA%E4%B8%AA%E4%BA%BA%E5%8D%9A%E5%AE%A2/</link>
      <pubDate>Sun, 23 Jul 2017 18:14:38 +0800</pubDate>
      
      <guid>https://zhanglihow.github.io/post/hugo%E6%90%AD%E5%BB%BA%E4%B8%AA%E4%BA%BA%E5%8D%9A%E5%AE%A2/</guid>
      <description>参考 https://www.jianshu.com/p/f1b02e00f206
可搭建出一个博客并发布在github
参考 https://blog.csdn.net/btlas/article/details/51712596
可将github地址解析在个人域名下
hugo命令： 新建文章
 hugo new post/xxx.md draft 改为 false  本地预览
hugo server --theme=hyde  即可在浏览器里输入： http://localhost:1313访问网站
发布在github
 hugo --theme=hyde --baseUrl=&amp;quot;https://YOURNAME.github.io/&amp;quot;  我发现Theme 为 nuo时发布命令需要这样写：
hugo --theme=nuo --buildDrafts --baseUrl=&amp;quot;https://YOURNAME.github.io/&amp;quot;  更新文章只需上面步骤即可。</description>
    </item>
    
    <item>
      <title>Zip压缩和解压的方法</title>
      <link>https://zhanglihow.github.io/post/zip%E5%8E%8B%E7%BC%A9%E5%92%8C%E8%A7%A3%E5%8E%8B%E7%9A%84%E6%96%B9%E6%B3%95/</link>
      <pubDate>Thu, 29 Jun 2017 11:30:40 +0800</pubDate>
      
      <guid>https://zhanglihow.github.io/post/zip%E5%8E%8B%E7%BC%A9%E5%92%8C%E8%A7%A3%E5%8E%8B%E7%9A%84%E6%96%B9%E6%B3%95/</guid>
      <description>首先是一个 ZipControl 的zip工具类
import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.InputStream; import java.util.ArrayList; import java.util.List; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; import java.util.zip.ZipInputStream; import java.util.zip.ZipOutputStream; /** * Created by zhangli * * @time 2017/8/23 */ public class ZipControl{ /** * 压缩文件和文件夹 * @param srcFileString 要压缩的文件或文件夹 * @param zipFileString 解压完成的Zip路径 * @throws Exception */ public static void ZipFolder(String srcFileString, String zipFileString)throws Exception { //创建ZIP ZipOutputStream outZip = new ZipOutputStream(new FileOutputStream(zipFileString)); //创建文件 File file = new File(srcFileString); //压缩 ZipFiles(file.</description>
    </item>
    
    <item>
      <title>添加或删除RecyclerView的item后</title>
      <link>https://zhanglihow.github.io/post/%E5%8A%A8%E6%80%81%E5%88%B7%E6%96%B0recyclerview%E7%9A%84item/</link>
      <pubDate>Thu, 13 Apr 2017 10:12:47 +0800</pubDate>
      
      <guid>https://zhanglihow.github.io/post/%E5%8A%A8%E6%80%81%E5%88%B7%E6%96%B0recyclerview%E7%9A%84item/</guid>
      <description>通常Recycler给Adapter赋上数据源的时候利用：
adapter.notifyDataSetChanged();  这样一般是在初始化界面 从网络获取到数据后 直接赋给adapter的写法。
然后再动态的增加条目，又希望带有动画效果，可以这么写：
adapter.notifyItemRangeInserted(int positionStart, int itemCount);  嗯，在RecyclerView中 数据给加上去了 并且有一个动画效果。
但是，注意Adapter 中，这个数据源并没有增加。
这时，就要用到 notifyDataSetChanged() 这个方法了
在 调用加入的方法后 再调用全部刷新的方法。我的写法是这样的：
adapter.notifyItemRangeInserted(int positionStart, int itemCount); new Handler().postDelayed(new Runnable() { @Override public void run() { adapter.notifyDataSetChanged(); } },400);  利用Handler延时400ms 刷新 这样写是因为加入时的动画效果有那么一小段时间，如果不延时直接刷新的话动画会卡顿，不信可以去试试。
删除也是同理。</description>
    </item>
    
    <item>
      <title>使用Retrofit的一些实例</title>
      <link>https://zhanglihow.github.io/post/%E4%BD%BF%E7%94%A8retrofit%E7%9A%84%E4%B8%80%E4%BA%9B%E5%AE%9E%E4%BE%8B/</link>
      <pubDate>Sat, 07 Jan 2017 16:45:47 +0800</pubDate>
      
      <guid>https://zhanglihow.github.io/post/%E4%BD%BF%E7%94%A8retrofit%E7%9A%84%E4%B8%80%E4%BA%9B%E5%AE%9E%E4%BE%8B/</guid>
      <description>刚开始熟悉Retrofit ,并正在将项目中的网络框架换为retrofit。
添加依赖：
//Retrofit2所需要的包 compile &#39;com.squareup.retrofit2:retrofit:last_version&#39; //ConverterFactory的Gson依赖包 compile &#39;com.squareup.retrofit2:converter-gson:last_version&#39;  Retrofit的网络接口服务的包装类
public class RetrofitWrapper { private static RetrofitWrapper retrofitWrapper; private Retrofit retrofit; private RetrofitWrapper() { retrofit = new Retrofit.Builder().baseUrl(AppConfig.RETROFIT_URL) .addConverterFactory(GsonConverterFactory.create()) .build(); } /** * 单列模式 */ public static RetrofitWrapper getWrapperInstance() { if (retrofitWrapper == null) { synchronized (RetrofitWrapper.class) { if (retrofitWrapper == null) { retrofitWrapper = new RetrofitWrapper(); } } } return retrofitWrapper; } public &amp;lt;T&amp;gt; T create(final Class&amp;lt;T&amp;gt; service) { return retrofit.</description>
    </item>
    
    <item>
      <title>调起百度、高德、腾讯地图导航功能</title>
      <link>https://zhanglihow.github.io/post/%E8%B0%83%E8%B5%B7%E7%99%BE%E5%BA%A6%E9%AB%98%E5%BE%B7%E8%85%BE%E8%AE%AF%E5%9C%B0%E5%9B%BE%E5%AF%BC%E8%88%AA%E5%8A%9F%E8%83%BD/</link>
      <pubDate>Wed, 28 Dec 2016 14:16:27 +0800</pubDate>
      
      <guid>https://zhanglihow.github.io/post/%E8%B0%83%E8%B5%B7%E7%99%BE%E5%BA%A6%E9%AB%98%E5%BE%B7%E8%85%BE%E8%AE%AF%E5%9C%B0%E5%9B%BE%E5%AF%BC%E8%88%AA%E5%8A%9F%E8%83%BD/</guid>
      <description>如果可以，先得到这3个条件，然后在调起地图的请求中传进去。
使用这个方法判断手机中是否包含应用：
 /** * 检查手机上是否安装了指定的软件 * * @param context * @param packageName：应用包名 * @return */ public static boolean isAvilible(Context context, String packageName) { //获取packagemanager final PackageManager packageManager = context.getPackageManager(); //获取所有已安装程序的包信息 List&amp;lt;PackageInfo&amp;gt; packageInfos = packageManager.getInstalledPackages(0); //用于存储所有已安装程序的包名 List&amp;lt;String&amp;gt; packageNames = new ArrayList&amp;lt;String&amp;gt;(); //从pinfo中将包名字逐一取出，压入pName list中 if (packageInfos != null) { for (int i = 0; i &amp;lt; packageInfos.size(); i++) { String packName = packageInfos.get(i).packageName; packageNames.add(packName); } } //判断packageNames中是否有目标程序的包名，有TRUE，没有FALSE return packageNames.contains(packageName); }   //百度 if (isAvilible(getApplicationContext(), &amp;quot;com.</description>
    </item>
    
    <item>
      <title>怎样使用SharedPrefences来存储对象</title>
      <link>https://zhanglihow.github.io/post/%E6%80%8E%E6%A0%B7%E4%BD%BF%E7%94%A8sharedprefences%E6%9D%A5%E5%AD%98%E5%82%A8%E5%AF%B9%E8%B1%A1/</link>
      <pubDate>Tue, 06 Dec 2016 17:56:22 +0800</pubDate>
      
      <guid>https://zhanglihow.github.io/post/%E6%80%8E%E6%A0%B7%E4%BD%BF%E7%94%A8sharedprefences%E6%9D%A5%E5%AD%98%E5%82%A8%E5%AF%B9%E8%B1%A1/</guid>
      <description>一般使用sp存储的都是基本类型的数据，但遇到需要存储整个对象的时候，分开存储是可以的，但是很麻烦，也会记不清楚。
那么可以使用将对象序列化成一个String数据类型存储在sp里，需要这个对象数据的时候在反序列化存储在sp的String数据，就得到了这个存储的对象。
首先将需要存储的对象实现 Serializable或Parcelable ，表示这个对象是可序列化的。
我这里存储User这个对象
public class User implements Serializable{ private int id; private String name; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } }  第一步，saveobject：
 saveObject(serialize(user),getApplicationContext(),USER);  第二步，取对象：
deSerialization(getObject(getApplicationContext(),USER))  那么，User对象就被SharedPrefences存储到一个手机里。
主要代码：
 /** * 序列化对象 * * @param person * @return * @throws IOException */ public static String serialize(Object person) throws IOException { ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream); objectOutputStream.</description>
    </item>
    
    <item>
      <title>利用贝塞尔曲线做签名功能</title>
      <link>https://zhanglihow.github.io/post/%E5%88%A9%E7%94%A8%E8%B4%9D%E5%A1%9E%E5%B0%94%E6%9B%B2%E7%BA%BF%E5%81%9A%E7%AD%BE%E5%90%8D%E5%8A%9F%E8%83%BD/</link>
      <pubDate>Sat, 06 Aug 2016 16:10:41 +0800</pubDate>
      
      <guid>https://zhanglihow.github.io/post/%E5%88%A9%E7%94%A8%E8%B4%9D%E5%A1%9E%E5%B0%94%E6%9B%B2%E7%BA%BF%E5%81%9A%E7%AD%BE%E5%90%8D%E5%8A%9F%E8%83%BD/</guid>
      <description>效果图： 开始在网上找的这个签名的功能，然后发觉画出来的线条不顺滑，之前偶然间看到贝塞尔曲线的一片博客，链接：http://blog.csdn.net/eclipsexys/article/details/51956908，然后将贝塞尔给添加进去，就完成了现在这种效果。
主要代码： import android.app.AlertDialog; import android.app.Dialog; import android.content.Context; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.Path; import android.graphics.Point; import android.os.Bundle; import android.os.Environment; import android.support.v7.app.AppCompatActivity; import android.view.Display; import android.view.LayoutInflater; import android.view.MotionEvent; import android.view.View; import android.view.ViewConfiguration; import android.view.WindowManager; import android.view.WindowManager.LayoutParams; import android.widget.Button; import android.widget.FrameLayout; import android.widget.ImageView; import android.widget.TextView; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; public class MainActivity extends AppCompatActivity implements View.OnClickListener { static final int BACKGROUND_COLOR = Color.</description>
    </item>
    
    <item>
      <title>演示</title>
      <link>https://zhanglihow.github.io/post/%E6%BC%94%E7%A4%BA/</link>
      <pubDate>Mon, 20 Sep 1999 11:43:49 +0800</pubDate>
      
      <guid>https://zhanglihow.github.io/post/%E6%BC%94%E7%A4%BA/</guid>
      <description>1，添加站点 
&amp;nbsp;
&amp;nbsp;
2，Tango扫描  &amp;nbsp;
&amp;nbsp;
3-1，Faro扫描App端  &amp;nbsp;
&amp;nbsp;
3-2，Faro机器  &amp;nbsp;
&amp;nbsp;
4，Theta拍照  &amp;nbsp;
&amp;nbsp;</description>
    </item>
    
  </channel>
</rss>