EventBus3的基本使用指南

使用EventBus可以省略繁杂的Handler,效果也是类似的,使用方法也很简单。这里从官网上面做一个小小的总结,可以看得更全面一些。入门贴官方教程定义事件事件就是一个普通的Java类,POJO就好。public class MessageEvent { public final Strin
阅读更多

关于Bitmap相关的一些总结

如何从当前View获取到Bitmap

1
2
3
v.setDrawingCacheEnabled(true);
v.buildDrawingCache();
Bitmap bitmap = v.getDrawingCache();

如何从TextureView中获取Bitmap

1
mTextureView.getBitmap();

如何压缩Bitmap

压缩成适配目标宽、高的Bitmap

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
/**
* get a scaled bitmap from a file located in path, adjust to destWidth and destHeight
* @param path the bitmap's file location
* @param destWidth destination width
* @param destHeight destination height
* @return a scaled bitmap
*/
public static Bitmap getScaledBitmap(String path, int destWidth, int destHeight){
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeFile(path, options);

float srcWidth = options.outWidth;
float srcHeight = options.outHeight;

int inSampleSize = 1;
if (srcHeight > destHeight || srcWidth > destWidth){
float heightScale = srcHeight / destHeight;
float widthScale = srcWidth / destWidth;

inSampleSize = Math.round(heightScale > widthScale ? heightScale : widthScale);
}

options = new BitmapFactory.Options();
options.inSampleSize = inSampleSize;

return BitmapFactory.decodeFile(path, options);
}

如何将Bitmap与byte[]相互转换

从Bitmap到byte[]

1
2
3
4
int bytes = bmp.getByteCount();
ByteBuffer buf = ByteBuffer.allocate(bytes);
bmp.copyPixelsToBuffer(buf);
byte[] byteArray = buf.array();

从byte[]到Bitmap

1
2
3
Bitmap stitchBmp = Bitmap.createBitmap(width, height, type);
stitchBmp.copyPixelsFromBuffer(ByteBuffer.wrap(byteArray));
imageView.setImageBitmap(stitchBmp);

缩略图相关

理解ThumbnaiUtils

安卓系统应用调试脚本

这是一个对之前写的脚本的记录档案,自己也看不太懂当时的写法了,羞愧。用一个 repo 放这些脚本代码感觉有些浪费,干脆整个文章记录曾经的那段历史吧!

这代码的主要目的就是想少敲点命令,一步到位,做一个快男!

说明 - AndroidROMTools

Android run script tools for debugging system apps or frameworks. This was used by myself when debugging system apps or frameworks. In this project, module names was not given to avoid the project name, but the main structure was reminded.

此脚本主要分成一个入口与两个模块,详细的树状图如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
.
├── README.md
├── btool
├── modules
│   ├── handleFramework.sh
│   ├── handleXxxx.sh
│   └── handleXxxxxx.sh
└── utils
├── handleSpecificTask.sh
├── init.sh
├── printOperationTip.sh
├── tipWhenNotImplement.sh
└── tipWhenParametersError.sh

2 directories, 10 files

入口

名字叫 btool,为啥起这个怪名字,我也不知道。

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
#!/bin/bash
# initialize variables
var1=$1
var2=$2
var3=$3
UTILS_DIR=~/.PersonalTools/utils
MODULES_DIR=~/.PersonalTools/modules

case $var1 in
"init" )
${UTILS_DIR}/init.sh
;;
"log" )
adb logcat -b main \*:E | grep "TAG"
;;
"wxxxx" )
${MODULES_DIR}/handleXXXX.sh $var2 $var3
;;
"txxxx" )
${MODULES_DIR}/handlexxxxxx.sh $var2 $var3
#${UTILS_DIR}/tipWhenNotImplement.sh $var1
;;
"txxxx" )
${UTILS_DIR}/tipWhenNotImplement.sh $var1
;;
"mxxxx" )
${UTILS_DIR}/tipWhenNotImplement.sh $var1
;;
* )
#${UTILS_DIR}/tipWhenParametersError.sh init xxxxxx *xxxxxx* *xxxxxx* *xxxxxx*
if [ "${var1}" == "" ]; then
${UTILS_DIR}/tipWhenParametersError.sh init xxxx *xxxx* *xxxxxx* *xxxxxx*
elif [ -f ${MODULES_DIR}/$var1.sh ]; then
#${UTILS_DIR}/tipWhenParametersError.sh init xxxxxx *xxxxxx* *xxxxxx* *xxxxxx*
${MODULES_DIR}/$var1.sh
else
${UTILS_DIR}/tipWhenParametersError.sh init xxxxxx *txxxxxx* *txxxxxx* *mxxxxxx*
${UTILS_DIR}/tipWhenNotImplement.sh "${var1}"
fi
;;
esac
exit

