<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Android on 个人记录 | 随心所意，记录点滴</title>
    <link>https://gker.net/tags/android/</link>
    <description>Recent content in Android on 个人记录 | 随心所意，记录点滴</description>
    <generator>Hugo</generator>
    <language>zh-cn</language>
    <lastBuildDate>Mon, 30 Nov 2020 11:50:12 +1000</lastBuildDate>
    <atom:link href="https://gker.net/tags/android/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>MacBook重新打包jar</title>
      <link>https://gker.net/post/10028/</link>
      <pubDate>Mon, 30 Nov 2020 11:50:12 +1000</pubDate>
      <guid>https://gker.net/post/10028/</guid>
      <description>&lt;ul&gt;&#xA;&lt;li&gt;解压jar包&#xA;先进入X.jar所在目录&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;&#x9;jar -xvf X.jar&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&#xA;&lt;li&gt;重新打jar包&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;&#x9;jar -cvf X.jar ./&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&#xA;&lt;li&gt;替换META-INF/MANIFEST.MF文件，到打包后的X.jar包中。&#xA;用上一个命令打出的包，MANIFEST.MF文件中是没有入口类的信息的，需要更新正确的清单文件(非可执行文件可以省略这一步)&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;&#x9;jar umf META-INF/MANIFEST.MF X.jar&#xA;&lt;/code&gt;&lt;/pre&gt;</description>
    </item>
    <item>
      <title>ProtoBuffer中文转码</title>
      <link>https://gker.net/post/10027/</link>
      <pubDate>Sat, 31 Oct 2020 11:50:12 +1000</pubDate>
      <guid>https://gker.net/post/10027/</guid>
      <description>&lt;p&gt;许多时候需要查看日志中的中文字符，但是protobuf中某字段为中文的话，打印出来为8进制字符。若要打印为中文，可用以下代码：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;import com.google.protobuf.TextFormat;&#xD;&#xA;&#xD;&#xA;public class NormalProtobufDeserializer implements IProtobufDeserializer{&#xD;&#xA;    @Override&#xD;&#xA;    public String deserial(byte[] data) {&#xD;&#xA;        String ret = &amp;#34;&amp;#34;;&#xD;&#xA;        try{&#xD;&#xA;            NormalDeserializer.NormalMessage normalMessage = NormalDeserializer.NormalMessage.parseFrom(data);&#xD;&#xA;            //ret = normalMessage.toString(); 此时为8进制，如&amp;#34;\241\242\243\244\245&amp;#34;&#xD;&#xA;            ret = TextFormat.printToUnicodeString(normalMessage);&#xD;&#xA;        }catch (Throwable throwable){&#xD;&#xA; &#xD;&#xA;        }&#xD;&#xA;        return ret;&#xD;&#xA;    }&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;若已经打印出八进制”\241\242\243\244\245”，可以用以下代码转成中文：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;public static void printProtoBuf(String dataStr) {&#xD;&#xA;        if (!dataStr.contains(&amp;#34;\\&amp;#34;)) {&#xD;&#xA;            System.out.println(&amp;#34;未识别：&amp;#34; + dataStr);&#xD;&#xA;        } else {&#xD;&#xA;            //不属于八进制内容的字符&#xD;&#xA;            StringBuilder oldBuffer = new StringBuilder();&#xD;&#xA;            //属于八进制的内容，转成十六进制后缓存在这里&#xD;&#xA;            StringBuilder hexBuffer = new StringBuilder();&#xD;&#xA;            for (int i = 0; i &amp;lt; dataStr.length(); i++) {&#xD;&#xA;                char c = dataStr.charAt(i);&#xD;&#xA;                if (c != &amp;#39;\\&amp;#39;) {&#xD;&#xA;                    oldBuffer.append(c);&#xD;&#xA;                }&#xD;&#xA;                //反斜杠往后3个为一组，组成了一个八进制数。例如\20710,其实是207组成了一个八进制数&#xD;&#xA;                else {&#xD;&#xA;                    char c1 = dataStr.charAt(i + 1);&#xD;&#xA;                    char c2 = dataStr.charAt(i + 2);&#xD;&#xA;                    char c3 = dataStr.charAt(i + 3);&#xD;&#xA;                    if(c1 == &amp;#39;n&amp;#39; &amp;amp;&amp;amp; c2 == &amp;#39;\\&amp;#39;){&#xD;&#xA;                        i += 1;&#xD;&#xA;                        oldBuffer.append(&amp;#34;\n&amp;#34;);&#xD;&#xA;                    }else if(c1 == &amp;#39;t&amp;#39; &amp;amp;&amp;amp; c2 == &amp;#39;\\&amp;#39;){&#xD;&#xA;                        i += 1;&#xD;&#xA;                        oldBuffer.append(&amp;#34;\t&amp;#34;);&#xD;&#xA;                    }else if(c1 == &amp;#39;f&amp;#39; &amp;amp;&amp;amp; c2 == &amp;#39;\\&amp;#39;){&#xD;&#xA;                        i += 1;&#xD;&#xA;                        oldBuffer.append(&amp;#34;\f&amp;#34;);&#xD;&#xA;                    }else {&#xD;&#xA;                        i += 3;&#xD;&#xA;                        //将八进制转换为十进制，再转换为十六进制&#xD;&#xA;                        String hex = Integer.toHexString((Integer.valueOf(&amp;#34;&amp;#34; + c1 + c2 + c3, 8)));&#xD;&#xA;                        //先缓存住，直到凑够三个字节&#xD;&#xA;                        hexBuffer.append(hex);&#xD;&#xA;                        String hexString = hexBuffer.toString();&#xD;&#xA;                        //utf8编码中，三个字节为一个汉字&#xD;&#xA;                        if (hexString.length() == 6) {&#xD;&#xA;                            //凑够三个字节了，转成汉字后放入oldBuffer中&#xD;&#xA;                            oldBuffer.append(hexStr2Str(hexString));&#xD;&#xA;                            //凑够一个汉字了，清空缓存&#xD;&#xA;                            hexBuffer = new StringBuilder();&#xD;&#xA;                        }&#xD;&#xA;                    }&#xD;&#xA;                }&#xD;&#xA;            }&#xD;&#xA;            System.out.println(&amp;#34;解码后：&amp;#34; + oldBuffer.toString());&#xD;&#xA;        }&#xD;&#xA;    }&#xA;&lt;/code&gt;&lt;/pre&gt;</description>
    </item>
    <item>
      <title>Parameter ‘directory‘ is not a directory</title>
      <link>https://gker.net/post/10026/</link>
      <pubDate>Wed, 21 Oct 2020 12:52:14 +1000</pubDate>
      <guid>https://gker.net/post/10026/</guid>
      <description>&lt;p&gt;将AndroidStudio项目复制了一份，运行时报错：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;Execution failed for task &amp;#39;:app:dataBindingGenBaseClassesDebug&amp;#39;.      &#xD;&#xA;Parameter &amp;#39;directory&amp;#39; is not a directory   &#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;按照stackoverflow的方法， invalidata Cache/Restart 或者删除 .gradle 文件夹，都不好使 最终解决办法是在命令行执行编译一遍：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;./gradlew assembleDebug --rerun-tasks&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;完成后重新在AndroidStudio中运行就可以了。&lt;/p&gt;</description>
    </item>
    <item>
      <title>混淆映射mapping压缩</title>
      <link>https://gker.net/post/10025/</link>
      <pubDate>Tue, 25 Aug 2020 10:51:14 +0800</pubDate>
      <guid>https://gker.net/post/10025/</guid>
      <description>&lt;p&gt;我们项目里终会有一些不需要混淆的符号，比如一些第三方包，一些jni调用，一些自动解析的model,这些不混淆的符号也会在mapping里生在相同不变的符号映射，其实这些符号映射是不需要也能正常解码错误代码的，去掉这些未混淆的符号就能给mapping文件瘦身，当文件超级大时，可以把android源生sdk取消混淆，第三方开源库也能取消，只把自己开发的核心功能保留混淆，这样去掉未混淆之符号时，mapping会达到极为精简的地步。&lt;/p&gt;&#xA;&lt;p&gt;使用shell可以很轻松的去掉未混淆的符号：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;find ./ -name mapping.txt | xargs cat | awk &amp;#39;{if($2!=$4) print $0}&amp;#39;&amp;gt;./newmapping.txt&#xA;&lt;/code&gt;&lt;/pre&gt;</description>
    </item>
    <item>
      <title>Android颜色计算</title>
      <link>https://gker.net/post/10022/</link>
      <pubDate>Tue, 13 Nov 2018 12:53:25 +0800</pubDate>
      <guid>https://gker.net/post/10022/</guid>
      <description>&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;/**&#xD;&#xA; * 合并颜色，支持argb8888 &#xD;&#xA; * @param fg 前景色&#xD;&#xA; * @param bg 背景色&#xD;&#xA; */&#xD;&#xA; public static int blendColor(int fg, int bg) {&#xD;&#xA; int scr = Color.red(fg);&#xD;&#xA; int scg = Color.green(fg);&#xD;&#xA; int scb = Color.blue(fg);&#xD;&#xA; int sa = fg &amp;gt;&amp;gt;&amp;gt; 24;&#xD;&#xA; int dcr = Color.red(bg);&#xD;&#xA; int dcg = Color.green(bg);&#xD;&#xA; int dcb = Color.blue(bg);&#xD;&#xA; int color_r = dcr * (0xff - sa) / 0xff + scr * sa / 0xff;&#xD;&#xA; int color_g = dcg * (0xff - sa) / 0xff + scg * sa / 0xff;&#xD;&#xA; int color_b = dcb * (0xff - sa) / 0xff + scb * sa / 0xff;&#xD;&#xA; return ((color_r &amp;lt;&amp;lt; 16) + (color_g &amp;lt;&amp;lt; 8) + color_b) | (0xff000000);&#xD;&#xA;}&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;    /** Calculates the constrast between two colors, using the algorithm provided by the WCAG v2. */&#xD;&#xA;    public static float computeContrastBetweenColors(int bg, int fg) {&#xD;&#xA;        float bgR = Color.red(bg) / 255f;&#xD;&#xA;        float bgG = Color.green(bg) / 255f;&#xD;&#xA;        float bgB = Color.blue(bg) / 255f;&#xD;&#xA;        bgR = (bgR &amp;lt; 0.03928f) ? bgR / 12.92f : (float) Math.pow((bgR + 0.055f) / 1.055f, 2.4f);&#xD;&#xA;        bgG = (bgG &amp;lt; 0.03928f) ? bgG / 12.92f : (float) Math.pow((bgG + 0.055f) / 1.055f, 2.4f);&#xD;&#xA;        bgB = (bgB &amp;lt; 0.03928f) ? bgB / 12.92f : (float) Math.pow((bgB + 0.055f) / 1.055f, 2.4f);&#xD;&#xA;        float bgL = 0.2126f * bgR + 0.7152f * bgG + 0.0722f * bgB;&#xD;&#xA;        &#xD;&#xA;        float fgR = Color.red(fg) / 255f;&#xD;&#xA;        float fgG = Color.green(fg) / 255f;&#xD;&#xA;        float fgB = Color.blue(fg) / 255f;&#xD;&#xA;        fgR = (fgR &amp;lt; 0.03928f) ? fgR / 12.92f : (float) Math.pow((fgR + 0.055f) / 1.055f, 2.4f);&#xD;&#xA;        fgG = (fgG &amp;lt; 0.03928f) ? fgG / 12.92f : (float) Math.pow((fgG + 0.055f) / 1.055f, 2.4f);&#xD;&#xA;        fgB = (fgB &amp;lt; 0.03928f) ? fgB / 12.92f : (float) Math.pow((fgB + 0.055f) / 1.055f, 2.4f);&#xD;&#xA;        float fgL = 0.2126f * fgR + 0.7152f * fgG + 0.0722f * fgB;&#xD;&#xA; &#xD;&#xA;        return Math.abs((fgL + 0.05f) / (bgL + 0.05f));&#xD;&#xA;    }&#xD;&#xA;&#x9;//判断是否是深色&#xD;&#xA;&#x9;isDark = computeContrastBetweenColors(color,Color.WHITE) &amp;gt; 3f;&#xA;&lt;/code&gt;&lt;/pre&gt;</description>
    </item>
    <item>
      <title>Android硬件加速后单个Bitmap可以显示的最大尺寸</title>
      <link>https://gker.net/post/10019/</link>
      <pubDate>Tue, 14 Nov 2017 18:56:12 +0800</pubDate>
      <guid>https://gker.net/post/10019/</guid>
      <description>&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;private void getGLESTextureLimitBelowLollipop() {  &#xD;&#xA;    int[] maxSize = new int[1];  &#xD;&#xA;    GLES10.glGetIntegerv(GLES10.GL_MAX_TEXTURE_SIZE, maxSize, 0);  &#xD;&#xA;    Toast.makeText(this,&amp;#34; &amp;#34; + maxSize[0],Toast.LENGTH_LONG).show();  &#xD;&#xA;}  &#xA;&lt;/code&gt;&lt;/pre&gt;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;private void getGLESTextureLimitEqualAboveLollipop() {  &#xD;&#xA;    EGL10 egl = (EGL10) EGLContext.getEGL();  &#xD;&#xA;    EGLDisplay dpy = egl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY);  &#xD;&#xA;    int[] vers = new int[2];  &#xD;&#xA;    egl.eglInitialize(dpy, vers);  &#xD;&#xA;    int[] configAttr = {  &#xD;&#xA;            EGL10.EGL_COLOR_BUFFER_TYPE, EGL10.EGL_RGB_BUFFER,  &#xD;&#xA;            EGL10.EGL_LEVEL, 0,  &#xD;&#xA;            EGL10.EGL_SURFACE_TYPE, EGL10.EGL_PBUFFER_BIT,  &#xD;&#xA;            EGL10.EGL_NONE  &#xD;&#xA;    };  &#xD;&#xA;    EGLConfig[] configs = new EGLConfig[1];  &#xD;&#xA;    int[] numConfig = new int[1];  &#xD;&#xA;    egl.eglChooseConfig(dpy, configAttr, configs, 1, numConfig);  &#xD;&#xA;    if (numConfig[0] == 0) {// TROUBLE! No config found.  &#xD;&#xA;    }  &#xD;&#xA;    EGLConfig config = configs[0];  &#xD;&#xA;    int[] surfAttr = {  &#xD;&#xA;            EGL10.EGL_WIDTH, 64,  &#xD;&#xA;            EGL10.EGL_HEIGHT, 64,  &#xD;&#xA;            EGL10.EGL_NONE  &#xD;&#xA;    };  &#xD;&#xA;    EGLSurface surf = egl.eglCreatePbufferSurface(dpy, config, surfAttr);  &#xD;&#xA;    final int EGL_CONTEXT_CLIENT_VERSION = 0x3098;  // missing in EGL10  &#xD;&#xA;    int[] ctxAttrib = {  &#xD;&#xA;            EGL_CONTEXT_CLIENT_VERSION, 1,  &#xD;&#xA;            EGL10.EGL_NONE  &#xD;&#xA;    };  &#xD;&#xA;    EGLContext ctx = egl.eglCreateContext(dpy, config, EGL10.EGL_NO_CONTEXT, ctxAttrib);  &#xD;&#xA;    egl.eglMakeCurrent(dpy, surf, surf, ctx);  &#xD;&#xA;    int[] maxSize = new int[1];  &#xD;&#xA;    GLES10.glGetIntegerv(GLES10.GL_MAX_TEXTURE_SIZE, maxSize, 0);  &#xD;&#xA;    egl.eglMakeCurrent(dpy, EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_SURFACE,  &#xD;&#xA;            EGL10.EGL_NO_CONTEXT);  &#xD;&#xA;    egl.eglDestroySurface(dpy, surf);  &#xD;&#xA;    egl.eglDestroyContext(dpy, ctx);  &#xD;&#xA;    egl.eglTerminate(dpy);  &#xD;&#xA;  &#xD;&#xA;    Toast.makeText(this,&amp;#34; &amp;#34; + maxSize[0],Toast.LENGTH_LONG).show();  &#xD;&#xA;} &#xA;&lt;/code&gt;&lt;/pre&gt;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;if (Build.VERSION.SDK_INT &amp;gt;= Build.VERSION_CODES.LOLLIPOP) {  &#xD;&#xA;    getGLESTextureLimitEqualAboveLollipop();  &#xD;&#xA;} else {  &#xD;&#xA;    getGLESTextureLimitBelowLollipop();  &#xD;&#xA;} &#xA;&lt;/code&gt;&lt;/pre&gt;</description>
    </item>
    <item>
      <title>Fresco修改decoder，解决超大图显示模糊的问题。</title>
      <link>https://gker.net/post/10018/</link>
      <pubDate>Tue, 31 Oct 2017 16:35:39 +0800</pubDate>
      <guid>https://gker.net/post/10018/</guid>
      <description>&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;private void setImageUrl() {&#xD;&#xA;    ImageRequest request = ImageRequestBuilder.newBuilderWithSource(Uri.parse(model.getImage()))&#xD;&#xA;            .setImageDecodeOptions(Utils.getFileTypeIsGif(model.getImage()) ? null ://null表示使用原有默认decoder&#xD;&#xA;                    ImageDecodeOptions.newBuilder()&#xD;&#xA;                            .setCustomImageDecoder(new ImageDecoder() {&#xD;&#xA;                                @Override&#xD;&#xA;  public CloseableImage decode(EncodedImage encodedImage, int length, QualityInfo qualityInfo, ImageDecodeOptions options) {&#xD;&#xA;                                    Bitmap bitmap = null;&#xD;&#xA; if (encodedImage.getHeight() &amp;gt; Utils.dip2px(manager.getContext(), 150)) {&#xD;&#xA;                                        int height = Utils.dip2px(manager.getContext(), 150);&#xD;&#xA; int width = Utils.getWidth(manager.getContext());&#xD;&#xA;  width = width &amp;gt; encodedImage.getWidth() ? encodedImage.getWidth() : width;&#xD;&#xA;  SkiaImageRegionDecoder inDecoder = new SkiaImageRegionDecoder();&#xD;&#xA;  Rect region = new Rect();&#xD;&#xA;  region.left = (encodedImage.getWidth() - width) / 2;&#xD;&#xA;  region.right = region.left + width;&#xD;&#xA;  region.top = (encodedImage.getHeight() - height) / 2;&#xD;&#xA;  region.bottom = region.top + height;&#xD;&#xA; try {&#xD;&#xA;                                            inDecoder.init(manager.getContext(), Uri.parse(&amp;#34;file://&amp;#34; + FrescoUtils.getImageFileOnDisk(Uri.parse(model.getImage())).getAbsolutePath()));&#xD;&#xA;  bitmap = inDecoder.decodeRegion(region, 1);&#xD;&#xA;  } catch (Exception e) {&#xD;&#xA;                                            LogInfo.LogOut(e);&#xD;&#xA;  }&#xD;&#xA;                                    }&#xD;&#xA;                                    if (bitmap == null) {//TODO 此处最好使用原有默认decoder&#xD;&#xA;                                        bitmap = BitmapFactory.decodeStream(encodedImage.getInputStream());&#xD;&#xA;  }&#xD;&#xA;                                    return new CloseableStaticBitmap(&#xD;&#xA;                                            bitmap,&#xD;&#xA;  SimpleBitmapReleaser.getInstance(),&#xD;&#xA;  ImmutableQualityInfo.FULL_QUALITY,&#xD;&#xA;  0);&#xD;&#xA;&#xD;&#xA;  }&#xD;&#xA;                            })&#xD;&#xA;                            .build())&#xD;&#xA;            .build();&#xD;&#xA;  DraweeController controller = Fresco.newDraweeControllerBuilder()&#xD;&#xA;            .setImageRequest(request)&#xD;&#xA;            .setAutoPlayAnimations(Utils.getFileTypeIsGif(model.getImage()))&#xD;&#xA;            .setOldController(image.getController())&#xD;&#xA;            .setControllerListener(new BaseControllerListener())&#xD;&#xA;            .build();&#xD;&#xA;  image.setController(controller);&#xD;&#xA;}&#xA;&lt;/code&gt;&lt;/pre&gt;</description>
    </item>
    <item>
      <title>学习正则表达式</title>
      <link>https://gker.net/post/10017/</link>
      <pubDate>Wed, 16 Aug 2017 12:25:29 +0800</pubDate>
      <guid>https://gker.net/post/10017/</guid>
      <description>&lt;p&gt;本文为转载，&lt;a href=&#34;https://github.com/zeeshanu/learn-regex/blob/master/README-cn.md&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;原文地址&lt;/a&gt;&lt;/p&gt;&#xA;&lt;h2 id=&#34;什么是正则表达式&#34;&gt;什么是正则表达式? &lt;a href=&#34;#%e4%bb%80%e4%b9%88%e6%98%af%e6%ad%a3%e5%88%99%e8%a1%a8%e8%be%be%e5%bc%8f&#34; class=&#34;anchor&#34;&gt;🔗&lt;/a&gt;&lt;/h2&gt;&lt;blockquote&gt;&#xA;&lt;p&gt;正则表达式是一组由字母和符号组成的特殊文本, 它可以用来从文本中找出满足你想要的格式的句子.&lt;/p&gt;&#xA;&lt;/blockquote&gt;&#xA;&lt;p&gt;一个正则表达式是在一个主体字符串中从左到右匹配字符串时的一种样式. 例如&amp;quot;Regular expression&amp;quot;是一个完整的句子, 但我们常使用缩写的术语&amp;quot;regex&amp;quot;或&amp;quot;regexp&amp;quot;. 正则表达式可以用来替换文本中的字符串,验证形式,提取字符串等等.&lt;/p&gt;&#xA;&lt;p&gt;想象你正在写一个应用, 然后你想设定一个用户命名的规则, 让用户名包含字符,数字,下划线和连字符,以及限制字符的个数,好让名字看起来没那么丑. 我们使用以下正则表达式来验证一个用户名:&lt;/p&gt;&#xA;&lt;p&gt;&lt;a href=&#34;https://camo.githubusercontent.com/90cf24181617b0cfc26f5a650d406f7e53b83927/68747470733a2f2f692e696d6775722e636f6d2f5071354c6c61742e706e67&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;&lt;p class=&#34;markdown-image&#34;&gt;&#xD;&#xA;  &lt;img src=&#34;https://camo.githubusercontent.com/90cf24181617b0cfc26f5a650d406f7e53b83927/68747470733a2f2f692e696d6775722e636f6d2f5071354c6c61742e706e67&#34; alt=&#34;&#34;  /&gt;&#xD;&#xA;&lt;/p&gt;&lt;/a&gt;&lt;/p&gt;&#xA;&lt;p&gt;以上的正则表达式可以接受 &lt;code&gt;john_doe&lt;/code&gt;, &lt;code&gt;jo-hn_doe&lt;/code&gt;, &lt;code&gt;john12_as&lt;/code&gt;. 但不匹配&lt;code&gt;Jo&lt;/code&gt;, 因为它包含了大写的字母而且太短了.&lt;/p&gt;&#xA;&lt;h1 id=&#34;目录&#34;&gt;&lt;a href=&#34;https://gker.net/articles/2017/08/16/1502871430957.html#%e7%9b%ae%e5%bd%95&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;&lt;/a&gt;目录 &lt;a href=&#34;#%e7%9b%ae%e5%bd%95&#34; class=&#34;anchor&#34;&gt;🔗&lt;/a&gt;&lt;/h1&gt;&lt;ul&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://gker.net/articles/2017/08/16/1502871430957.html#1-%E5%9F%BA%E6%9C%AC%E5%8C%B9%E9%85%8D&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;1. 基本匹配&lt;/a&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://gker.net/articles/2017/08/16/1502871430957.html#2-%E5%85%83%E5%AD%97%E7%AC%A6&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;2. 元字符&lt;/a&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://gker.net/articles/2017/08/16/1502871430957.html#21-%E7%82%B9%E8%BF%90%E7%AE%97%E7%AC%A6-&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;2.1 点运算符 .&lt;/a&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://gker.net/articles/2017/08/16/1502871430957.html#22-%E5%AD%97%E7%AC%A6%E9%9B%86&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;2.2 字符集&lt;/a&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://gker.net/articles/2017/08/16/1502871430957.html#221-%E5%90%A6%E5%AE%9A%E5%AD%97%E7%AC%A6%E9%9B%86&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;2.2.1 否定字符集&lt;/a&gt;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://gker.net/articles/2017/08/16/1502871430957.html#23-%E9%87%8D%E5%A4%8D%E6%AC%A1%E6%95%B0&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;2.3 重复次数&lt;/a&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://gker.net/articles/2017/08/16/1502871430957.html#231--%E5%8F%B7&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;2.3.1 * 号&lt;/a&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://gker.net/articles/2017/08/16/1502871430957.html#232--%E5%8F%B7&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;2.3.2 号&lt;/a&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://gker.net/articles/2017/08/16/1502871430957.html#233--%E5%8F%B7&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;2.3.3 ? 号&lt;/a&gt;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://gker.net/articles/2017/08/16/1502871430957.html#24--%E5%8F%B7&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;2.4 {} 号&lt;/a&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://gker.net/articles/2017/08/16/1502871430957.html#25--%E7%89%B9%E5%BE%81%E6%A0%87%E7%BE%A4&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;2.5 (&amp;hellip;) 特征标群&lt;/a&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://gker.net/articles/2017/08/16/1502871430957.html#26--%E6%88%96%E8%BF%90%E7%AE%97%E7%AC%A6&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;2.6 | 或运算符&lt;/a&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://gker.net/articles/2017/08/16/1502871430957.html#27-%E8%BD%AC%E7%A0%81%E7%89%B9%E6%AE%8A%E5%AD%97%E7%AC%A6&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;2.7 转码特殊字符&lt;/a&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://gker.net/articles/2017/08/16/1502871430957.html#28-%E9%94%9A%E7%82%B9&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;2.8 锚点&lt;/a&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://gker.net/articles/2017/08/16/1502871430957.html#281--%E5%8F%B7&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;2.8.1 ^ 号&lt;/a&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://gker.net/articles/2017/08/16/1502871430957.html#282--%E5%8F%B7&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;2.8.2 $ 号&lt;/a&gt;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://gker.net/articles/2017/08/16/1502871430957.html#3-%E7%AE%80%E5%86%99%E5%AD%97%E7%AC%A6%E9%9B%86&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;3. 简写字符集&lt;/a&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://gker.net/articles/2017/08/16/1502871430957.html#4-%E5%89%8D%E5%90%8E%E5%85%B3%E8%81%94%E7%BA%A6%E6%9D%9F%E5%89%8D%E5%90%8E%E9%A2%84%E6%9F%A5&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;4. 前后关联约束(前后预查)&lt;/a&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://gker.net/articles/2017/08/16/1502871430957.html#41--%E5%89%8D%E7%BD%AE%E7%BA%A6%E6%9D%9F%E5%AD%98%E5%9C%A8&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;4.1 ?=&amp;hellip; 前置约束(存在)&lt;/a&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://gker.net/articles/2017/08/16/1502871430957.html#42--%E5%89%8D%E7%BD%AE%E7%BA%A6%E6%9D%9F-%E6%8E%92%E9%99%A4&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;4.2 ?!&amp;hellip; 前置约束-排除&lt;/a&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://gker.net/articles/2017/08/16/1502871430957.html#43---%E5%90%8E%E7%BD%AE%E7%BA%A6%E6%9D%9F-%E5%AD%98%E5%9C%A8&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;4.3 ?&amp;lt;= &amp;hellip; 后置约束-存在&lt;/a&gt;&lt;/li&gt;&#xA;&lt;li&gt;[4.4 ? &lt;code&gt;the&lt;/code&gt;, 它表示一个规则: 由字母&lt;code&gt;t&lt;/code&gt;开始,接着是&lt;code&gt;h&lt;/code&gt;,再接着是&lt;code&gt;e&lt;/code&gt;.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;&amp;ldquo;the&amp;rdquo; =&amp;gt; The fat cat sat on &lt;a href=&#34;https://gker.net/articles/2017/08/16/1502871430957.html#learn-regex&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;&lt;strong&gt;the&lt;/strong&gt;&lt;/a&gt; mat.&lt;/p&gt;</description>
    </item>
    <item>
      <title>升级到Android Studio 3.0 Beta 1后编译错误解决</title>
      <link>https://gker.net/post/10016/</link>
      <pubDate>Thu, 10 Aug 2017 10:55:19 +0800</pubDate>
      <guid>https://gker.net/post/10016/</guid>
      <description>&lt;p&gt;如果现有的 Android Studio 项目使用的是 Android plugin 3.0.0  的 Alpha 版本（如 3.0.0-alpha9），那么迁移到 Android plugin 3.0.0-beta1 并进行&lt;a href=&#34;http://d.android.com/studio/build/index.html#sync-files&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;项目同步&lt;/a&gt;时，可能会收到以下错误 ：Gradle project refresh failed。&lt;/p&gt;&#xA;&lt;p&gt;解决方法：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;从菜单栏中选择 &lt;strong&gt;Build &amp;gt; Clean Project&lt;/strong&gt;，需要为每个项目执行一次这个操作。然后，可以通过从工具栏中单击同步项目，使用 Gradle 将项目文件同步。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;&lt;a href=&#34;https://androidstudio.googleblog.com/2017/08/android-studio-30-beta-1.html&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;官方解决方案链接&lt;/a&gt;&lt;/p&gt;</description>
    </item>
    <item>
      <title>记录AndroidStudio升级2.3后DataBinding与Realm注解冲突问题</title>
      <link>https://gker.net/post/10015/</link>
      <pubDate>Thu, 22 Jun 2017 19:45:12 +0800</pubDate>
      <guid>https://gker.net/post/10015/</guid>
      <description>&lt;p&gt;现象：&#xA;2.3后不支持apt了，所以旧版本Realm编译不通过。&lt;/p&gt;&#xA;&lt;p&gt;升级Realm后，DataBinding编译失败，报找不到BR错误。&lt;/p&gt;&#xA;&lt;p&gt;借助kotlin使用kapt &amp;ldquo;com.android.databinding:compiler:2.3.3&amp;quot;编译后，Realm的相应注解没有被解析，报is not part of the schema for this Realm错误&lt;/p&gt;&#xA;&lt;p&gt;最终解决：&#xA;所有用到注解的三方库，都得加上解释器：&#xA;annotationProcessor &amp;ldquo;com.android.databinding:compiler:2.3.3&amp;rdquo;&#xA;annotationProcessor &amp;lsquo;org.greenrobot:eventbus-annotation-processor:3.0.1&amp;rsquo;&#xA;annotationProcessor &amp;ldquo;io.realm:realm-annotations-processor:3.3.2&amp;rdquo;&lt;/p&gt;&#xA;&lt;p&gt;参考&#xA;1.https://stackoverflow.com/questions/38642712/enable-annotation-processors-option-in-android-studio-2-2&#xA;2.https://stackoverflow.com/questions/40940253/realm-and-android-databinding&#xA;3.https://developer.android.com/topic/libraries/data-binding/index.html&lt;/p&gt;</description>
    </item>
    <item>
      <title>搜索中文汉字的正则表达式</title>
      <link>https://gker.net/post/10014/</link>
      <pubDate>Sun, 18 Jun 2017 16:16:38 +0800</pubDate>
      <guid>https://gker.net/post/10014/</guid>
      <description>&lt;p&gt;^((?!(*|//)).)+[\u4e00-\u9fa5]&lt;/p&gt;</description>
    </item>
    <item>
      <title>Android手机上传下载文件夹</title>
      <link>https://gker.net/post/10013/</link>
      <pubDate>Fri, 16 Jun 2017 12:13:28 +0800</pubDate>
      <guid>https://gker.net/post/10013/</guid>
      <description>&lt;p&gt;批量从/sdcard/files目录下载文件到电脑：adb shell ls /sdcard/files/* | tr &amp;ldquo;\n\r&amp;rdquo; &amp;quot; &amp;quot; | xargs -n1 adb pull&lt;/p&gt;&#xA;&lt;p&gt;注意：如果permission denied，则先执行adb root，再执行adb remount,如果你不知道什么是root，那么就不要操作了。&lt;/p&gt;&#xA;&lt;p&gt;将整个目录下的文件上传到手机：adb push . /sdcard/files&lt;/p&gt;</description>
    </item>
    <item>
      <title>Android打开最近任务列表代码</title>
      <link>https://gker.net/post/10012/</link>
      <pubDate>Thu, 18 May 2017 16:17:18 +0800</pubDate>
      <guid>https://gker.net/post/10012/</guid>
      <description>&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;Class serviceManagerClass;&#xD;&#xA;try {&#xD;&#xA;    serviceManagerClass = Class.forName(&amp;#34;android.os.ServiceManager&amp;#34;);&#xD;&#xA;  Method getService = serviceManagerClass.getMethod(&amp;#34;getService&amp;#34;,&#xD;&#xA;  String.class);&#xD;&#xA;  IBinder retbinder = (IBinder) getService.invoke(&#xD;&#xA;            serviceManagerClass, &amp;#34;statusbar&amp;#34;);&#xD;&#xA;  Class statusBarClass = Class.forName(retbinder&#xD;&#xA;            .getInterfaceDescriptor());&#xD;&#xA;  Object statusBarObject = statusBarClass.getClasses()[0].getMethod(&#xD;&#xA;            &amp;#34;asInterface&amp;#34;, IBinder.class).invoke(null,&#xD;&#xA; new Object[]{retbinder});&#xD;&#xA;  Method clearAll = statusBarClass.getMethod(&amp;#34;toggleRecentApps&amp;#34;);&#xD;&#xA;  clearAll.setAccessible(true);&#xD;&#xA;  clearAll.invoke(statusBarObject);&#xD;&#xA;} catch (Exception e) {&#xD;&#xA;    e.printStackTrace();&#xD;&#xA;}&#xA;&lt;/code&gt;&lt;/pre&gt;</description>
    </item>
    <item>
      <title>Activity的启动过程拦截Intent参数</title>
      <link>https://gker.net/post/10011/</link>
      <pubDate>Tue, 18 Apr 2017 18:14:10 +0800</pubDate>
      <guid>https://gker.net/post/10011/</guid>
      <description>&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;import  android.content.ComponentName;&#xD;&#xA;import android.content.Context;&#xD;&#xA;import android.content.Intent;&#xD;&#xA;import android.os.Bundle;&#xD;&#xA;import android.os.Handler;&#xD;&#xA;import android.os.Message;&#xD;&#xA;import android.util.Log;&#xD;&#xA;&#xD;&#xA;import java.lang.reflect.Field;&#xD;&#xA;import java.lang.reflect.InvocationHandler;&#xD;&#xA;import java.lang.reflect.Method;&#xD;&#xA;import java.lang.reflect.Proxy;&#xD;&#xA;&#xD;&#xA;public class HookUtil {&#xD;&#xA;&#xD;&#xA;    private Class proxyActivity;&#xD;&#xA;&#xD;&#xA; private Context context;&#xD;&#xA;&#xD;&#xA; public HookUtil(Context context) {&#xD;&#xA;        try {&#xD;&#xA;            this.proxyActivity = Class.forName(&amp;#34;class&amp;#34;);&#xD;&#xA;  } catch (ClassNotFoundException e) {&#xD;&#xA;            e.printStackTrace();&#xD;&#xA;  }&#xD;&#xA;        this.context = context;&#xD;&#xA;  }&#xD;&#xA;&#xD;&#xA;    public void hookSystemHandler() {&#xD;&#xA;        try {&#xD;&#xA;&#xD;&#xA;            Class activityThreadClass = Class.forName(&amp;#34;android.app.ActivityThread&amp;#34;);&#xD;&#xA;  Method currentActivityThreadMethod = activityThreadClass.getDeclaredMethod(&amp;#34;currentActivityThread&amp;#34;);&#xD;&#xA;  currentActivityThreadMethod.setAccessible(true);&#xD;&#xA;  //获取主线程对象&#xD;&#xA;  Object activityThread = currentActivityThreadMethod.invoke(null);&#xD;&#xA;  //获取mH字段&#xD;&#xA;  Field mH = activityThreadClass.getDeclaredField(&amp;#34;mH&amp;#34;);&#xD;&#xA;  mH.setAccessible(true);&#xD;&#xA;  //获取Handler&#xD;&#xA;  Handler handler = (Handler) mH.get(activityThread);&#xD;&#xA;  //获取原始的mCallBack字段&#xD;&#xA;  Field mCallBack = Handler.class.getDeclaredField(&amp;#34;mCallback&amp;#34;);&#xD;&#xA;  mCallBack.setAccessible(true);&#xD;&#xA;  //这里设置了我们自己实现了接口的CallBack对象&#xD;&#xA;  mCallBack.set(handler, new ActivityThreadHandlerCallback(handler));&#xD;&#xA;&#xD;&#xA;  } catch (Exception e) {&#xD;&#xA;            e.printStackTrace();&#xD;&#xA;  }&#xD;&#xA;    }&#xD;&#xA;&#xD;&#xA;    public void hookAms() {&#xD;&#xA;&#xD;&#xA;        //一路反射，直到拿到IActivityManager的对象&#xD;&#xA;  try {&#xD;&#xA;            Class ActivityManagerNativeClss = Class.forName(&amp;#34;android.app.ActivityManagerNative&amp;#34;);&#xD;&#xA;  Field defaultFiled = ActivityManagerNativeClss.getDeclaredField(&amp;#34;gDefault&amp;#34;);&#xD;&#xA;  defaultFiled.setAccessible(true);&#xD;&#xA;  Object defaultValue = defaultFiled.get(null);&#xD;&#xA;  //反射SingleTon&#xD;&#xA;  Class SingletonClass = Class.forName(&amp;#34;android.util.Singleton&amp;#34;);&#xD;&#xA;  Field mInstance = SingletonClass.getDeclaredField(&amp;#34;mInstance&amp;#34;);&#xD;&#xA;  mInstance.setAccessible(true);&#xD;&#xA;  //到这里已经拿到ActivityManager对象&#xD;&#xA;  Object iActivityManagerObject = mInstance.get(defaultValue);&#xD;&#xA;&#xD;&#xA;  //开始动态代理，用代理对象替换掉真实的ActivityManager，瞒天过海&#xD;&#xA;  Class IActivityManagerIntercept = Class.forName(&amp;#34;android.app.IActivityManager&amp;#34;);&#xD;&#xA;&#xD;&#xA;  AmsInvocationHandler handler = new AmsInvocationHandler(iActivityManagerObject);&#xD;&#xA;&#xD;&#xA;  Object proxy = Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), new Class[]{IActivityManagerIntercept}, handler);&#xD;&#xA;&#xD;&#xA;  //现在替换掉这个对象&#xD;&#xA;  mInstance.set(defaultValue, proxy);&#xD;&#xA;&#xD;&#xA;  } catch (Exception e) {&#xD;&#xA;            e.printStackTrace();&#xD;&#xA;  }&#xD;&#xA;    }&#xD;&#xA;&#xD;&#xA;    private class ActivityThreadHandlerCallback implements Handler.Callback {&#xD;&#xA;&#xD;&#xA;        private Handler handler;&#xD;&#xA;&#xD;&#xA; private ActivityThreadHandlerCallback(Handler handler) {&#xD;&#xA;            this.handler = handler;&#xD;&#xA;  }&#xD;&#xA;&#xD;&#xA;        @Override&#xD;&#xA;  public boolean handleMessage(Message msg) {&#xD;&#xA;            Log.i(&amp;#34;HookAmsUtil&amp;#34;, &amp;#34;handleMessage&amp;#34;);&#xD;&#xA;  //替换之前的Intent&#xD;&#xA;  if (msg.what == 100) {&#xD;&#xA;                Log.i(&amp;#34;HookAmsUtil&amp;#34;, &amp;#34;lauchActivity&amp;#34;);&#xD;&#xA;  handleLauchActivity(msg);&#xD;&#xA;  }&#xD;&#xA;&#xD;&#xA;            handler.handleMessage(msg);&#xD;&#xA; return true;  }&#xD;&#xA;&#xD;&#xA;        private void handleLauchActivity(Message msg) {&#xD;&#xA;            Object obj = msg.obj;//ActivityClientRecord&#xD;&#xA;  try {&#xD;&#xA;                Field intentField = obj.getClass().getDeclaredField(&amp;#34;intent&amp;#34;);&#xD;&#xA;  intentField.setAccessible(true);&#xD;&#xA;  Intent proxyInent = (Intent) intentField.get(obj);&#xD;&#xA;  Intent realIntent = proxyInent.getParcelableExtra(&amp;#34;oldIntent&amp;#34;);&#xD;&#xA; if (realIntent != null) {&#xD;&#xA;                    proxyInent.setComponent(realIntent.getComponent());&#xD;&#xA;  }&#xD;&#xA;            } catch (Exception e) {&#xD;&#xA;                Log.i(&amp;#34;HookAmsUtil&amp;#34;, &amp;#34;lauchActivity falied&amp;#34;);&#xD;&#xA;  }&#xD;&#xA;&#xD;&#xA;        }&#xD;&#xA;    }&#xD;&#xA;&#xD;&#xA;    public class AmsInvocationHandler implements InvocationHandler {&#xD;&#xA;&#xD;&#xA;        private Object iActivityManagerObject;&#xD;&#xA;&#xD;&#xA; public AmsInvocationHandler(Object iActivityManagerObject) {&#xD;&#xA;            this.iActivityManagerObject = iActivityManagerObject;&#xD;&#xA;  }&#xD;&#xA;&#xD;&#xA;        @Override&#xD;&#xA;  public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {&#xD;&#xA;&#xD;&#xA;            Log.i(&amp;#34;HookUtil&amp;#34;, method.getName());&#xD;&#xA; if (&amp;#34;startActivity&amp;#34;.contains(method.getName())) {&#xD;&#xA;                Log.e(&amp;#34;HookUtil&amp;#34;, &amp;#34;Activity已经开始启动&amp;#34;);&#xD;&#xA;  //换掉&#xD;&#xA;  Intent intent = null;&#xD;&#xA; int index = 0;&#xD;&#xA; for (int i = 0; i &amp;lt; args.length; i++) {&#xD;&#xA;                    Object arg = args[i];&#xD;&#xA; if (arg instanceof Intent) {&#xD;&#xA;                        //说明找到了startActivity的Intent参数&#xD;&#xA;  intent = (Intent) args[i];&#xD;&#xA;  //这个意图是不能被启动的，因为Acitivity没有在清单文件中注册&#xD;&#xA;  index = i;&#xD;&#xA; if (intent != null) {&#xD;&#xA;                            Bundle extras = intent.getExtras();&#xD;&#xA; if (extras != null &amp;amp;&amp;amp; extras.keySet() != null) {&#xD;&#xA;                                for (String key : extras.keySet()) {&#xD;&#xA;                                    Log.d(&amp;#34;HookUtil&amp;#34;, &amp;#34;intent.extras.key=&amp;#34; + key + &amp;#34;,value=&amp;#34; + extras.get(key));&#xD;&#xA;  }&#xD;&#xA;                            }&#xD;&#xA;                            Log.d(&amp;#34;HookUtil&amp;#34;, extras + &amp;#34;&amp;#34;);&#xD;&#xA;  }&#xD;&#xA;                    }&#xD;&#xA;                }&#xD;&#xA;&#xD;&#xA;                //伪造一个代理的Intent，代理Intent启动的是proxyActivity&#xD;&#xA;  if (context != null &amp;amp;&amp;amp; proxyActivity != null) {&#xD;&#xA;                    Intent proxyIntent = new Intent();&#xD;&#xA;  ComponentName componentName = new ComponentName(context, proxyActivity);&#xD;&#xA;  proxyIntent.setComponent(componentName);&#xD;&#xA;  proxyIntent.putExtra(&amp;#34;oldIntent&amp;#34;, intent);&#xD;&#xA;  args[index] = proxyIntent;&#xD;&#xA;  }&#xD;&#xA;            }&#xD;&#xA;&#xD;&#xA;            return method.invoke(iActivityManagerObject, args);&#xD;&#xA;  }&#xD;&#xA;    }&#xD;&#xA;}&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;在Application中的onCreate函数中插桩&lt;/p&gt;</description>
    </item>
    <item>
      <title>RxAndroid学习笔记</title>
      <link>https://gker.net/post/10010/</link>
      <pubDate>Fri, 14 Apr 2017 16:15:15 +0800</pubDate>
      <guid>https://gker.net/post/10010/</guid>
      <description>&lt;p&gt;学习RX的原因各有不同，但是目的都一样，就是学会使用RX。想要学会使用RX，最好理解Rx的编程思想。&lt;/p&gt;&#xA;&lt;p&gt;官方网站：http://reactivex.io/&#xA;官方对RX的解释：ReactiveX is a library for composing asynchronous and event-based programs by using observable sequences.&lt;/p&gt;&#xA;&lt;p&gt;RxJava文档的中文翻译&#xA;&lt;a href=&#34;https://mcxiaoke.gitbooks.io/rxdocs&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;https://mcxiaoke.gitbooks.io/rxdocs&lt;/a&gt;&lt;/p&gt;&#xA;&lt;p&gt;比较精华的文章&#xA;&lt;a href=&#34;http://gank.io/post/560e15be2dca930e00da1083&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;《给Android开发者的RxJava详解》 by:扔物线&lt;/a&gt;&#xA;&lt;a href=&#34;http://blog.csdn.net/lzyzsd/article/details/41833541&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;《深入浅出RxJava》 by:大头鬼&lt;/a&gt;&#xA;&lt;a href=&#34;https://segmentfault.com/a/1190000004049490&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;《谜之RxJava》 by:Gemini&lt;/a&gt;&#xA;&lt;a href=&#34;http://www.jianshu.com/p/7fd42c262982&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;《RxJava之旅》 by:Chuckiefan&lt;/a&gt;&#xA;&lt;a href=&#34;http://www.jianshu.com/u/c50b715ccaeb&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;《给初学者的RxJava2.0教程》系列 by:Season_zlc&lt;/a&gt;&lt;/p&gt;&#xA;&lt;p&gt;RX官方解释为响应式编程。而Chuckiefan指出理解响应式编程首先要养成一切皆数据流的编程思维、理解异步编程和观察者模式，并将响应式编程与面向过程编程和面向对象编程并列。可见，如果不理解其编程思想，很难熟练运用RX。&lt;/p&gt;&#xA;&lt;p&gt;Season_zlc的水管理论通俗易懂，建议认真阅读。&lt;/p&gt;</description>
    </item>
    <item>
      <title>Notification播放apk中自带raw音频</title>
      <link>https://gker.net/post/10007/</link>
      <pubDate>Wed, 15 Mar 2017 09:45:54 +0800</pubDate>
      <guid>https://gker.net/post/10007/</guid>
      <description>&lt;ul&gt;&#xA;&lt;li&gt;本场景为自定义Notification的声音&lt;/li&gt;&#xA;&lt;li&gt;根本解决方式是修改notification的sound&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;notification.sound =Uri sound;&#xD;&#xA;//或者&#xD;&#xA;NotificationCompat.Builder.setSound(Uri sound)&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&#xA;&lt;li&gt;Uri的规范可以参考 &lt;a href=&#34;http://www.ietf.org/rfc/rfc2396.txt&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;http://www.ietf.org/rfc/rfc2396.txt&lt;/a&gt; 以下为示例&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;Uri sound=Uri.parse(&amp;#34;android.resource://&amp;#34; + getPackageName() + &amp;#34;/&amp;#34; + R.raw.notificationsound );  &#xD;&#xA;//或者&#xD;&#xA;Uri sound=Uri.parse(ContentResolver.SCHEME_ANDROID_RESOURCE + &amp;#34;://&amp;#34; + getPackageName() + &amp;#34;/raw/notificationsound&amp;#34;); &#xD;&#xA;//或者&#xD;&#xA;Uri sound=Uri.parse(ContentResolver.SCHEME_ANDROID_RESOURCE + &amp;#34;://&amp;#34; + getPackageName() + &amp;#34;/&amp;#34;+R.raw.notificationsound); &#xD;&#xA;//或者从铃声管理器获取 &#xD;&#xA;Uri sound= RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&#xA;&lt;li&gt;也可以将一个无声音的音频文件指定给notification使其静音，然后启用MediaPlayer播放铃声。播放代码如下：&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;try {&#xD;&#xA;  Context context = Application.getInstance();&#xD;&#xA;  MediaPlayer mediaPlayer;&#xD;&#xA;  if (rawId &amp;gt; 0) {&#xD;&#xA;        if (Build.VERSION.SDK_INT &amp;lt; Build.VERSION_CODES.LOLLIPOP) {&#xD;&#xA;            mediaPlayer = MediaPlayer.create(context, rawId);&#xD;&#xA;&#x9;&#x9;} else {&#xD;&#xA;&#x9;&#x9;  int sessionId = ((AudioManager) context.getSystemService(Context.AUDIO_SERVICE)).generateAudioSessionId();&#xD;&#xA;&#x9;&#x9;  AudioAttributes audioAttributes = new AudioAttributes.Builder()&#xD;&#xA;&#x9;&#x9;&#x9;&#x9;  .setUsage(AudioAttributes.USAGE_NOTIFICATION)&#xD;&#xA;&#x9;&#x9;&#x9;&#x9;  .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)&#xD;&#xA;&#x9;&#x9;&#x9;&#x9;  .setLegacyStreamType(AudioManager.STREAM_NOTIFICATION)&#xD;&#xA;&#x9;&#x9;&#x9;&#x9;  .build();&#xD;&#xA;&#x9;&#x9;  mediaPlayer = MediaPlayer.create(context, rawId, audioAttributes, sessionId);&#xD;&#xA;&#x9;&#x9;}&#xD;&#xA;    } else {&#xD;&#xA;        mediaPlayer = MediaPlayer.create(context, RingtoneManager.getActualDefaultRingtoneUri(context, RingtoneManager.TYPE_NOTIFICATION));&#xD;&#xA;    }&#xD;&#xA;&#x9; //使用MediaPlayer.create(context, R.raw.mingdao)这种方式创建的MediaPlayer已经prepare完成，且不能修改AudioStreamType&#xD;&#xA;&#x9; //mediaPlayer.setAudioStreamType(AudioManager.STREAM_ALARM);  &#xD;&#xA;&#x9; mediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {&#xD;&#xA;        @Override&#xD;&#xA;&#x9;&#x9;public void onCompletion(MediaPlayer mediaPlayer) {&#xD;&#xA;            mediaPlayer.release();&#xD;&#xA;&#x9;}&#xD;&#xA;    });&#xD;&#xA;&#x9;mediaPlayer.start();&#xD;&#xA;} catch (Exception e) {&#xD;&#xA;    e.printStackTrace();&#xD;&#xA;}&#xA;&lt;/code&gt;&lt;/pre&gt;</description>
    </item>
    <item>
      <title>初衷</title>
      <link>https://gker.net/post/10000/</link>
      <pubDate>Wed, 01 Aug 2007 13:51:14 +0800</pubDate>
      <guid>https://gker.net/post/10000/</guid>
      <description>&lt;h1 id=&#34;个人记录网建设初衷&#34;&gt;个人记录网建设初衷 &lt;a href=&#34;#%e4%b8%aa%e4%ba%ba%e8%ae%b0%e5%bd%95%e7%bd%91%e5%bb%ba%e8%ae%be%e5%88%9d%e8%a1%b7&#34; class=&#34;anchor&#34;&gt;🔗&lt;/a&gt;&lt;/h1&gt;&lt;ul&gt;&#xA;&lt;li&gt;自2007年毕业工作以来，起初使用notepad记录工作心得。&lt;/li&gt;&#xA;&lt;li&gt;2008年伊始，对比了多家博客，采用百度空间开始记录博客，可惜百度空间于2012年关闭。&lt;/li&gt;&#xA;&lt;li&gt;2012-2017年期间使用印象笔记,可惜其较为封闭，不方便共享于众网友同仁。&lt;/li&gt;&#xA;&lt;li&gt;2017年开始了，鉴于百度空间关闭的前车之鉴，所以自建博客，用以共勉。&lt;/li&gt;&#xA;&lt;li&gt;2020年了，改用hugo，使用静态网站。&lt;/li&gt;&#xA;&lt;/ul&gt;</description>
    </item>
  </channel>
</rss>
