空中花园

实践出真知,博闻而强识.


  • 首页

  • 归档

  • 分类

  • 标签

adb shell常用命令

发表于 2016年09月02日   |   分类于 Android学习笔记   |  

adb命令

  • 获取编译时间

    cat /proc/version

  • 内核崩溃

    cat /proc/last_kmsg

  • 获取硬件信息

    adb shell getprop | grep cpu

  • 获取序列号:

    adb get-serialno

  • 查看连接计算机的设备:

    adb devices

  • 查看模拟器/设施的当前状态:

    adb get-state

  • 多设备下连接目标设备:

    adb -s xxx shell

  • 重启机器:

    adb reboot

  • 重启到bootloader,即刷机模式:

    adb reboot bootloader

  • 重启到recovery,即恢复模式:

    adb reboot recovery

  • 查看log:

    adb logcat

  • 终止adb服务进程:

    adb kill-server

  • 重启adb服务进程:

    adb start-server

  • 查看Service列表

    adb shell service list
    adb shell dumpsys activity services

  • 检查Service是否存在

    adb shell service check phone

  • 获取机器MAC地址:

    adb shell cat /sys/class/net/wlan0/address

  • 获取CPU序列号:

    adb shell cat /proc/cpuinfo

  • 安装APK:

    adb install <apkfile> //比如:adb install baidu.apk

  • 保留数据和缓存文件,重新安装apk:

    adb install -r <apkfile> //比如:adb install -r baidu.apk

  • 安装apk到sd卡:

    adb install -s <apkfile> // 比如:adb install -s baidu.apk

  • 卸载APK:

    adb uninstall <package> //比如:adb uninstall com.baidu.search

  • 卸载app但保留数据和缓存文件:

    adb uninstall -k <package> //比如:adb uninstall -k com.baidu.search

  • 启动应用:

    adb shell am start -n <package_name>/.<activity_class_name>

  • 查看数据库:

    adb shell content query –uri content://settings/secure

  • 查看设备cpu和内存占用情况:

    adb shell top

  • 查看占用内存前6的app:

    adb shell top -m 6

  • 刷新一次内存信息,然后返回:

    adb shell top -n 1

  • 查询各进程内存使用情况:

    adb shell procrank

  • 启动应用程序:

    adb shell am

  • 杀死一个进程:

    adb shell kill [pid]

  • 查看进程列表:

    adb shell ps

  • 查看Android系统的属性

    adb shell prop

  • 查看指定进程状态:

    adb shell ps -x [PID]

  • 查看后台services信息:

    adb shell service list

  • adb 查看最上层成activity名字:

    linux:
    adb shell dumpsys activity | grep “mFocusedActivity”
    windows:
    adb shell dumpsys activity | findstr “mFocusedActivity”

  • 查看当前内存占用:

    adb shell cat /proc/meminfo

  • 查看IO内存分区:

    adb shell cat /proc/iomem

  • 将system分区重新挂载为可读写分区:

    adb remount

  • 从本地复制文件到设备:

    adb push <local> <remote>

  • 从设备复制文件到本地:

    adb pull <remote> <local>

  • 列出目录下的文件和文件夹,等同于dos中的dir命令:

    adb shell ls

  • 进入文件夹,等同于dos中的cd 命令:

    adb shell cd <folder>

  • 重命名文件:

    adb shell rename path/oldfilename path/newfilename

  • 删除system/avi.apk:

    adb shell rm /system/avi.apk

  • 删除文件夹及其下面所有文件:

    adb shell rm -r <folder>

  • 移动文件:

    adb shell mv path/file newpath/file

  • 设置文件权限:

    adb shell chmod 777 /system/fonts/DroidSansFallback.ttf

  • 新建文件夹:

    adb shell mkdir path/foldelname

  • 查看文件内容:

    adb shell cat <file>

  • 查看wifi密码:

    adb shell cat /data/misc/wifi/*.conf

  • 清除log缓存:

    adb logcat -c

  • 查看bug报告:

    adb bugreport

  • 获取设备名称:

    adb shell cat /system/build.prop

  • 查看ADB帮助:

    adb help

  • 跑monkey:

    adb shell monkey -v -p your.package.name 500

  • dump堆栈:

    debuggerd -b <pid>

  • 备份与恢复:

    备份:
    adb backup -f c:\allowBackup.ab -noapk com.ijinshan.browser_fast
    恢复:
    adb restore “c:\allowBackup.ab”

  • 拷贝文件(这些命令都是在adb下用,而不是在shell中用):

    push从电脑端向手机复制文件:
    adb push d:/adb/test.txt /data/data/download/
    pull从手机端向本地复制文件:
    adb pull /data/data/download/ d:/adb/

  • 查看应用程序内存使用情况:

    adb shell dumpsys meminfo <package_name>
    其中,package_name 也可以换成程序的pid,
    pid可以通过 adb shell top | grep app_name 来查找.
    内存使用情况参考http://blog.csdn.net/bigconvience/article/details/35553983

  • 查看进程占用cpu的情况:

    adb shell top -n 1 -d 0.5 | grep proc_ id

  • procrank查看内存占用:

    adb shell procrank
    VSS - Virtual Set Size 虚拟耗用内存(包含共享库占用的内存)
    RSS - Resident Set Size 实际使用物理内存(包含共享库占用的内存)
    PSS - Proportional Set Size 实际使用的物理内存(比例分配共享库占用的内存)
    USS - Unique Set Size 进程独自占用的物理内存(不包含共享库占用的内存)

  • 快速查看apk内androidmanifest文件内容:

    aapt dump xmltree xxxx.apk AndroidManifest.xml

  • 列出一些系统信息和所有应用的信息:

    adb shell dumpsys packages > d:\packages.txt

  • 列出一些指定应用的信息:

    adb shell dumpsys package com.ijinshan.duba > d:\duba.txt

  • 查看当前谁持有WAKE_LOCK锁对象:

    adb shell dumpsys power

  • 查看电池用量详情:

    adb shell dumpsys batteryinfo

  • 搜索文件:

    busybox find -name xxx

  • 电池日志:

    adb shell dumpsys batterystats > x:\batterystats.txt
    bugreport日志:adb bugreport > x:\bugreport.txt

  • 电池日志图形界面查看

    https://github.com/cacker/battery-historian

  • 查看应用uid

    cat /proc//status
    cat /data/system/packages.list | grep xxx

  • cpu频率

    查看:
    cat [%cpuFreqPath%]/cpuinfo_cur_freq (当前cpu频率)
    修改:
    echo xxx > /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor
    cat /sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_cur_freq (当前cpu频率)
    cat /sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_max_freq (最大cpu频率)
    cat /sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_min_freq (最小cpu频率)
    cat /sys/devices/system/cpu/cpu0/cpufreq/related_cpus (cpu数量标号,从0开始,如果是双核,结果为0,1)
    cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_available_frequencies (cpu所有可用频率)
    cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_available_governors (cpu所有可用调控模式)
    cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor (当前使用哪种调控模式)
    cat /sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_transition_latency (变频延迟)

  • 某个应用内存消耗信息

    adb shell dumpsys meminfo sina.mobile.tianqitong > d:\meminfo.txt

  • zygote的堆栈dump

    adb shell // 进入shell
    chmod 777 /data/anr // /data/anr设置可读写权限
    rm -r traces.txt // 删除原始traces
    adb shell ps //查看进程pid
    kill -3 //
    adb pull /data/anr/traces.txt d:/trace.txt
    trace中查看cpu调度的基本信息

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    "Thread-196" prio=5 tid=27 SUSPENDED
    | sysTid=2271 nice=0 sched=0/0 cgrp=apps/bg_non_interactive handle=1543812984
    | state=S schedstat=( 1177036142201 119659820902 234955 ) utm=84431 stm=33272 core=0
    #00 pc 000217a8 /system/lib/libc.so (__futex_syscall3+8)
    #01 pc 0000e09c /system/lib/libc.so (__pthread_cond_timedwait_relative+48)
    #02 pc 0000e0f8 /system/lib/libc.so (__pthread_cond_timedwait+60)
    #03 pc 0005419d /system/lib/libdvm.so (dvmChangeStatus(Thread*, ThreadStatus)+72)
    #04 pc 00049995 /system/lib/libdvm.so
    #05 pc 0004b9c1 /system/lib/libdvm.so
    #06 pc 0006e721 /system/lib/libandroid_runtime.so
    #07 pc 0001e610 /system/lib/libdvm.so (dvmPlatformInvoke+112)
    #08 pc 0004df29 /system/lib/libdvm.so (dvmCallJNIMethod(unsigned int const*, JValue*, Method const*, Thread*)+500)
    #09 pc 00027a24 /system/lib/libdvm.so
    #10 pc 000fedc8 [stack:2271]
    at android.util.Log.println_native(Native Method)
    at android.util.Log.println(Log.java:332)
    at com.android.internal.os.AndroidPrintStream.log(AndroidPrintStream.java:47)
    at com.android.internal.os.LoggingPrintStream.println(LoggingPrintStream.java:311)
    at java.net.PlainSocketImpl.read(PlainSocketImpl.java:487)
    at java.net.PlainSocketImpl.access$000(PlainSocketImpl.java:46)
    at java.net.PlainSocketImpl$PlainSocketInputStream.read(PlainSocketImpl.java:240)
    at java.io.InputStream.read(InputStream.java:163)
    at java.io.BufferedInputStream.fillbuf(BufferedInputStream.java:142)
    at java.io.BufferedInputStream.read(BufferedInputStream.java:309)
    at com.sina.push.i.c.c(SourceFile:241)
    at com.sina.push.i.c.b(SourceFile:133)
    at com.sina.push.i.c.d(SourceFile:270)
    at com.sina.push.i.c.e(SourceFile:496)
    at com.sina.push.i.c.<init>(SourceFile:97)
    at com.sina.push.b.a.b.a(SourceFile:56)
    at com.sina.push.b.e.a(SourceFile:166)
    at com.sina.push.b.e$b$a.run(SourceFile:487)

其中schedstat=( 1177036142201 119659820902 234955 ) utm=84431 stm=33272 core=0
从左到右六个数字分别是:
1- 当前线程在cpu上消耗的时间
2- 当前任务在CPU任务轮询中的等待时间
3- 当前线程在这个cpu上运行的次数
4- 当前线程的用户态执行时间
5- 当前线程的内核态执行时间
6- 当前线程在哪里个核心上执行
实际上描述了调度的基本信息

  • SYSTEM LOG

    logcat -b system -v time -d :v | grep sina.mobile
    -b // 加载一个可使用的日志缓冲区供查看,比如event和radio,默认值是main.
    system // system log
    -v // 输出字段 time 显示时间
    -d // 缓冲区日志打印并退出
    :v // 日志级别高到低 E W I D V
    grep sina.mobile // 过滤包含sina.mobile的信息

参考文章

adb shell常用命令
安卓CPU,GPU,IO,缓存工作模式查看与修改

Java 正则表达式

发表于 2016年08月26日   |   分类于 Android学习笔记   |  

Java 正则表达式

正则表达式定义了字符串的模式。
正则表达式可以用来搜索、编辑或处理文本。
正则表达式并不仅限于某一种语言,但是在每种语言中有细微的差别。
Java正则表达式和Perl的是最为相似的。
java.util.regex包主要包括以下三个类:
Pattern类:
pattern对象是一个正则表达式的编译表示。Pattern类没有公共构造方法。要创建一个Pattern对象,你必须首先调用其公共静态编译方法,它返回一个Pattern对象。该方法接受一个正则表达式作为它的第一个参数。
Matcher类:
Matcher对象是对输入字符串进行解释和匹配操作的引擎。与Pattern类一样,Matcher也没有公共构造方法。你需要调用Pattern对象的matcher方法来获得一个Matcher对象。
PatternSyntaxException:
PatternSyntaxException是一个非强制异常类,它表示一个正则表达式模式中的语法错误。

正则表达式语法

字符

说明

\

将下一字符标记为特殊字符、文本、反向引用或八进制转义符。例如,”n”匹配字符”n”。”\n”匹配换行符。序列”\“匹配”\”,”(“匹配”(“。

^

匹配输入字符串开始的位置。如果设置了 RegExp 对象的 Multiline 属性,^ 还会与”\n”或”\r”之后的位置匹配。

$

匹配输入字符串结尾的位置。如果设置了 RegExp 对象的 Multiline 属性,$ 还会与”\n”或”\r”之前的位置匹配。

零次或多次匹配前面的字符或子表达式。例如,zo 匹配”z”和”zoo”。 等效于 {0,}。

+

一次或多次匹配前面的字符或子表达式。例如,”zo+”与”zo”和”zoo”匹配,但与”z”不匹配。+ 等效于 {1,}。

?

零次或一次匹配前面的字符或子表达式。例如,”do(es)?”匹配”do”或”does”中的”do”。? 等效于 {0,1}。

{n}

n 是非负整数。正好匹配 n 次。例如,”o{2}”与”Bob”中的”o”不匹配,但与”food”中的两个”o”匹配。

{n,}

n 是非负整数。至少匹配 n 次。例如,”o{2,}”不匹配”Bob”中的”o”,而匹配”foooood”中的所有 o。”o{1,}”等效于”o+”。”o{0,}”等效于”o“。

{n,m}

M 和 n 是非负整数,其中 n <= m。匹配至少 n 次,至多 m 次。例如,”o{1,3}”匹配”fooooood”中的头三个 o。’o{0,1}’ 等效于 ‘o?’。注意:您不能将空格插入逗号和数字之间。

?

当此字符紧随任何其他限定符(*、+、?、{n}、{n,}、{n,m})之后时,匹配模式是”非贪心的”。”非贪心的”模式匹配搜索到的、尽可能短的字符串,而默认的”贪心的”模式匹配搜索到的、尽可能长的字符串。例如,在字符串”oooo”中,”o+?”只匹配单个”o”,而”o+”匹配所有”o”。

.

匹配除”\r\n”之外的任何单个字符。若要匹配包括”\r\n”在内的任意字符,请使用诸如”[\s\S]”之类的模式。

(pattern)

匹配 pattern 并捕获该匹配的子表达式。可以使用 $0…$9 属性从结果”匹配”集合中检索捕获的匹配。若要匹配括号字符 ( ),请使用”(“或者”)“。

(?:pattern)

匹配 pattern 但不捕获该匹配的子表达式,即它是一个非捕获匹配,不存储供以后使用的匹配。这对于用”or”字符 (|) 组合模式部件的情况很有用。例如,’industr(?:y|ies) 是比 ‘industry|industries’ 更经济的表达式。

(?=pattern)

执行正向预测先行搜索的子表达式,该表达式匹配处于匹配 pattern 的字符串的起始点的字符串。它是一个非捕获匹配,即不能捕获供以后使用的匹配。例如,’Windows (?=95|98|NT|2000)’ 匹配”Windows 2000”中的”Windows”,但不匹配”Windows 3.1”中的”Windows”。预测先行不占用字符,即发生匹配后,下一匹配的搜索紧随上一匹配之后,而不是在组成预测先行的字符后。

(?!pattern)

执行反向预测先行搜索的子表达式,该表达式匹配不处于匹配 pattern 的字符串的起始点的搜索字符串。它是一个非捕获匹配,即不能捕获供以后使用的匹配。例如,’Windows (?!95|98|NT|2000)’ 匹配”Windows 3.1”中的 “Windows”,但不匹配”Windows 2000”中的”Windows”。预测先行不占用字符,即发生匹配后,下一匹配的搜索紧随上一匹配之后,而不是在组成预测先行的字符后。

x|y

匹配 x 或 y。例如,’z|food’ 匹配”z”或”food”。’(z|f)ood’ 匹配”zood”或”food”。

[xyz]

字符集。匹配包含的任一字符。例如,”[abc]”匹配”plain”中的”a”。

[^xyz]

反向字符集。匹配未包含的任何字符。例如,”[^abc]”匹配”plain”中”p”,”l”,”i”,”n”。

[a-z]

字符范围。匹配指定范围内的任何字符。例如,”[a-z]”匹配”a”到”z”范围内的任何小写字母。

[^a-z]

反向范围字符。匹配不在指定的范围内的任何字符。例如,”[^a-z]”匹配任何不在”a”到”z”范围内的任何字符。

\b

匹配一个字边界,即字与空格间的位置。例如,”er\b”匹配”never”中的”er”,但不匹配”verb”中的”er”。

\B

非字边界匹配。”er\B”匹配”verb”中的”er”,但不匹配”never”中的”er”。

\cx

匹配 x 指示的控制字符。例如,\cM 匹配 Control-M 或回车符。x 的值必须在 A-Z 或 a-z 之间。如果不是这样,则假定 c 就是”c”字符本身。

\d

数字字符匹配。等效于 [0-9]。

\D

非数字字符匹配。等效于 [^0-9]。

\f

换页符匹配。等效于 \x0c 和 \cL。

\n

换行符匹配。等效于 \x0a 和 \cJ。

\r

匹配一个回车符。等效于 \x0d 和 \cM。

\s

匹配任何空白字符,包括空格、制表符、换页符等。与 [ \f\n\r\t\v] 等效。

\S

匹配任何非空白字符。与 [^ \f\n\r\t\v] 等效。

\t

制表符匹配。与 \x09 和 \cI 等效。

\v

垂直制表符匹配。与 \x0b 和 \cK 等效。

\w

匹配任何字类字符,包括下划线。与”[A-Za-z0-9]”等效。

\W

与任何非单词字符匹配。与”[^A-Za-z0-9]”等效。

\xn

匹配 n,此处的 n 是一个十六进制转义码。十六进制转义码必须正好是两位数长。例如,”\x41”匹配”A”。”\x041”与”\x04”&”1”等效。允许在正则表达式中使用 ASCII 代码。

\num

匹配 num,此处的 num 是一个正整数。到捕获匹配的反向引用。例如,”(.)\1”匹配两个连续的相同字符。

\n

标识一个八进制转义码或反向引用。如果 \n 前面至少有 n 个捕获子表达式,那么 n 是反向引用。否则,如果 n 是八进制数 (0-7),那么 n 是八进制转义码。

\nm

标识一个八进制转义码或反向引用。如果 \nm 前面至少有 nm 个捕获子表达式,那么 nm 是反向引用。如果 \nm 前面至少有 n 个捕获,则 n 是反向引用,后面跟有字符 m。如果两种前面的情况都不存在,则 \nm 匹配八进制值 nm,其中 n 和 m 是八进制数字 (0-7)。

\nml

当 n 是八进制数 (0-3),m 和 l 是八进制数 (0-7) 时,匹配八进制转义码 nml。

\un

匹配 n,其中 n 是以四位十六进制数表示的 Unicode 字符。例如,\u00A9 匹配版权符号 (©)。

捕获组

捕获组是把多个字符当一个单独单元进行处理的方法,它通过对括号内的字符分组来创建。
例如,正则表达式(dog) 创建了单一分组,组里包含”d”,”o”,和”g”。
捕获组是通过从左至右计算其开括号来编号。例如,在表达式((A)(B(C))),有四个这样的组:
((A)(B(C)))
(A)
(B(C))
(C)
可以通过调用matcher对象的groupCount方法来查看表达式有多少个分组。groupCount方法返回一个int值,表示matcher对象当前有多个捕获组。
还有一个特殊的组(组0),它总是代表整个表达式。该组不包括在groupCount的返回值中。
Pattern.compile();
Matcher.matcher();
Matcher.group() = Matcher.group(0);

示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class RegexMatches
{
public static void main( String args[] ){
// 按指定模式在字符串查找
String line = "This order was placed for QT3000! OK?";
String pattern = "(.*)(\\d+)(.*)";
// 创建 Pattern 对象
Pattern r = Pattern.compile(pattern);
// 现在创建 matcher 对象
Matcher m = r.matcher(line);
System.out.println("Found value groupCount: " + m.groupCount());
if (m.find( )) {
System.out.println("Found value: " + m.group(0) );
System.out.println("Found value: " + m.group(1) );
System.out.println("Found value: " + m.group(2) );
System.out.println("Found value: " + m.group(3) );
} else {
System.out.println("NO MATCH");
}
}
}

以上实例编译运行结果如下:

1
2
3
4
5
08-26 19:33:38.717: I/System.out(639): Found value groupCount: 3
08-26 19:33:38.717: I/System.out(639): Found value: This order was placed for QT3000! OK?
08-26 19:33:38.717: I/System.out(639): Found value: This order was placed for QT
08-26 19:33:38.717: I/System.out(639): Found value: 3000
08-26 19:33:38.717: I/System.out(639): Found value: ! OK?

参考文章

正则表达式 - 教程
Java 正则表达式

ContentProvider初体验

发表于 2016年08月25日   |   分类于 Android学习笔记   |  

写在前面

当我们想要读取写入第三方app的数据库的时候怎么办?默认android系统是有权限限制不能访问别的app的数据库的,那么我们应该怎么做,才能让app可以读取别的app的数据库,ContentProvider就应用而生了,专门用于app的数据库访问读取操作。

provider提供者

作为provider的提供者,我们至少要准备的两个文件AndroidManifest.xml和继承自ContentProvider的类,下面来看下具体的实现。
AndroidManifest.xml

1
2
3
4
<provider
android:name="com.pachong.main.MyContentProvider"
android:authorities="com.pachong.myprovider"
android:exported="true" />

name为自定义ContentProvider完整类名。
authorities为自定义认证字符串,类似Activity、Broadcast和Service定义的隐式启动的action字符串,第三方应用要想调用到本provider就得用这个authorities的字符串。
exported为true表示可以被其他应用访问。

MyContentProvider.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
public class MyContentProvider extends ContentProvider {
private static final UriMatcher mUriMatcher;
private static final String AUTHORITY = "com.pachong.myprovider";
private static final String PATH_NAME = "name";
private static final String PATH_PASSWORD = "password/private/steven";
private static final String CONTENT_TYPE_NAME = "vnd.android.cursor.dir/steven.name";
private static final String CONTENT_TYPE_PASSWORD = "vnd.android.cursor.item/steven.password";
private static final int CODE_NAME = 1;
private static final int CODE_PASSWORD = 2;
static {
mUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
mUriMatcher.addURI(AUTHORITY, PATH_NAME, CODE_NAME);
mUriMatcher.addURI(AUTHORITY, PATH_PASSWORD, CODE_PASSWORD);
}
@Override
public boolean onCreate() {
return false;
}
@Override
public Cursor query(Uri uri, String[] projection, String selection,
String[] selectionArgs, String sortOrder) {
switch (mUriMatcher.match(uri)) {
case CODE_NAME:
break;
case CODE_PASSWORD:
break;
default:
break;
}
Log.d("TAG", "query:"+mUriMatcher.match(uri)+",uri:"+uri);
return null;
}
@Override
public String getType(Uri uri) {
String result = null;
switch (mUriMatcher.match(uri)) {
case CODE_NAME:
result = CONTENT_TYPE_NAME;
break;
case CODE_PASSWORD:
result = CONTENT_TYPE_PASSWORD;
break;
default:
break;
}
Log.d("TAG", "getType:"+result+",uri:"+uri);
return result;
}
@Override
public Uri insert(Uri uri, ContentValues values) {
switch (mUriMatcher.match(uri)) {
case CODE_NAME:
break;
case CODE_PASSWORD:
break;
default:
break;
}
Log.d("TAG", "insert:"+mUriMatcher.match(uri)+",uri:"+uri);
getContext().getContentResolver().notifyChange(uri, null);
return null;
}
@Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
switch (mUriMatcher.match(uri)) {
case CODE_NAME:
break;
case CODE_PASSWORD:
break;
default:
break;
}
Log.d("TAG", "delete:"+mUriMatcher.match(uri)+",uri:"+uri);
getContext().getContentResolver().notifyChange(uri, null);
return 0;
}
@Override
public int update(Uri uri, ContentValues values, String selection,
String[] selectionArgs) {
switch (mUriMatcher.match(uri)) {
case CODE_NAME:
break;
case CODE_PASSWORD:
break;
default:
break;
}
Log.d("TAG", "update:"+mUriMatcher.match(uri)+",uri:"+uri);
getContext().getContentResolver().notifyChange(uri, null);
return 0;
}
}

MyContentProvider是继承自ContentProvider的类,默认会重写onCreate、query、getType、insert、delete、update等方法。在MyContentProvider中我们初始化了UriMatcher并addURI了两条uri,那么UriMatcher是做什么的呢?其实它就像一个过滤网,比如我们有很多种AUTHORITY = “com.pachong.myprovider”的uri,但是我们并不想每一种都处理,只处理我们要处理里的某一条或者某几条uri,那要怎么办呢?这个时候就得有我们的过滤装置UriMatcher了,UriMatcher通过addURI预设我们要处理的uri,然后通过match来比较uri是否是我们预设的uri,如果是就返回想要的code,这样我们就可以做特定的操作了。MyContentProvider类中我没有做数据库的操作,想进一步深入的朋友可以参考ContentProvider数据库共享之——实例讲解。query、insert、delete、update等都是对应的数据库操作方法,我们只要match出相应的uri,做处理就ok了。在insert、delete、update方法中我们加了一句getContext().getContentResolver().notifyChange(uri, null);加这句话的目的是通知相关的调用者本provider有数据更新。另外getType与启动指定的Activity或者Service中这个属性有关,不多说了,可以参考ContentProvider数据库共享之——MIME类型与getType()做深入了解。

provider调用者

再起一个新的app,然后实现下面的代码做测试。主要用到的方法getContentResolver()的insert、query、delete、update、registerContentObserver和unregisterContentObserver。
Main.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
public class Main extends Activity implements OnClickListener {
private String[] mUris = {
"content://com.pachong.myprovider/name",
"content://com.pachong.myprovider/password/private/steven",
"content://com.pachong.myprovider/other"
};
private MyContentObserver mObserver = new MyContentObserver(null);
private class MyContentObserver extends ContentObserver {
public MyContentObserver(Handler handler) {
super(handler);
}
@Override
public void onChange(boolean selfChange) {
super.onChange(selfChange);
Log.d("TAG", "onChange:"+selfChange);
}
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
findViewById(R.id.insert).setOnClickListener(this);
findViewById(R.id.query).setOnClickListener(this);
findViewById(R.id.delete).setOnClickListener(this);
findViewById(R.id.update).setOnClickListener(this);
getContentResolver().registerContentObserver(Uri.parse(mUris[0]), true, mObserver);
}
@Override
protected void onDestroy() {
super.onDestroy();
getContentResolver().unregisterContentObserver(mObserver);
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.insert:
getContentResolver().insert(Uri.parse(mUris[0]), new ContentValues());
break;
case R.id.query:
getContentResolver().query(Uri.parse(mUris[1]), null, null, null, null);
break;
case R.id.delete:
getContentResolver().delete(Uri.parse(mUris[2]), null, null);
break;
case R.id.update:
getContentResolver().update(Uri.parse(mUris[1]), new ContentValues(), null, null);
break;
default:
break;
}
}
}

Main.java中我声明了3条了Uri,其中有两条是和MyContentProvider匹配的,另外一条是不匹配的。这样做的目的就是测试前面所说UriMatcher.match的作用。

main.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity" >
<Button
android:id="@+id/insert"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="insert" />
<Button
android:id="@+id/query"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="query" />
<Button
android:id="@+id/delete"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="delete" />
<Button
android:id="@+id/update"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="update" />
</LinearLayout>

依次点击上面的四个按钮后,打印的消息如下:

1
2
3
4
5
08-25 19:59:28.150: D/TAG(26776): insert:1,uri:content://com.pachong.myprovider/name
08-25 19:59:28.150: D/TAG(27469): onChange:false
08-25 19:59:28.800: D/TAG(26776): query:2,uri:content://com.pachong.myprovider/password/private/steven
08-25 19:59:29.200: D/TAG(26776): delete:-1,uri:content://com.pachong.myprovider/other
08-25 19:59:29.600: D/TAG(26776): update:2,uri:content://com.pachong.myprovider/password/private/steven

通过log可以看到和MyContentProvider匹配的uri都返回了正确的code,所以我们在做数据库读取操作时一定要和对应的ContentProvider里的uri一致。才能保证操作生效。其他就不多说了,现在也只是通过启舰的博客对ContentProvider有了一定的认识,实际项目中还没有用到,等到工作中有项目用它再做深入的探究。

参考文章

ContentProvider数据库共享之——概述
ContentProvider数据库共享之——实例讲解
ContentProvider数据库共享之——MIME类型与getType()
ContentProvider数据库共享之——读写权限与数据监听

Uri学习总结

发表于 2016年08月25日   |   分类于 Android学习笔记   |  

写在前面

写学习总结的目的就是尽量让各知识点简单明了的展现,节省再学习的时间成本。

结构格式:

1
2
[scheme]://[authority][path]?[query]#[fragment]
[authority] = [userinfo]@[host]:[port]

每个[]表示一个小模块可选可不选,通过了解了Uri的结构布局我们就可以任性的去解读不同的Uri了,因为万变不离其宗,所有的Uri都是按照这个结构来布局的。

样例:

1
2
3
4
5
6
7
8
9
10
Uri uri = Uri.parse("http://steven@www.java2s.com:8080/yourpath/fileName.htm?stove=10&path=32&id#pc");
uri.getScheme()->[scheme]->http
uri.getAuthority()->[userinfo]@[host]:[port]->steven@www.java2s.com:8080
uri.getSchemeSpecificPart()->//[userinfo]@[host]:[port][path]?[query]->//steven@www.java2s.com:8080/yourpath/fileName.htm?stove=10&path=32&id
uri.getUserInfo()->[userinfo]->steven
uri.getHost()->[host]->www.java2s.com
uri.getPort()->[port]->8080
uri.getPath()->[path]->/yourpath/fileName.htm
uri.getQuery()->[query]->stove=10&path=32&id
uri.getFragment()->[fragment]->pc

参考文章

Uri详解之——Uri结构与代码提取
Uri详解之二——通过自定义Uri外部启动APP与Notification启动

用Github和Hexo建立个人博客站点

发表于 2016年08月12日   |  

一. Github

首先得拥有一个自己的github账户,然后建立一个以自己账户名命名的仓库。例如你的github账户名为zhangsan,那么仓库名就为zhangsan.github.io,建立好后就可以用这个仓库名作为网址访问了。想要详细的步骤可以参考github官方给出的文档。上面我们建立了一个可以在互联网上访问的站点了,那么具体表现形式还没有,这个时候就要用到博客框架Hexo了。
一个简单的站点

二. Hexo

使用Hexo前,我们需要准备Node,Git环境的搭建。环境搭建好后,就是配置Hexo了,在我们想要的路径下用git执行以下命令配置Hexo

1
2
3
4
5
6
7
mkdir MyBlog
cd MyBlog
npm install -g hexo-cli
hexo init
npm install blog --save
cd node_modules/blog/
hexo init

执行完上面的命令后,Hexo的初始化也算完成了,接下来就是写博文,预览,上传等待的操作了。

- 清除生成的公共文件

1
hexo clean

- 生成公共文件

1
hexo generate 或者 hexo g

- 在本地预览

1
hexo server 或者 hexo s
一个简单的站点

这个是Hexo为我们生成的默认主题博客,如果不想换主题的话,就可以开始写博客了

- 新建立一个博文

1
hexo new title

使用这条命令后就生成public/_post/title.md文件,我们只需要编辑这个md文件就好,md就是支持MarkDown语法的文件,如果不了解MarkDown语法话,可以先去学习一下,MarkDown现在是主流的写作了。然后在用

1
hexo s

就可以在本地预览博文效果啦,是不是很简单。至于hexo md文件一些特殊的属性写作可以参考hexo官方文档博客框架搭好了,文章也写好了,要怎么上传的自己github的站点呢?

- 修改_config.yml文件中deploy属性

1
2
3
4
deploy:
type: git
repo: https://github.com/GeorgePengZhang/GeorgePengZhang.github.io.git
branch: master

- 上传到github,如果是第一次使用话,就要依次执行下面的指令

1
2
3
4
npm install hexo-deployer-git --save
hexo clean
hexo g
hexo deploy 或者 hexo d

否则,直接用hexo d就可以了

看上去是不是很简单,就是hexo的几条命令的使用就可以把我们的博客管理起来了,还不快动手建立自己的博客站点。

1
2
3
4
5
hexo clean
hexo g
hexo new title
hexo s
hexo d

想要更详细的配置Hexo博客,可以参考Hexo官网给出的文档,详细看过其文档后,相信你可以配置出更好,更适合自己的博客站点。

前面说到Hexo会我们默认配置一个主题,那么我们想改成别的主题怎么办呢?Hexo也为我们提供了主题的选择,这里我就推荐一款比较适合新手的主题NexT。

三. NexT

为什么说NexT是一款比较适合新手的主题,因为它有自己的官方网站专门用来介绍NexT的使用配置,通过它的文档,你也就很快熟悉Hexo的一些文件配置,搭配出更好的博客。

- 下载主题

1
2
cd your-hexo-site
git clone https://github.com/iissnan/hexo-theme-next themes/next

在我们的themes目录下就会多出next文件夹,这个就是我们的要更换的主题了。

- 修改_config.yml文件中theme属性

1
theme: next

重新hexo s一下,就可以预览我们新的主题啦!下面是我的next主题效果
NexT主题效果图
想要更详细的使用NexT主题,可以参考NexT主题官方网站一步一步建立出高大上的博客站点。

四. 参考网站

Hexo官方网站
NexT官方网站
Jekyll迁移到Hexo搭建个人博客

爬虫小小强

爬虫小小强

世界那么大,我还是敲代码吧.

5 日志
1 分类
5 标签
GitHub
其他站点
  • CSDN
© 2016 爬虫小小强
由 Hexo 强力驱动
主题 - NexT.Pisces
本站访客数人次 本站总访问量次