Utils

  • 初始化:init.sh

    1
    2
    3
    #!/bin/bash
    adb root
    adb wait-for-device remount
  • 打印带颜色的字符:printOperationTip.sh

    1
    2
    3
    4
    5
    6
    #!/bin/bash
    #echo -e "\e[31;43m-----------------------------------------------------------\e[0m"
    echo ""
    echo -e "\e[31;47m\t"$1"\t\e[0m"
    echo ""
    #echo -e "\e[31;43m-----------------------------------------------------------\e[0m"
  • 模块未完成的告警提示:tipWhenNotImplement.sh

    1
    2
    #/bin/bash
    echo -e "\nModule < \e[41m$1\e[0m \e[31m>NOT IMPELEMNT!\e[0m\n"
  • 参数错误提示:tipWhenParametersError.sh

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    #/bin/bash
    #clear
    echo ""
    echo -e "\e[31;42mOops! Please give me the \e[0m\e[1;5;40;31mcorrect\e[0m\e[31;42m parameters!!!\e[0m"
    echo ""

    params=""
    cnt=1;
    for i in $@;
    do
    if [ $cnt != 1 ]; then
    params=$params",\e[1;5;31;40m "$i" \e[0m"
    else
    params="\e[1;5;31;40m "$i" \e[0m"
    fi
    cnt=$(($cnt+1))
    done
    if [ $cnt == 1 ]; then
    params="\e[4;31mNONE\e[0m"
    fi
    echo -e "\e[33mavaliable parameters are :\e[0m" $params"\n"
  • 处理特定任务:handleSpecificTask.sh

    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
    #!/bin/bash

    UTILS_DIR=~/.PersonalTools/utils

    OP_INDEX=$1
    PROJECT_SRC_DIR=$2
    APP_SRC_DIR=$3
    APP_OUT_DIR=$4
    APP_REMOTE_DIR=$5
    APP_PKG_NAME=$6
    PROJECT_LUNCH_IDX=$7

    #for i in $@; do
    #statements
    # echo $i
    #done

    # for compile SnapCamera APK in


    #if [ -f /tmp/btoollog ]; then
    #echo "exist"
    #else
    #echo "/tmp/btoollog not exists"
    #mkdir /tmp/btoollog
    #fi

    function compileModifiedSourceCode(){
    ${UTILS_DIR}/printOperationTip.sh "<Prepare to Compile>"
    cd ${PROJECT_SRC_DIR}
    pwd
    source build/envsetup.sh
    lunch ${PROJECT_LUNCH_IDX}
    cd ${APP_SRC_DIR}
    pwd
    mm
    }

    function makeSureCloseCompletelyAndReopen(){
    ${UTILS_DIR}/printOperationTip.sh "<Prepare to force-stop APK>"

    echo -e "\n\e[32m\ttry to stop app\e[0m"
    adb shell am force-stop ${APP_PKG_NAME}
    echo -e ""

    echo -e "\n\e[32m\ttry to start app\e[0m"
    adb shell am start -n ${APP_PKG_NAME}
    echo -e ""
    }

    function pushCompiledAPK2Phone(){
    ${UTILS_DIR}/printOperationTip.sh "<Prepare to Push APK>"
    cd ${APP_OUT_DIR}
    #pwd
    #echo "${APP_OUT_DIR}"
    adb push . ${APP_REMOTE_DIR}
    #adb push oat/arm64/$appname.odex /system/priv-app/$appname/oat/arm64/$appname.odex
    if [ $? -eq 0 ]; then
    echo -e "\n\e[32m\tpush app to phone successfully\e[0m"
    fi
    echo -e ""
    }

    function checkPushedFilesStatus(){
    ${UTILS_DIR}/printOperationTip.sh "<Prepare to Check Push Result>"
    adb shell ls -l ${APP_REMOTE_DIR} ${APP_REMOTE_DIR}/oat/arm64/
    if [ $? -eq 0 ]; then
    echo -e "\n\e[32m\tconnect to phone successfully\e[0m"
    fi
    echo -e ""
    }

    case $1 in
    "0" )
    compileModifiedSourceCode
    pushCompiledAPK2Phone
    makeSureCloseCompletelyAndReopen
    checkPushedFilesStatus
    ;;
    "1" )
    compileModifiedSourceCode
    ;;
    "2" )
    pushCompiledAPK2Phone
    ;;
    "3" )
    makeSureCloseCompletelyAndReopen
    ;;
    "4" )
    checkPushedFilesStatus
    ;;
    "subl" )
    subl ${APP_SRC_DIR}
    ;;
    "src" )
    echo ${APP_SRC_DIR}
    ;;
    * )
    ${UTILS_DIR}/tipWhenParametersError.sh 0 1 2 3 4 subl src
    echo -e "\t\e[1;4;5;31;40m 0 \e[0m\t : \e[33m1 -> 2 -> 3 -> 4\e[0m"
    echo -e "\t\e[1;4;5;31;40m 1 \e[0m\t : \e[33mCompile Modified Source Code\e[0m"
    echo -e "\t\e[1;4;5;31;40m 2 \e[0m\t : \e[33mPush Compiled APK 2 Phone\e[0m"
    echo -e "\t\e[1;4;5;31;40m 3 \e[0m\t : \e[33mClose App\e[0m"
    echo -e "\t\e[1;4;5;31;40m 4 \e[0m\t : \e[33mShow App Info\e[0m"
    echo -e "\t\e[1;4;5;31;40m subl \e[0m\t : \e[33mOpen App Src With Sublime Text\e[0m\n"
    echo -e "\t\e[1;4;5;31;40m src \e[0m\t : \e[33mPrint SRC path\e[0m\n"
    ;;
    esac

