Android EditText禁止输入中文字符

只允许EditText输入数字或者email格式字符是非常简单的(详见API文档)。 要实现只允许输入自定的数字字符也是很容易的(详见API文档,[setKeyListener(KeyListener)](http://blog.csdn.net/reference/android/widget/TextView.html#setKeyListener(android.text.method.KeyListener)) 和<span class="sympad">setFilters</span> <span class="normal">([InputFilter[]](http://blog.csdn.net/reference/android/text/InputFilter.html) filters)</span> )。 但是要限制只能输入指定的字母字符就非常的困难。 /** InputFilter[] ifs = {new InputFilter.LengthFilter(10),new DigitsKeyListener(true,true)}; editText01.setFilters(ifs); **/ &nbsp; 发现,**[Android](http://lib.csdn.net/base/15):digits**的参数是一个字符串,没有更多的语义检查,因此想到内部处理很可能仅是简单的检查,输入的字符是否在给定的字符串中(要我设计,我就这样做)。尝试着给它指定带有英文字符的参数,发现果然如此。万幸,万幸! 在layout.xml里 **[xml]** [view plain](http://blog.csdn.net/jdsjlzx/article/details/6762751#) [copy](http://blog.csdn.net/jdsjlzx/article/details/6762751#) <div> <embed id="ZeroClipboardMovie_1" src="http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf" type="application/x-shockwave-flash" width="18" height="18" align="middle" name="ZeroClipboardMovie_1"> </embed> </div> </div> </div> - <span class="tag"><</span><span class="tag-name">EditText</span> - <span class="attribute">android:id</span>=<span class="attribute-value">&#8220;@+id/register_userName_editText&#8221;</span> - <span class="attribute">style</span>=<span class="attribute-value">&#8220;@style/register_editText_style&#8221;</span> - <span class="attribute">android:digits</span>=<span class="attribute-value">&#8220;@string/register_name_digits&#8221;</span> - <span class="attribute">android:textColor</span>=<span class="attribute-value">&#8220;@drawable/register_edit_text_textColor&#8221;</span> - <span class="attribute">android:textColorHint</span>=<span class="attribute-value">&#8220;@drawable/register_hint_text_textColor&#8221;</span> - <span class="attribute">android:hint</span>=<span class="attribute-value">&#8220;@string/register_name_hint_text&#8221;</span> - <span class="tag">/></span> &nbsp; 在string.xml里 &nbsp; **[xml]** [view plain](http://blog.csdn.net/jdsjlzx/article/details/6762751#) [copy](http://blog.csdn.net/jdsjlzx/article/details/6762751#) <div> <embed id="ZeroClipboardMovie_2" src="http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf" type="application/x-shockwave-flash" width="18" height="18" align="middle" name="ZeroClipboardMovie_2"> </embed> </div> </div> </div> - <span class="tag"><</span><span class="tag-name">string</span> <span class="attribute">name</span>=<span class="attribute-value">&#8220;register_name_digits&#8221;</span><span class="tag">></span> - - ._0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLIMNOPQRSTUVWXYZ - - <span class="tag"></</span><span class="tag-name">string</span><span class="tag">></span> &nbsp; &nbsp; &nbsp; &nbsp; Java代码 - editText01.addTextChangedListener(<span class="keyword">new</span> TextWatcher() { - String tmp = <span class="string">&#8220;&#8221;</span>; - String digits = <span class="string">&#8220;abcdef&#8221;</span>; - <span class="annotation">@Override</span> - <span class="keyword">public</span> <span class="keyword">void</span> onTextChanged(CharSequence s, <span class="keyword">int</span> start, <span class="keyword">int</span> before, <span class="keyword">int</span> count) { - } - <span class="annotation">@Override</span> - <span class="keyword">public</span> <span class="keyword">void</span> beforeTextChanged(CharSequence s, <span class="keyword">int</span> start, <span class="keyword">int</span> count, <span class="keyword">int</span> after) { - tmp = s.toString(); - } - - <span class="annotation">@Override</span> - <span class="keyword">public</span> <span class="keyword">void</span> afterTextChanged(Editable s) { - Log.d(Sample4Main.TAG, <span class="string">&#8220;<><>afterTextChanged<><>&#8221;</span> + s.toString()); - - String str = s.toString(); - <span class="keyword">if</span>(str.equals(tmp)){ - <span class="keyword">return</span>; - } - - StringBuffer sb = <span class="keyword">new</span> StringBuffer(); - <span class="keyword">for</span>(<span class="keyword">int</span> i = <span class="number"></span>; i < str.length(); i++){ - <span class="keyword">if</span>(digits.indexOf(str.charAt(i)) >= <span class="number"></span>){ - sb.append(str.charAt(i)); - } - } - tmp = sb.toString(); - editText01.setText(tmp); - } - });

2016年7月20日 · 2 分钟 · 天边的星星

【Android】自定义控件让TextView的drawableLeft与文本一起居中显示

前言 TextView的drawableLeft、drawableRight和drawableTop是一个常用、好用的属性,可以在文本的上下左右放置一个图片,而不使用更加复杂布局就能达到,我也常常喜欢用RadioButton的这几个属性实现很多效果,但是苦于不支持让drawbleLeft与文本一起居中,设置gravity为center也无济于事,终于有空研究了一下,这里与大家一起分享。 声明 欢迎转载,请注明出处! 博客园:http://www.cnblogs.com/ 农民伯伯: http://www.cnblogs.com/over140/ 正文 一、效果图 二、实现代码 自定义控件 ![复制代码](http://common.cnblogs.com/images/copycode.gif) /** * drawableLeft与文本一起居中显示 * * @author 农民伯伯 * @see http://www.cnblogs.com/over140/p/3464348.html * */ public class DrawableCenterTextView extends TextView { public DrawableCenterTextView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); } public DrawableCenterTextView(Context context, AttributeSet attrs) { super(context, attrs); } public DrawableCenterTextView(Context context) { super(context); } @Override protected void onDraw(Canvas canvas) { Drawable[] drawables = getCompoundDrawables(); if (drawables != null) { Drawable drawableLeft = drawables[0]; if (drawableLeft != null) { float textWidth = getPaint().measureText(getText().toString()); int drawablePadding = getCompoundDrawablePadding(); int drawableWidth = 0; drawableWidth = drawableLeft.getIntrinsicWidth(); float bodyWidth = textWidth + drawableWidth + drawablePadding; } } super.onDraw(canvas); } } ...

2016年7月19日 · 1 分钟 · 天边的星星

Android share绘制虚线在手机上显示实线问题

可以说这是一个Bug, 据说在4.0以上机器会出现,我测试是android 4.4.2 Xml代码 <embed src="http://wv1124.iteye.com/javascripts/syntaxhighlighter/clipboard_new.swf" type="application/x-shockwave-flash" width="14" height="15"> </embed> <a title="收藏这段代码">![收藏代码](http://wv1124.iteye.com/images/icon_star.png)</a> </div> - <span class="tag"><?</span><span class="tag-name">xml</span> <span class="attribute">version</span>=<span class="attribute-value">&#8220;1.0&#8221;</span> <span class="attribute">encoding</span>=<span class="attribute-value">&#8220;utf-8&#8221;</span><span class="tag">?></span> - <span class="tag"><</span><span class="tag-name">shape</span> <span class="attribute">xmlns:android</span>=<span class="attribute-value">&#8220;http://schemas.android.com/apk/res/android&#8221;</span> - <span class="attribute">android:shape</span>=<span class="attribute-value">&#8220;line&#8221;</span> <span class="tag">></span> - - <span class="tag"><</span><span class="tag-name">stroke</span> - <span class="attribute">android:dashGap</span>=<span class="attribute-value">&#8220;3dp&#8221;</span> - <span class="attribute">android:dashWidth</span>=<span class="attribute-value">&#8220;8dp&#8221;</span> - <span class="attribute">android:width</span>=<span class="attribute-value">&#8220;1dp&#8221;</span> - <span class="attribute">android:color</span>=<span class="attribute-value">&#8220;#999999&#8221;</span> <span class="tag">/></span> - - <span class="tag"><</span><span class="tag-name">size</span> <span class="attribute">android:height</span>=<span class="attribute-value">&#8220;1dp&#8221;</span> <span class="tag">/></span> - - <span class="tag"></</span><span class="tag-name">shape</span><span class="tag">></span> layout中引用: ...

2016年7月19日 · 2 分钟 · 天边的星星

InputStream与String,Byte之间互转

本文将介绍InputStream与String,Byte之间的相互转换。以代码来说明: **[html]** [view plain](http://blog.csdn.net/cjjky/article/details/6892443#) [copy](http://blog.csdn.net/cjjky/article/details/6892443#) <div> <embed id="ZeroClipboardMovie_1" src="http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf" type="application/x-shockwave-flash" width="18" height="18" align="middle" name="ZeroClipboardMovie_1"> </embed> </div> </div> - import java.io.ByteArrayInputStream; - import java.io.ByteArrayOutputStream; - import java.io.IOException; - import java.io.InputStream; - - /** - * - * @author Andy.Chen - * @mail Chenjunjun.ZJ@gmail.com - * - */ - public class InputStreamUtils { - - final static int <span class="attribute">BUFFER_SIZE</span> = <span class="attribute-value">4096</span>; - - /** - * 将InputStream转换成String - * @param in InputStream - * @return String - * @throws Exception - * - */ - public static String InputStreamTOString(InputStream in) throws Exception{ - - ByteArrayOutputStream <span class="attribute">outStream</span> = <span class="attribute-value">new</span> ByteArrayOutputStream(); - byte[] <span class="attribute">data</span> = <span class="attribute-value">new</span> byte[BUFFER_SIZE]; - int <span class="attribute">count</span> = -1; - while((<span class="attribute">count</span> = <span class="attribute-value">in</span>.read(data,0,BUFFER_SIZE)) != -1) - outStream.write(data, 0, count); - - <span class="attribute">data</span> = <span class="attribute-value">null</span>; - return new String(outStream.toByteArray(),&#8221;ISO-8859-1&#8243;); - } - - /** - * 将InputStream转换成某种字符编码的String - * @param in - * @param encoding - * @return - * @throws Exception - */ - public static String InputStreamTOString(InputStream in,String encoding) throws Exception{ - - ByteArrayOutputStream <span class="attribute">outStream</span> = <span class="attribute-value">new</span> ByteArrayOutputStream(); - byte[] <span class="attribute">data</span> = <span class="attribute-value">new</span> byte[BUFFER_SIZE]; - int <span class="attribute">count</span> = -1; - while((<span class="attribute">count</span> = <span class="attribute-value">in</span>.read(data,0,BUFFER_SIZE)) != -1) - outStream.write(data, 0, count); - - <span class="attribute">data</span> = <span class="attribute-value">null</span>; - return new String(outStream.toByteArray(),&#8221;ISO-8859-1&#8243;); - } - - /** - * 将String转换成InputStream - * @param in - * @return - * @throws Exception - */ - public static InputStream StringTOInputStream(String in) throws Exception{ - - ByteArrayInputStream <span class="attribute">is</span> = <span class="attribute-value">new</span> ByteArrayInputStream(in.getBytes(&#8220;ISO-8859-1&#8221;)); - return is; - } - - /** - * 将InputStream转换成byte数组 - * @param in InputStream - * @return byte[] - * @throws IOException - */ - public static byte[] InputStreamTOByte(InputStream in) throws IOException{ - - ByteArrayOutputStream <span class="attribute">outStream</span> = <span class="attribute-value">new</span> ByteArrayOutputStream(); - byte[] <span class="attribute">data</span> = <span class="attribute-value">new</span> byte[BUFFER_SIZE]; - int <span class="attribute">count</span> = -1; - while((<span class="attribute">count</span> = <span class="attribute-value">in</span>.read(data,0,BUFFER_SIZE)) != -1) - outStream.write(data, 0, count); - - <span class="attribute">data</span> = <span class="attribute-value">null</span>; - return outStream.toByteArray(); - } - - /** - * 将byte数组转换成InputStream - * @param in - * @return - * @throws Exception - */ - public static InputStream byteTOInputStream(byte[] in) throws Exception{ - - ByteArrayInputStream <span class="attribute">is</span> = <span class="attribute-value">new</span> ByteArrayInputStream(in); - return is; - } - - /** - * 将byte数组转换成String - * @param in - * @return - * @throws Exception - */ - public static String byteTOString(byte[] in) throws Exception{ - - InputStream <span class="attribute">is</span> = <span class="attribute-value">byteTOInputStream</span>(in); - return InputStreamTOString(is); - } - - }

2016年7月18日 · 2 分钟 · 天边的星星

Android禁止ViewPager的左右滑动

有时候在开发中会遇到一些“诡异”的要求,比如在ViewPager中嵌入ListView,或者再嵌入一个ViewPager,那么在滑动的时候就会造成被嵌入的XXView不能滑动了,那么现在就把最外层的ViewPager禁止滑动吧,让被嵌入的XXView获得滑动事件好了。关于解决方法,网上也有很多说法,基本上是一致的,但是需要理解这个[Android](http://lib.csdn.net/base/15)下的事件分发机制才行,不明白事件分发机制的,上网查些资料看看,然后我这里也有简单的介绍,请参看博客Android自定义控件——侧滑菜单的下方。 怎样禁止ViewPager左右滑动呢?大致就是重写ViewPager,覆盖ViewPager的onInterceptTouchEvent(MotionEvent arg0)方法和onTouchEvent(MotionEvent arg0)方法,这两个方法的返回值都是boolean类型的,只需要将返回值改为false,那么ViewPager就不会消耗掉手指滑动的事件了,转而传递给上层View去处理或者该事件就直接终止了。下面是我的自定义ViewPager。 ``` `<span class=“hljs-keyword”>public</span> <span class=“hljs-class”><span class=“hljs-keyword”>class</span> <span class=“hljs-title”>NoScrollViewPager</span> <span class=“hljs-keyword”>extends</span> <span class=“hljs-title”>ViewPager</span> {</span> <span class=“hljs-keyword”>private</span> <span class=“hljs-keyword”>boolean</span> noScroll = <span class=“hljs-keyword”>false</span>; &lt;span class="hljs-keyword">public&lt;/span> &lt;span class="hljs-title">NoScrollViewPager&lt;/span>(Context context, AttributeSet attrs) { &lt;span class="hljs-keyword">super&lt;/span>(context, attrs); &lt;span class="hljs-comment">// TODO Auto-generated constructor stub&lt;/span> } &lt;span class="hljs-keyword">public&lt;/span> &lt;span class="hljs-title">NoScrollViewPager&lt;/span>(Context context) { &lt;span class="hljs-keyword">super&lt;/span>(context); } &lt;span class="hljs-keyword">public&lt;/span> &lt;span class="hljs-keyword">void&lt;/span> &lt;span class="hljs-title">setNoScroll&lt;/span>(&lt;span class="hljs-keyword">boolean&lt;/span> noScroll) { &lt;span class="hljs-keyword">this&lt;/span>.noScroll = noScroll; } &lt;span class="hljs-annotation">@Override&lt;/span> &lt;span class="hljs-keyword">public&lt;/span> &lt;span class="hljs-keyword">void&lt;/span> &lt;span class="hljs-title">scrollTo&lt;/span>(&lt;span class="hljs-keyword">int&lt;/span> x, &lt;span class="hljs-keyword">int&lt;/span> y) { &lt;span class="hljs-keyword">super&lt;/span>.scrollTo(x, y); } &lt;span class="hljs-annotation">@Override&lt;/span> &lt;span class="hljs-keyword">public&lt;/span> &lt;span class="hljs-keyword">boolean&lt;/span> &lt;span class="hljs-title">onTouchEvent&lt;/span>(MotionEvent arg0) { &lt;span class="hljs-comment">/* return false;//super.onTouchEvent(arg0); */&lt;/span> &lt;span class="hljs-keyword">if&lt;/span> (noScroll) &lt;span class="hljs-keyword">return&lt;/span> &lt;span class="hljs-keyword">false&lt;/span>; &lt;span class="hljs-keyword">else&lt;/span> &lt;span class="hljs-keyword">return&lt;/span> &lt;span class="hljs-keyword">super&lt;/span>.onTouchEvent(arg0); } &lt;span class="hljs-annotation">@Override&lt;/span> &lt;span class="hljs-keyword">public&lt;/span> &lt;span class="hljs-keyword">boolean&lt;/span> &lt;span class="hljs-title">onInterceptTouchEvent&lt;/span>(MotionEvent arg0) { &lt;span class="hljs-keyword">if&lt;/span> (noScroll) &lt;span class="hljs-keyword">return&lt;/span> &lt;span class="hljs-keyword">false&lt;/span>; &lt;span class="hljs-keyword">else&lt;/span> &lt;span class="hljs-keyword">return&lt;/span> &lt;span class="hljs-keyword">super&lt;/span>.onInterceptTouchEvent(arg0); } &lt;span class="hljs-annotation">@Override&lt;/span> &lt;span class="hljs-keyword">public&lt;/span> &lt;span class="hljs-keyword">void&lt;/span> &lt;span class="hljs-title">setCurrentItem&lt;/span>(&lt;span class="hljs-keyword">int&lt;/span> item, &lt;span class="hljs-keyword">boolean&lt;/span> smoothScroll) { &lt;span class="hljs-keyword">super&lt;/span>.setCurrentItem(item, smoothScroll); } &lt;span class="hljs-annotation">@Override&lt;/span> &lt;span class="hljs-keyword">public&lt;/span> &lt;span class="hljs-keyword">void&lt;/span> &lt;span class="hljs-title">setCurrentItem&lt;/span>(&lt;span class="hljs-keyword">int&lt;/span> item) { &lt;span class="hljs-keyword">super&lt;/span>.setCurrentItem(item); } }` ...

2016年7月15日 · 1 分钟 · 天边的星星

Android下如何计算要显示的字符串所占的宽度和高度

查询了google发现在android一下有几种方法可以做到,但是经过实际测试发现下面这种方法是最准确的 Rect bounds = new Rect(); String text = "Hello World"; TextPaint paint; paint = findViewById(R.id.hello_world).getPaint(); paint.getTextBounds(text, 0, text.length(), bounds); int width = bounds.width(); ``` Paint pFont = new Paint(); Rect rect = new Rect(); pFont.getTextBounds("豆", 0, 1, rect); Log.v(TAG, "height:"+rect.height()+"width:"+rect.width()); ## Android_FontMetrics对象的各种基准线(以及怎么获取文字的width和height) </div> Canvas 作为绘制文本时,使用FontMetrics对象,计算位置的坐标。 public static class FontMetrics { /** * The maximum distance above the baseline for the tallest glyph in * the font at a given text size. / public float top; /* * The recommended distance above the baseline for singled spaced text. / public float ascent; /* * The recommended distance below the baseline for singled spaced text. / public float descent; /* * The maximum distance below the baseline for the lowest glyph in * the font at a given text size. / public float bottom; /* * The recommended additional space to add between lines of text. */ public float leading; } ...

2016年7月12日 · 2 分钟 · 天边的星星

android SDK 19以上代码设置状态栏透明

//判断android 版本然后设置Systembar颜色-设置透明 public void initSystemBar() { Window window = getWindow(); //4.4版本及以上 if (Build.VERSION.SDK_INT &gt;= Build.VERSION_CODES.KITKAT) { window.setFlags( WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS, WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS); } //5.0版本及以上 if (Build.VERSION.SDK_INT &gt;= Build.VERSION_CODES.LOLLIPOP) { window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS | WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION); window.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_LAYOUT_STABLE); window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS); window.setStatusBarColor(Color.TRANSPARENT); } }

2016年6月22日 · 1 分钟 · 天边的星星

android SDK更新 镜像设置

The user guide for this mirror Powered by Tencent Bugly (bugly.qq.com) - [ANDROID SDK](http://android-mirror.bugly.qq.com:8080/include/usage.html#androidsdk) - [Android Studio](http://android-mirror.bugly.qq.com:8080/include/usage.html#ASD) <div class="tab-content"> <div id="androidsdk" class="tab active"> <span class="subtitle">☀ Windows</span> <span class="content">**A. 打开Android SDK Manager**</span> <span class="content">**B. 设置代理**</span> <span class="content">请务必选择: Force https://&#8230; sources to be fetched using http://&#8230;</span> <span class="content">**C. 检查代理是否正常工作**</span> <span class="content">点击菜单Package>Reload,如果能获取新版本,表明可以正常访问镜像</span> <span class="content">**D. 选择包进行安装**</span> <span class="subtitle">☀ Mac</span> <span class="content">**A. Terminal下,cd到android sdk部署目录**</span> ...

2016年6月16日 · 1 分钟 · 天边的星星

android 打Patch的方法 .

http://blog.csdn.net/sunyubo458/article/details/6680840 作为程序员,了解diff&patch命 令是非常必要的。比如说我们发现某个项目有bug代码,而自己又没有svn的提交权限,那么此时最合适的解决方法就是用diff命令做一个补丁发给项目成 员。项目成员通过patch命令可以立刻知道你的意图。有人会说直接传一个新文件不是更简单?不要忘了,一个patch文件尺寸更小传输更快,而且可以明 显的看到都做了哪些修改。 保证当前目录是demo名录: # mkdir demo # cd demo 先模拟一个项目目录old: # mkdir -p old/a/b # vi old/a/b/foo.txt old_line_1 old_line_2 假设我们发现项目old有bug代码,下面我们先拷贝一个新目录new,并在此修改bug代码: # cp -r old new # vi new/a/b/foo.txt new_line_1 new_line_2 保证old和new两个目录都在当前目录下,下面就可以使用diff命令了,不要使用绝对路径,而应该使用相对路径,至于原因,看到文章结尾你就清楚了: # LC_ALL=C TZ=UTC0 diff -Naur old new > foo.patch 如果不在意字符集,时差等问题,也可以省略LC_ALL=C TZ=UTC0环境变量: # diff -Naur old new > foo.patch 其中-Naur参数属于固定打法,不管是对一个文件,还是对一个目录,在使用这个参数基本就可以了。 大概浏览一下补丁文件: # cat foo.patch diff -Naur old/a/b/foo.txt new/a/b/foo.txt — old/a/b/foo.txt 2009-12-07 20:40:07.000000000 +0800 +++ new/a/b/foo.txt 2009-12-07 20:41:51.000000000 +0800 @@ -1,2 +1,2 @@ -old_line_1 -old_line_2 +new_line_1 +new_line_2 ...

2016年5月3日 · 2 分钟 · 天边的星星

Android-HotPatch在线热补丁方案

转自:http://www.jianshu.com/p/2a7d16ab29e8 本教程采用阿里dexposed开源库实现。 https://github.com/alibaba/dexposed </blockquote> ## 主APP实现: ### 主程序Application onCreate方法中初始化dexposed ``` &lt;span class="hljs-tag">DexposedBridge&lt;/span>&lt;span class="hljs-class">.canDexposed&lt;/span>(&lt;span class="hljs-tag">context&lt;/span>); ### Patch apk下载及修复: - 为保证修复patch的及时性,使用push推送patch,客户端收到消息后立即完成patch的下载及修复; - 客户端版本管理模块在程序入口Activity中检测是否有需要修复的patch; - 下载完patch apk到程序私有目录,即/data/data/packageName/files目录,同时可在xml中保存patch apk本地存储路径、方便下载启动app时加载补丁patch。 ``` ` &lt;span class="hljs-keyword">public&lt;/span> &lt;span class="hljs-class">&lt;span class="hljs-keyword">class&lt;/span> &lt;span class="hljs-title">HotPatchManager&lt;/span> &lt;/span>{ &lt;span class="hljs-keyword">public&lt;/span> &lt;span class="hljs-keyword">static&lt;/span> &lt;span class="hljs-keyword">boolean&lt;/span> canDexposed = &lt;span class="hljs-keyword">false&lt;/span>; &lt;span class="hljs-keyword">private&lt;/span> &lt;span class="hljs-keyword">static&lt;/span> &lt;span class="hljs-keyword">final&lt;/span> String SP_KEY_HOT_PATCH = &lt;span class="hljs-string">"hot_patch_path"&lt;/span>; &lt;span class="hljs-comment">/** * init hotPatch library. * * &lt;span class="hljs-doctag">@param&lt;/span> context */&lt;/span> &lt;span class="hljs-function">&lt;span class="hljs-keyword">public&lt;/span> &lt;span class="hljs-keyword">static&lt;/span> &lt;span class="hljs-keyword">void&lt;/span> &lt;span class="hljs-title">init&lt;/span>&lt;span class="hljs-params">(Context context)&lt;/span> &lt;/span>{ &lt;span class="hljs-comment">// aop init.&lt;/span> canDexposed = DexposedBridge.canDexposed(context); &lt;span class="hljs-keyword">if&lt;/span> (canDexposed) { List&lt;String&gt; list = getHotPatchPaths(context); &lt;span class="hljs-keyword">if&lt;/span> (list != &lt;span class="hljs-keyword">null&lt;/span> && list.size() &gt; &lt;span class="hljs-number">0&lt;/span>) { &lt;span class="hljs-keyword">for&lt;/span> (String path : list) { runPatchApk(context, path); } } } &lt;span class="hljs-keyword">else&lt;/span> { &lt;span class="hljs-keyword">if&lt;/span> (LogUtils.DEBUG) { LogUtils.d(&lt;span class="hljs-string">"==========your device not support dexposed aop.=========="&lt;/span>); } } } &lt;span class="hljs-comment">/** * /data/data/package/files * * &lt;span class="hljs-doctag">@param&lt;/span> context * &lt;span class="hljs-doctag">@param&lt;/span> apkPath */&lt;/span> &lt;span class="hljs-function">&lt;span class="hljs-keyword">public&lt;/span> &lt;span class="hljs-keyword">static&lt;/span> &lt;span class="hljs-keyword">void&lt;/span> &lt;span class="hljs-title">runPatchApk&lt;/span>&lt;span class="hljs-params">(Context context, String apkPath)&lt;/span> &lt;/span>{ &lt;span class="hljs-keyword">if&lt;/span> (Build.VERSION.SDK_INT &gt;= &lt;span class="hljs-number">21&lt;/span> || !canDexposed) { LogUtils.d(&lt;span class="hljs-string">"This device doesn't support dexposed."&lt;/span>); &lt;span class="hljs-keyword">return&lt;/span>; } &lt;span class="hljs-keyword">if&lt;/span> (!pathIsValid(context, apkPath)) { &lt;span class="hljs-keyword">return&lt;/span>; } &lt;span class="hljs-keyword">try&lt;/span> { PatchResult result = PatchMain.load(context, apkPath, &lt;span class="hljs-keyword">null&lt;/span>); &lt;span class="hljs-keyword">if&lt;/span> (result.isSuccess()) { LogUtils.d(&lt;span class="hljs-string">"hotPath load apk success."&lt;/span>); } &lt;span class="hljs-keyword">else&lt;/span> { LogUtils.e(&lt;span class="hljs-string">"hotPath load apk error."&lt;/span>, result.getErrorInfo()); result.getThrowbale().printStackTrace(); } } &lt;span class="hljs-keyword">catch&lt;/span> (Exception e) { e.printStackTrace(); } } &lt;span class="hljs-comment">/** * download hotPatch and auto mege. * * &lt;span class="hljs-doctag">@param&lt;/span> context */&lt;/span> &lt;span class="hljs-function">&lt;span class="hljs-keyword">public&lt;/span> &lt;span class="hljs-keyword">static&lt;/span> &lt;span class="hljs-keyword">void&lt;/span> &lt;span class="hljs-title">downloadHotPatch&lt;/span>&lt;span class="hljs-params">(&lt;span class="hljs-keyword">final&lt;/span> Context context, String downloadUrl)&lt;/span> &lt;/span>{ &lt;span class="hljs-keyword">if&lt;/span> (TextUtils.isEmpty(downloadUrl)) { LogUtils.d(&lt;span class="hljs-string">"downloadUrl is null."&lt;/span>); &lt;span class="hljs-keyword">return&lt;/span>; } DownloadInfo downloadInfo = &lt;span class="hljs-keyword">new&lt;/span> DownloadInfo(); downloadInfo.setDownloadUrl(downloadUrl); String fileName = downloadUrl.substring(downloadUrl.lastIndexOf(&lt;span class="hljs-string">"/"&lt;/span>) + &lt;span class="hljs-number">1&lt;/span>); String fileSavePath = &lt;span class="hljs-keyword">new&lt;/span> File(context.getFilesDir(), fileName).getAbsolutePath(); downloadInfo.setFileSavePath(fileSavePath); downloadInfo.setDaoCallback( &lt;span class="hljs-keyword">new&lt;/span> Task.Callback() { &lt;span class="hljs-annotation">@Override&lt;/span> &lt;span class="hljs-function">&lt;span class="hljs-keyword">public&lt;/span> &lt;span class="hljs-keyword">void&lt;/span> &lt;span class="hljs-title">onSuccess&lt;/span>&lt;span class="hljs-params">(DownloadInfo downloadInfo)&lt;/span> &lt;/span>{ LogUtils.d(&lt;span class="hljs-string">"runPatchApk begin."&lt;/span>, downloadInfo.getFileSavePath()); runPatchApk(context, downloadInfo.getFileSavePath()); appendHotPatchPath(context, downloadInfo.getFileSavePath()); LogUtils.d(&lt;span class="hljs-string">"runPatchApk end."&lt;/span>, downloadInfo.getFileSavePath()); } &lt;span class="hljs-annotation">@Override&lt;/span> &lt;span class="hljs-function">&lt;span class="hljs-keyword">public&lt;/span> &lt;span class="hljs-keyword">void&lt;/span> &lt;span class="hljs-title">onStart&lt;/span>&lt;span class="hljs-params">(DownloadInfo downloadInfo)&lt;/span> &lt;/span>{ } &lt;span class="hljs-annotation">@Override&lt;/span> &lt;span class="hljs-function">&lt;span class="hljs-keyword">public&lt;/span> &lt;span class="hljs-keyword">void&lt;/span> &lt;span class="hljs-title">onFailure&lt;/span>&lt;span class="hljs-params">(DownloadInfo downloadInfo)&lt;/span> &lt;/span>{ } &lt;span class="hljs-annotation">@Override&lt;/span> &lt;span class="hljs-function">&lt;span class="hljs-keyword">public&lt;/span> &lt;span class="hljs-keyword">boolean&lt;/span> &lt;span class="hljs-title">onLoading&lt;/span>&lt;span class="hljs-params">(&lt;span class="hljs-keyword">long&lt;/span> total, &lt;span class="hljs-keyword">long&lt;/span> current)&lt;/span> &lt;/span>{ &lt;span class="hljs-keyword">return&lt;/span> &lt;span class="hljs-keyword">true&lt;/span>; } &lt;span class="hljs-annotation">@Override&lt;/span> &lt;span class="hljs-function">&lt;span class="hljs-keyword">public&lt;/span> &lt;span class="hljs-keyword">void&lt;/span> &lt;span class="hljs-title">onCancelled&lt;/span>&lt;span class="hljs-params">(DownloadInfo downloadInfo)&lt;/span> &lt;/span>{ } } ); DownloadManager dm = DownloadService.getDownloadManager(context, DownloadService.ACTION); dm.addDownloadTask(downloadInfo); } &lt;span class="hljs-function">&lt;span class="hljs-keyword">public&lt;/span> &lt;span class="hljs-keyword">static&lt;/span> &lt;span class="hljs-keyword">void&lt;/span> &lt;span class="hljs-title">clearHotPatchFiles&lt;/span>&lt;span class="hljs-params">(Context context)&lt;/span> &lt;/span>{ List&lt;String&gt; list = getHotPatchPaths(context); &lt;span class="hljs-keyword">if&lt;/span> (list != &lt;span class="hljs-keyword">null&lt;/span> && list.size() &gt; &lt;span class="hljs-number">0&lt;/span>) { &lt;span class="hljs-keyword">for&lt;/span> (String path : list) { FileUtils.delFile(path); } } } &lt;span class="hljs-function">&lt;span class="hljs-keyword">public&lt;/span> &lt;span class="hljs-keyword">static&lt;/span> &lt;span class="hljs-keyword">boolean&lt;/span> &lt;span class="hljs-title">pathIsValid&lt;/span>&lt;span class="hljs-params">(Context context, String apkPath)&lt;/span> &lt;/span>{ &lt;span class="hljs-keyword">if&lt;/span> (TextUtils.isEmpty(apkPath)) { LogUtils.d(&lt;span class="hljs-string">"apkPath is null."&lt;/span>); &lt;span class="hljs-keyword">return&lt;/span> &lt;span class="hljs-keyword">false&lt;/span>; } String parentDir = String.format(&lt;span class="hljs-string">"/data/data/%s/files"&lt;/span>, context.getPackageName()); File apkFile = &lt;span class="hljs-keyword">new&lt;/span> File(apkPath); &lt;span class="hljs-keyword">if&lt;/span> (!parentDir.equals(apkFile.getParent())) { LogUtils.d(&lt;span class="hljs-string">"apkPath is error."&lt;/span>, apkPath); &lt;span class="hljs-keyword">return&lt;/span> &lt;span class="hljs-keyword">false&lt;/span>; } &lt;span class="hljs-keyword">if&lt;/span> (!apkFile.exists()){ LogUtils.d(&lt;span class="hljs-string">"apkPath is not exist."&lt;/span>, apkPath); &lt;span class="hljs-keyword">return&lt;/span> &lt;span class="hljs-keyword">false&lt;/span>; } &lt;span class="hljs-keyword">return&lt;/span> &lt;span class="hljs-keyword">true&lt;/span>; } &lt;span class="hljs-function">&lt;span class="hljs-keyword">public&lt;/span> &lt;span class="hljs-keyword">static&lt;/span> List&lt;String&gt; &lt;span class="hljs-title">getHotPatchPaths&lt;/span>&lt;span class="hljs-params">(Context context)&lt;/span> &lt;/span>{ List&lt;String&gt; list = &lt;span class="hljs-keyword">null&lt;/span>; SP sp = SP.getInstance(context); String paths = sp.getString(SP_KEY_HOT_PATCH, &lt;span class="hljs-keyword">null&lt;/span>); &lt;span class="hljs-keyword">if&lt;/span> (!TextUtils.isEmpty(paths)) { &lt;span class="hljs-keyword">if&lt;/span> (paths.indexOf(&lt;span class="hljs-string">","&lt;/span>) != -&lt;span class="hljs-number">1&lt;/span>) { String[] pathArr = paths.split(&lt;span class="hljs-string">","&lt;/span>); &lt;span class="hljs-keyword">if&lt;/span> (pathArr != &lt;span class="hljs-keyword">null&lt;/span> && pathArr.length &gt; &lt;span class="hljs-number">0&lt;/span>) { list = Arrays.asList(paths); } } &lt;span class="hljs-keyword">else&lt;/span> { list = &lt;span class="hljs-keyword">new&lt;/span> ArrayList&lt;String&gt;(); list.add(paths); } } &lt;span class="hljs-keyword">return&lt;/span> list; } &lt;span class="hljs-function">&lt;span class="hljs-keyword">public&lt;/span> &lt;span class="hljs-keyword">static&lt;/span> &lt;span class="hljs-keyword">void&lt;/span> &lt;span class="hljs-title">appendHotPatchPath&lt;/span>&lt;span class="hljs-params">(Context context, String apkPath)&lt;/span> &lt;/span>{ &lt;span class="hljs-keyword">if&lt;/span> (!pathIsValid(context, apkPath)) { &lt;span class="hljs-keyword">return&lt;/span>; } SP sp = SP.getInstance(context); String paths = sp.getString(SP_KEY_HOT_PATCH, &lt;span class="hljs-keyword">null&lt;/span>); &lt;span class="hljs-keyword">if&lt;/span> (!TextUtils.isEmpty(paths)) { String allPath = &lt;span class="hljs-keyword">new&lt;/span> StringBuilder(apkPath).append(&lt;span class="hljs-string">","&lt;/span>).append(apkPath).toString(); sp.commit(SP_KEY_HOT_PATCH, allPath); } &lt;span class="hljs-keyword">else&lt;/span> { sp.commit(SP_KEY_HOT_PATCH, apkPath); } } &lt;span class="hljs-function">&lt;span class="hljs-keyword">public&lt;/span> &lt;span class="hljs-keyword">static&lt;/span> &lt;span class="hljs-keyword">void&lt;/span> &lt;span class="hljs-title">clearHotPatchPaths&lt;/span>&lt;span class="hljs-params">(Context context)&lt;/span> &lt;/span>{ SP sp = SP.getInstance(context); sp.commit(SP_KEY_HOT_PATCH, &lt;span class="hljs-string">""&lt;/span>); } }` ## Patch Apk部分: <blockquote> dexpose支持方法粒度的patch,可以实现整个方法的替换或方法前、后执行修复代码。 以下实例为方法替换实例,其它只需实现相应的回调接口即可。 ...

2016年5月3日 · 4 分钟 · 天边的星星