模块

  • Android Framework 处理:handleFramework.sh

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    #!/bin/bash
    SRC_HOME=/home/ckt/work/xxxxxx/msm8909_go/LINUX/android/frameworks/base
    OUT_HOME=/home/ckt/work/xxxxxx/msm8909_go/LINUX/android/out/target/product/msm8909go/system/framework

    cd /home/ckt/work/xxxxxx/msm8909_go/LINUX/android/

    source build/envsetup.sh
    lunch 29
    make framework
    make snod

    adb push ${OUT_HOME}/arm/boot.oat /system/framework/arm/
    adb push ${OUT_HOME}/arm/boot.art /system/framework/arm/

    adb push ${OUT_HOME}/framework.jar /system/framework/
    adb push ${OUT_HOME}/framework-res.apk /system/framework/

    adb reboot bootloader
  • 桌面时钟:handleXxxx.sh

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    #/bin/bash

    UTILS_DIR=~/.PersonalTools/utils

    PROJECT_DIR="/home/ckt/work/android8"
    PROJECT_SRC_DIR=${PROJECT_DIR}
    PROJECT_OUT_DIR=${PROJECT_DIR}/out/target/product/msm8953_64
    PROJECT_LUNCH_IDX=39

    DESKCLOCK_SRC_DIR=${PROJECT_SRC_DIR}/packages/apps/DeskClock/
    DESKCLOCK_OUT_DIR=${PROJECT_OUT_DIR}/system/app/DeskClock/
    DESKCLOCK_PKG_NAME=com.android.deskclock
    DESKCLOCK_REMOTE_DIR=/system/app/DeskClock


    case $1 in
    "deskclock" )
    ${UTILS_DIR}/handleSpecificTask.sh $2 ${PROJECT_SRC_DIR} ${DESKCLOCK_SRC_DIR} ${DESKCLOCK_OUT_DIR} ${DESKCLOCK_REMOTE_DIR} ${DESKCLOCK_PKG_NAME} ${PROJECT_LUNCH_IDX}
    ;;
    * )
    ${UTILS_DIR}/tipWhenParametersError.sh deskclock
    ;;
    esac
  • 多媒体应用:handleXxxxxx.sh

    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
    #!/bin/bash

    UTILS_DIR=~/.PersonalTools/utils

    PROJECT_DIR="/home/ckt/work/xxxxxxx/LINUX/android"
    PROJECT_SRC_DIR="${PROJECT_DIR}"
    PROJECT_OUT_DIR="${PROJECT_DIR}/out/target/product/msm8909go"
    PROJECT_LUNCH_IDX=29

    SOUNDRECORDER_SRC_DIR="${PROJECT_SRC_DIR}/packages/apps/SoundRecorder/"
    SOUNDRECORDER_OUT_DIR="${PROJECT_OUT_DIR}/system/priv-app/SoundRecorder/"
    SOUNDRECORDER_PKG_NAME=com.android.soundrecorder
    SOUNDRECORDER_REMOTE_DIR=/system/priv-app/SoundRecorder

    GALLERY_SRC_DIR="${PROJECT_SRC_DIR}/packages/apps/Gallery2/"
    GALLERY_OUT_DIR="${PROJECT_OUT_DIR}/system/app/Gallery2/"
    GALLERY_PKG_NAME=com.android.gallery3d
    GALLERY_REMOTE_DIR=/system/app/Gallery2

    SNAPDRAGONMUSIC_SRC_DIR="${PROJECT_SRC_DIR}/packages/apps/Music/"
    SNAPDRAGONMUSIC_OUT_DIR="${PROJECT_OUT_DIR}/system/app/Music/"
    SNAPDRAGONMUSIC_PKG_NAME=com.android.music
    SNAPDRAGONMUSIC_REMOTE_DIR=/system/app/Music

    CLOCK_SRC_DIR="${PROJECT_SRC_DIR}/packages/apps/DeskClock"
    CLOCK_OUT_DIR="${PROJECT_OUT_DIR}/system/app/DeskClock"
    CLOCK_PKG_NAME=com.android.deskclock
    CLOCK_REMOTE_DIR=/system/app/DeskClock

    case $1 in
    "soundrecorder" )
    ${UTILS_DIR}/handleSpecificTask.sh $2 ${PROJECT_SRC_DIR} ${SOUNDRECORDER_SRC_DIR} ${SOUNDRECORDER_OUT_DIR} ${SOUNDRECORDER_REMOTE_DIR} ${SOUNDRECORDER_PKG_NAME} ${PROJECT_LUNCH_IDX}
    ;;
    "gallery" )
    ${UTILS_DIR}/handleSpecificTask.sh $2 ${PROJECT_SRC_DIR} ${GALLERY_SRC_DIR} ${GALLERY_OUT_DIR} ${GALLERY_REMOTE_DIR} ${GALLERY_PKG_NAME} ${PROJECT_LUNCH_IDX}
    ;;
    "music" )
    ${UTILS_DIR}/handleSpecificTask.sh $2 ${PROJECT_SRC_DIR} ${SNAPDRAGONMUSIC_SRC_DIR} ${SNAPDRAGONMUSIC_OUT_DIR} ${SNAPDRAGONMUSIC_REMOTE_DIR} ${SNAPDRAGONMUSIC_PKG_NAME} ${PROJECT_LUNCH_IDX}
    ;;
    "clock" )
    ${UTILS_DIR}/handleSpecificTask.sh $2 ${PROJECT_SRC_DIR} ${CLOCK_SRC_DIR} ${CLOCK_OUT_DIR} ${CLOCK_REMOTE_DIR} ${CLOCK_PKG_NAME} ${PROJECT_LUNCH_IDX}
    ;;
    * )
    ${UTILS_DIR}/tipWhenParametersError.sh soundrecorder gallery music clock
    ;;
    esac

目前这些脚本对我来说,已无实际用途,不能保证准确性,只是做一个纪念,纪念那段无知却在挣扎的时光。

ProjectA 项目辅助脚本档案

本文主要记录在做 ProjectA 时用到的 Python 脚本,因为用得频繁,所以做成了脚本,避免重复输命令。

项目树状结构图如下:

1
2
3
4
5
6
.
├── CommonTips.py
├── DumpPhotos.py
├── FallWithMask.py
├── OfflineSoRunner.py
└── main.py

它主要的功能是:

  • 从 Android 手机拉取照片(需要手机连接到电脑并且安装好 adb 命令)
  • 在 Android 手机上以 shell 的形式跑 so 库算法,一般是在 apk 上运行
  • 这个带 mask 分析已经看不懂是什么意思了

入口:main.py

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
import CommonTips
import DumpPhotos
import OfflineSoRunner
import FallWithMask
sub_model_name = 'Main Menu'
op_info = '''\n--------------Main Menu--------------
| 【0】:Dump照片
| 【1】:离线跑算法库
| 【2】:带mask分析跌倒视频''' + CommonTips.tip_ops+'-------------------------------------\n'
print(op_info)

while True:
cmd = input('('+sub_model_name+')'+CommonTips.tip_input_cmd)

if cmd.isdigit():
cmd = int(cmd)
if cmd == 0:
DumpPhotos.main()
elif cmd == 1:
OfflineSoRunner.main()
elif cmd == 2:
FallWithMask.main()
else:
print(CommonTips.tip_arg_error)
else:
if 'h' == cmd.lower():
print(op_info)
elif 'q' == cmd.lower():
print(CommonTips.tip_quit)
break
else:
print(CommonTips.tip_arg_error)

提示输出:CommonTips.py

1
2
3
4
5
6
7
8
9
tip_arg_error = '''--------------------------
| X 参数错误,请重新输入! |
--------------------------\n'''
tip_quit = "已退出子模块"
tip_input_cmd = "请输入命令:"
tip_ops = '''\n|************************************
| 【h】:打印本帮助
| 【q】:退出本模块
'''

拉取照片:DumpPhotos.py

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
import os

import CommonTips

sub_model_name = 'Dump照片'

save_path = "C:\\Users\\D22433\\Desktop\\DumpPhotos\\"
remote_path = "/sdcard/AlgoTest/"

pull_photo_2_local = "adb pull "+remote_path+" "+save_path
del_local_photos = "del /Q "+save_path+"\\*"
del_remote_photos = 'adb shell "rm -rf '+remote_path+'/*"'

op_info = '''--------------Dump照片--------------
| 【0】:从安卓端拉取dump照片至本地
| 【1】:删除本地dump照片
| 【2】:删除安卓dump照片
| 【3】:删除本地&安卓dump照片''' + CommonTips.tip_ops+'-----------------------------------'


def main():
print(op_info)
while True:
cmd = input('('+sub_model_name+')'+CommonTips.tip_input_cmd)

if cmd.isdigit():
cmd = int(cmd)
if cmd == 0:
os.system(pull_photo_2_local)
elif cmd == 1:
os.system(del_local_photos)
elif cmd == 2:
os.system(del_remote_photos)
elif cmd == 3:
os.system(del_local_photos)
os.system(del_remote_photos)
else:
print(CommonTips.tip_arg_error)
else:
if 'h' == cmd.lower():
print(op_info)
elif 'q' == cmd.lower():
print(CommonTips.tip_quit)
break
else:
print(CommonTips.tip_arg_error)


if __name__ == '__main__':
main()

离线跑 so 库:OfflineSoRunner.py

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
# -*- coding:utf-8 -*-
import os
import CommonTips

sub_model_name = '跑离线算法库'

model_path_local = 'E:\\ProjectA\\latestModel'
model_path_remote = '/sdcard/apache/model/'

exe_path_local = 'E:\\projects\\Android\\projectA_app\\app\\build\\intermediates\\cmake\\debug\\obj\\arm64-v8a\\executor'
exe_path_remote = '/system/app/'

so_path_local = 'E:\\ProjectA\\latestLib'
so_path_remote = '/system/lib64/'

cmd_push_model = 'adb push ' + model_path_local + ' ' + model_path_remote
cmd_push_exe = 'adb push ' + exe_path_local + ' ' + exe_path_remote
cmd_grant_permission = 'adb shell chmod 777 /system/app/executor'
cmd_push_so = 'adb push ' + so_path_local + ' ' + so_path_remote

op_info = '''--------------跑离线算法库--------------
| 【0】:推送算法库所需要的数据文件
| 【1】:推送算法库so文件
| 【2】:推送可执行文件并授予运行权限
| 【3】:执行可执行文件
| 1 for testing checkFall
| 2 for testing detectFaceNumber
| 3 for testing extractFaceFeature
| others for quit.''' + CommonTips.tip_ops + '----------------------------------------'


def main():
print(op_info)
while True:
cmd = input('('+sub_model_name+')'+CommonTips.tip_input_cmd)
if cmd.isdigit():
cmd = int(cmd)
if cmd == 0:
os.system(cmd_push_model)
elif cmd == 1:
os.system(cmd_push_so)
elif cmd == 2:
os.system(cmd_push_exe)
os.system(cmd_grant_permission)
elif cmd == 3:
while True:
choice = input("测试选项:")
if choice == '1' or choice == '2' or choice == '3':
# do something about checkFall
command = 'adb shell "/system/app/executor ' + choice + ' `ls /sdcard/TestData' + choice + '`"'
print(command)
os.system(command)
else:
break
else:
print(CommonTips.tip_arg_error)
else:
if 'h' == cmd.lower():
print(op_info)
elif 'q' == cmd.lower():
print(CommonTips.tip_quit)
break
else:
print(CommonTips.tip_arg_error)


if __name__ == '__main__':
main()

带 mask 分析:FallWithMask.py

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
import os

import CommonTips

sub_model_name = '带mask跌倒检测'

exe_path = 'E:\\ProjectA\\TestVideoWithMask\\TestVideoWithMask.exe'
video_path = 'E:\\ProjectA\\videos'
remote_path = '/sdcard/LuPingDaShi/Rec/'

op_info = '--------------带mask跌倒检测--------------'


def main():
# pull videos
pull = input("是否要从Android拉取视频(y/N):")
if pull == 'y':
os.system('adb pull '+remote_path+' '+video_path+' ')
os.system('adb shell rm '+remote_path+'* ')

files = os.listdir(video_path)
print("可用来测试的视频 :")
for f in range(0, len(files)):
print('【'+str(f)+'】 : '+files[f])

while True:
idx = input('(' + sub_model_name + ')' + "请选择序号:")

if idx.isdigit():
idx = int(idx)
if idx >= len(files) or idx < 0:
print(CommonTips.tip_arg_error+"---数组越界")
else:
os.system(exe_path + ' ' + video_path + '\\' + files[idx]+' >> log.txt')
else:
if 'h' == idx.lower():
print(op_info)
elif 'q' == idx.lower():
print(CommonTips.tip_quit)
break
elif 'r' == idx.lower():
files = os.listdir(video_path)
print("可用来测试的视频 :")
for f in range(0, len(files)):
print('【' + str(f) + '】 : ' + files[f])
else:
print(CommonTips.tip_arg_error)


if __name__ == '__main__':
main()

SpringBoot快速入门笔记

咨询了老哥,做一个系统用哪些东西比较好,给我推荐了Spring Boot。说真的,以前知道有Spring、SpringMVC,虽然还有一大堆东西,但是对Spring Boot还是略为陌生。所以,去搜了搜它的主要功能。总结网上所说,即最大的功能就是简化Spring应用的配置,让上手更容易。使用Mave
阅读更多

MyEclipse中Maven的配置与使用

Maven可以帮你搞定一些项目上的包依赖,与Android Studio中的Gradle有点类似,当然也有很大的不一样。目前认识还是有点粗浅,期待后续的深入。

配置

虽然MyEclipse上面也集成了Maven,但是版本比官网上的低一些。从官网上面下载最新的软件包,找个合适的位置解压,然后在环境变量中加入所解压目录下的bin目录。
这里写图片描述

具体的配置方式,视不同的Shell,修改不同的配置文件。再此处为zsh,修改了~/.zshrc的内容如下:
这里写图片描述
检查配置是否成功
这里写图片描述
还需要修改conf目录下的setting.xml文件的localRepository的路径。从注释我们可以看到,如果不设置的话,默认是在~/.m2/repository目录下。该目录的主要功能就是存放Maven从仓库里面下下来的包。
这里写图片描述

接下来在MyEclipse中集成我们下载后解压的Maven。打开Preference,依次选择Maven中的InstallationsUser Settings,添加Maven的路径以及配置文件后如下:
这里写图片描述
这里写图片描述

到此基本配置完成。

创建Maven项目

网上的博客,创建Maven项目的方式有很多,尚不清楚它们会不会有什么差异。不过能达到使用Maven的功能就没差了吧。

第一次创建Maven项目时,它从服务器上面下载jar包会花费很长的时间,请耐心等待

方法一:创建JavaWeb项目同时添加Maven支持

感觉这种方法流程较简单。创建流程如下:
New一个Web Project,然后勾上Add Maven Support选项
这里写图片描述
重复选择下一步,直到出现Maven的相关设置。这里被建议选择Standard Maven JEE project structure。其实就是项目的目录结构不一样。之后,选择到Finish即可完成创建。
这里写图片描述
创建后如下,但是请注意啊,这已经是第二次创建了。所以再重复一下:
第一次创建Maven项目时,它从服务器上面下载jar包会花费很长的时间,请耐心等待
这里写图片描述

方法二:创建Maven Web项目

选择创建一个Maven Project
这里写图片描述
选择创建
这里写图片描述
后续按实际需求填写即可

使用

在该项目的pom.xml中添加依赖信息,然后点击Build Project,Maven就会把相关的依赖信息都找齐到本项目中。

Service使用笔记

看过好几回了,但是还是好像每次都忘,可能是用得少,但是工作中看的一些源代码中用的太多了,可是每次用的时候都看一遍,有点浪费时间,还是自己做一个简单的总结,这样可能以后会快一些。

这篇在草稿箱里实在是存太久了。。。


Service的分类

  • 启动型
    通过调用startService() 启动,一旦启动,服务即可在后台无限期运行,即使启动服务的组件已被销毁也不受影响。 已启动的服务通常是执行单一操作,而且不会将结果返回给调用方。

  • 绑定型
    通过调用bindService() 绑定到服务,服务即处于“绑定”状态。绑定服务提供了一个客户端-服务器接口,允许组件与服务进行交互、发送请求、获取结果,甚至是利用进程间通信 (IPC) 跨进程执行这些操作。 仅当与另一个应用组件绑定时,绑定服务才会运行; 多个组件可以同时绑定到该服务,但全部取消绑定后,该服务即会被销毁

服务在其托管进程的主线程中运行,它既不创建自己的线程,也不在单独的进程中运行(除非另行指定)。

Service的生命周期

因为其分两类,所以它的生命周期也有两种:
图片1

左边为启动型, 右边为绑定型.

Service在清单文件中的属性

  • android:exported: 顾名思义,是否可以被导出,即是否可以被绑定用做服务端.
    false:确保服务仅适用于您的应用.
    true: 与false相反.

请始终使用显式 Intent 启动或绑定 Service,且不要为服务声明 Intent 过滤器

启动型Service

继承Service

若使用这种方法,则需要注意一个问题,那就是**Service默认的线程是主线程**, 不要在其中做耗时的事情.

继承IntentService

使用这种方法, 就不需要担心线程的问题.因为其做为一个对Service的简单封装,它内部已经将所有的事件都放在了子线程中.不妨对其做一个简单的分析来加深对Service的理解.

1
2
3
4
5
6
7
8
9
10
@Override
public void onCreate() {
super.onCreate();
HandlerThread thread =
new HandlerThread("IntentService[" + mName + "]");
thread.start();

mServiceLooper = thread.getLooper();
mServiceHandler = new ServiceHandler(mServiceLooper);
}

在其onCreate()中,将开启一个初始化好Looper的子线程. 并为这个Looper的消息队列添加一个Handler.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//IntentService.java
private final class ServiceHandler extends Handler {
public ServiceHandler(Looper looper) {
super(looper);
}
@Override
public void handleMessage(Message msg) {
onHandleIntent((Intent)msg.obj);
stopSelf(msg.arg1);
}
}

@WorkerThread
protected abstract void onHandleIntent(
@Nullable Intent intent);

其中的Handler用来处理在这个子线程中的事务,其中的onHandleIntent()正是我们在继承IntentService时所需要实现的一个方法, 也就是说我们在其中写的方法都是在子线程中执行.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
@Override
public void onStart(@Nullable Intent intent, int startId) {
Message msg = mServiceHandler.obtainMessage();
msg.arg1 = startId;
msg.obj = intent;
mServiceHandler.sendMessage(msg);
}

/**
* You should not override this method for your IntentService. Instead,
* override {@link #onHandleIntent}, which the system calls when the IntentService
* receives a start request.
* @see android.app.Service#onStartCommand
*/
@Override
public int onStartCommand(@Nullable Intent intent, int flags, int startId) {
onStart(intent, startId);
return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY;
}

onStart()并没有太大的意义,只是一个普通的函数,重要的是它里面做的事情。它将从onStartCommand()里面得到的intent,通过message传递给handler,然后再是自己,对不同intent的处理。

onStartCommand()的返回值,有下面三种:

  • START_NOT_STICKY
    如果系统在 onStartCommand() 返回后终止服务,则除非有挂起 Intent 要传递,否则系统不会重建服务。这是最安全的选项,可以避免在不必要时以及应用能够轻松重启所有未完成的作业时运行服务。
  • START_STICKY
    如果系统在 onStartCommand() 返回后终止服务,则会重建服务并调用 onStartCommand(),但不会重新传递最后一个 Intent。相反,除非有挂起 Intent 要启动服务(在这种情况下,将传递这些 Intent ),否则系统会通过空 Intent 调用 onStartCommand()。这适用于不执行命令、但无限期运行并等待作业的媒体播放器(或类似服务)。
  • START_REDELIVER_INTENT
    如果系统在 onStartCommand() 返回后终止服务,则会重建服务,并通过传递给服务的最后一个 Intent 调用 onStartCommand()。任何挂起 Intent 均依次传递。这适用于主动执行应该立即恢复的作业(例如下载文件)的服务。

如何停止

启动服务必须管理自己的生命周期。也就是说,除非系统必须回收内存资源,否则系统不会停止或销毁服务,而且服务在 onStartCommand() 返回后会继续运行。
因此,服务必须通过调用stopSelf() 自行停止运行,或者由另一个组件通过调用 stopService() 来停止它。一旦请求使用 stopSelf() 或 stopService() 停止服务,系统就会尽快销毁服务。

http://blog.csdn.net/baidu_31405631/article/details/52469093

绑定型Service

对于此种类型的,感觉自己用得到的地方并不是很多,但是要能够看得懂这这种类型的Service的代码,尤其是AIDL,在Android中非常常见。

AIDL的大致使用步骤如下:

  1. 编写包含接口的aidl文件,make project,生成同名的java文件
  2. AIDL是一种可跨进程的,就是说可以在进程A中,调用进程B中的方法,所以要首先要实现该方法类。实现其中的方法,只需要继承同名java文件中的Stub类,并实现其中的方法,即可。

设计模式之代理模式

何为代理模式?代理,顾名思义可联想到代理人,代理人是干啥子的,帮别人做某件事的,且可能会根据一些具体的情况,做一些具体的处理。大概如此吧。


定义与作用

它提供了对目标对象另外的访问方式;即通过代理对象访问目标对象。代理对象是对目标对象的扩展,并会调用目标对象。

好处:可以在目标对象实现的基础上,增强额外的功能操作,即扩展目标对象的功能.

实现

静态代理

简而言之,就是代理对象被代理对象都实现同一接口,在代理对象中,调用被代理对象的相应方法,并加上一些自定义的其它操作,要使用被代理对象的方法时,只需要调用代理对象的相应方法即可。

缺点:如果增加接口中的方法,那么代理对象以及被代理对象都需要进行相应的修改,难以维护。

动态代理

不需要实现接口,利用JDK的API,在内存中动态地创建代理对象代理对象不需要实现接口,但是被代理对象一定要实现接口,否则不能用动态代理。

代理类所在包:java.lang.reflect.Proxy
JDK实现代理只需要使用newProxyInstance方法,但是该方法需要接收三个参数,完整的写法是:

static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces,InvocationHandler h )
其中三个参数的含义依次为:

  • ClassLoader loader,:指定当前目标对象使用类加载器,获取加载器的方法是固定的
  • Class<?>[] interfaces,:目标对象实现的接口的类型,使用泛型方式确认类型
  • InvocationHandler h:事件处理,执行目标对象的方法时,会触发事件处理器的方法,会把当前执行目标对象的方法作为参数传入

代码示例:

接口类IUserDao.java以及接口实现类,目标对象UserDao是一样的,没有做修改.在这个基础上,增加一个代理工厂类(ProxyFactory.java),将代理类写在这个地方,然后在测试类(需要使用到代理的代码)中先建立目标对象和代理对象的联系,然后代用代理对象的中同名方法

代理工厂类:ProxyFactory.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
/**
* 创建动态代理对象
* 动态代理不需要实现接口,但是需要指定接口类型
*/
public class ProxyFactory{

//维护一个目标对象
private Object target;
public ProxyFactory(Object target){
this.target=target;
}

//给目标对象生成代理对象
public Object getProxyInstance(){
return Proxy.newProxyInstance(
target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("开始事务2");
//执行被代理对象方法
Object returnValue = method.invoke(target, args);
System.out.println("提交事务2");
return returnValue;
}
}
);
}

}

测试类:App.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/**
* 测试类
*/
public class App {
public static void main(String[] args) {
// 目标对象
IUserDao target = new UserDao();
// 【原始的类型 class cn.itcast.b_dynamic.UserDao】
System.out.println(target.getClass());

// 给目标对象,创建代理对象
IUserDao proxy = (IUserDao) new ProxyFactory(target).getProxyInstance();
// class $Proxy0 内存中动态生成的代理对象
System.out.println(proxy.getClass());

// 执行方法 【代理对象】
proxy.save();
}
}

其实对于上面的写法,有一个小小的疑问,如果接口中存在多个函数,那么这种做法是会为很一个函数都执行相同的附加操作,如果对每个函数做不同的操作呢?利用Method的属性加以区别,然后对每个函数做分别处理?这样处理可以不。。


参考:https://www.cnblogs.com/cenyu/p/6289209.html

ButterKnife官方使用指南

看到了ButterKnife之后,感觉它实在是太棒了,可以省略掉一大堆无趣的findViewById(),整个代码看起来都舒服多了。这篇使用说明来自它的官方网站的简易介绍,用起来非常简单,但是也是有挺多的情况,所以还是觉得自己翻译出来,方便以后查阅吧!


使用@BindViewID注解相应的变量,ButterKnife就会在你的layout文件中找到所对应的View并赋值给它。

1
2
3
4
5
6
7
8
9
10
11
12
class ExampleActivity extends Activity {
@BindView(R.id.title) TextView title;
@BindView(R.id.subtitle) TextView subtitle;
@BindView(R.id.footer) TextView footer;

@Override public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.simple_activity);
ButterKnife.bind(this);
// TODO Use fields...
}
}

上面例子中,所生成的代码大致与下面代码等同:

1
2
3
4
5
public void bind(ExampleActivity activity) {
activity.subtitle = (android.widget.TextView) activity.findViewById(2130968578);
activity.footer = (android.widget.TextView) activity.findViewById(2130968579);
activity.title = (android.widget.TextView) activity.findViewById(2130968577);
}

资源绑定

使用@BindBool, @BindColor, @BindDimen, @BindDrawable, @BindInt, @BindString与一个对应的ID来绑定定义好的资源,

1
2
3
4
5
6
7
class ExampleActivity extends Activity {
@BindString(R.string.title) String title;
@BindDrawable(R.drawable.graphic) Drawable graphic;
@BindColor(R.color.red) int red; // int or ColorStateList field
@BindDimen(R.dimen.spacer) Float spacer; // int (for pixel size) or float (for exact value) field
// ...
}

非ACTIVITY绑定

我们还可以在已知View的情况下,在任意的对象中,绑定该View中所含有的控件。比如在Fragment中:

1
2
3
4
5
6
7
8
9
10
11
public class FancyFragment extends Fragment {
@BindView(R.id.button1) Button button1;
@BindView(R.id.button2) Button button2;

@Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fancy_fragment, container, false);
ButterKnife.bind(this, view);
// TODO Use fields...
return view;
}
}

另外一个是在ViewHolder中:

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
public class MyAdapter extends BaseAdapter {
@Override public View getView(int position, View view, ViewGroup parent) {
ViewHolder holder;
if (view != null) {
holder = (ViewHolder) view.getTag();
} else {
view = inflater.inflate(R.layout.whatever, parent, false);
holder = new ViewHolder(view);
view.setTag(holder);
}

holder.name.setText("John Doe");
// etc...

return view;
}

static class ViewHolder {
@BindView(R.id.title) TextView name;
@BindView(R.id.job_title) TextView jobTitle;

public ViewHolder(View view) {
ButterKnife.bind(this, view);
}
}
}

其它的绑定方式

可使用Activity当做一个根View可以绑定任何对象。如果你使用了MVC模式,你可以使用ButterKnife.bind(this, activity)来绑定Controller
可使用ButterKnife.bind(this)来绑定一个View里面的子View。如果你在layout文件中使用了<merge>标签并且在View的构造器中填充,你可以在这之后立马调用它。或者,你也可以在onFinishInflate()回调中调用。

VIEW LISTS

将所需要的控件,全部填充到一个List中。

1
2
@BindViews({ R.id.first_name, R.id.middle_name, R.id.last_name })
List<EditText> nameViews;

apply()方法可以对List中所有的View执行某个操作。

1
2
ButterKnife.apply(nameViews, DISABLE);
ButterKnife.apply(nameViews, ENABLED, false);

可以指定一些简单的动作。

1
2
3
4
5
6
7
8
9
10
static final ButterKnife.Action<View> DISABLE = new ButterKnife.Action<View>() {
@Override public void apply(View view, int index) {
view.setEnabled(false);
}
};
static final ButterKnife.Setter<View, Boolean> ENABLED = new ButterKnife.Setter<View, Boolean>() {
@Override public void set(View view, Boolean value, int index) {
view.setEnabled(value);
}
};

当然也可以在apply()方法中指定一个Android中控件的属性名。

ButterKnife.apply(nameViews, View.ALPHA, 0.0f);

绑定LISTENER

监听器也可以自动配置到相应的View上。

1
2
3
4
@OnClick(R.id.submit)
public void submit(View view) {
// TODO submit data to server...
}

监听器函数的参数都是可选的。

1
2
3
4
@OnClick(R.id.submit)
public void submit() {
// TODO submit data to server...
}

指定一个确定的类型,它将会被自动转换成之。

1
2
3
4
@OnClick(R.id.submit)
public void sayHi(Button button) {
button.setText("Hello!");
}

还可以为将一个监听器函数,绑定到多个控件上。

1
2
3
4
5
6
7
8
@OnClick({ R.id.door1, R.id.door2, R.id.door3 })
public void pickDoor(DoorView door) {
if (door.hasPrizeBehind()) {
Toast.makeText(this, "You win!", LENGTH_SHORT).show();
} else {
Toast.makeText(this, "Try again", LENGTH_SHORT).show();
}
}

自定义View时,绑定自己的监听器函数不需要设置ID

1
2
3
4
5
6
public class FancyButton extends Button {
@OnClick
public void onClick() {
// TODO do something!
}
}

重置绑定

FragmentActivity的生命周期不同。当在FragmentonCreateView()中使用了绑定,就需要在onDestroyView()中将变量置为nullButterKnife在调用绑定时会返回一个Unbinder的实例,在适当的生命周期回调中,调用这个实例的unbind()方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class FancyFragment extends Fragment {
@BindView(R.id.button1) Button button1;
@BindView(R.id.button2) Button button2;
private Unbinder unbinder;

@Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fancy_fragment, container, false);
unbinder = ButterKnife.bind(this, view);
// TODO Use fields...
return view;
}

@Override public void onDestroyView() {
super.onDestroyView();
unbinder.unbind();
}
}

其它绑定

通常@Bind和监听器绑定都是必须的。如果在目标View中为找到相应ID的控件,则会抛出异常。

为了抑制住这中异常,创建一个可选的绑定,可以使用@Nullable@Optional来注解变量或方法。

注 : 可使用任何名为@Nullable的注解来注解变量,但推荐Android support-annotations中的@Nullable

1
2
3
4
5
@Nullable @BindView(R.id.might_not_be_there) TextView mightNotBeThere;

@Optional @OnClick(R.id.maybe_missing) void onMaybeMissingClicked() {
// TODO ...
}

多方法监听器

可在注解中加入参数来区分。

1
2
3
4
5
6
7
8
9
@OnItemSelected(R.id.list_view)
void onItemSelected(int position) {
// TODO ...
}

@OnItemSelected(value = R.id.maybe_missing, callback = NOTHING_SELECTED)
void onNothingSelected() {
// TODO ...
}

下载

GRADLE

1
2
compile 'com.jakewharton:butterknife:(insert latest version)'
annotationProcessor 'com.jakewharton:butterknife-compiler:(insert latest version)'

通过反射来获取Intent中的Key

在项目中遇到一种情况,我想通过了解某个Intent里面到底存了哪些数据来解决这个问题。但是我们知道,Intent里面的数据需要知道key才能调用相应的函数取出来,所以如何才能找出这些key呢?通过对Intent代码里面对存数据的观察,我们可以看到,通过putExtra()存的数据,都放在一个叫做mE
阅读更多