LYNX

Links

Tags

Categories

jni笔记

jnijava间的交互

jni获取/修改jobject成员

参考:CSDN

javac变量转换

JNIEXPORT void JNICALL Java_ClassName_MethodName(JNIEnv *env, jobject obj, jstring javaString)
{
const char *nativeString = (*env)->GetStringUTFChars(env, javaString, 0);
(*env)->ReleaseStringUTFChars(env, javaString, nativeString);
}

javaString[]->c

参考:CSDN

public native void sendString(String[] imgPaths);// 函数声明
JNIEXPORT void JNICALL
Java_com_example_stitch_MainActivity_sendString(
JNIEnv *env,
jobject thiz,
jobjectArray imgPaths) {
// 获取String数组长度
jsize str_len = env->GetArrayLength(imgPaths);

for (int i = 0; i < str_len; i ++) {
jstring tmp = (jstring) env->GetObjectArrayElement(imgPaths, i);
const char *img_path = env->GetStringUTFChars(tmp, 0);

LOG("img[%d]: %s", i, img_path);
}
}

javaMat->cMat

public native void findPoint(String imgPath, long result);// 函数声明

... {// 函数调用
findPoint(appPath + "/img0.png", matBGR.getNativeObjAddr());
}
extern "C"
JNIEXPORT void JNICALL
Java_com_example_stitch_MainActivity_findPoint(
JNIEnv *env,
jobject thiz,
jstring imgPath,
jlong result) {
*(Mat *)result = mat.clone();// 一定要用clone()
umat.copyTo(*(Mat *)result);
}

jni的opencvmat与javaBitmap互转

参考:简书

jni新建图片返回到java

TODO

参考
stackoverflow

jni调用java类的函数

  • 使用Message回调进行UI修改:sina
openCV安装

AS和cmake笔记

android的cpu架构

  • android查看cpu架构(termux)
cat /proc/cpuinfo
  • AArch32ARMv7架构的一种执行状态
  • AArch64ARMv8架构的一种执行状态
  • 64位ARMv8包含上面两种状态

cmake在AS中的使用

不要把mkcmake两种方法混淆

输出控制(message)

(TODO)如果想直接看到打印信息,使用WARNING以上的级别进行打印

  • message(WARNING "fuck")
    • Build->Build Output->CMake warnings查看
    • Build->Build Output->Toggle View查看

Android

  • 版本信息
    • Android Studio版本为3.5
    • Build-Tools版本为28.0.3
  • 需要使用SDK Manager安装
    • ndk
    • cmake

只使用java模块

3.x-3.4.7-3.x版本

  1. File->New->Import Module->选择opencv文件夹下的sdk/java文件夹,此时Android Studio会自动加载Module name
  2. File->Project Structure->Dependencies->选择app->添加Module Dependency->选择opencv
  3. 将opencv文件夹下的sdk/native/libs下自己手机cpu对应的架构文件夹复制到app/libs
  4. 将opencv模块的build.gradlecomplieSdkVersion,buildToolVersion,minSdkVersion,targetSdkVersion改成和appbuild.gradle一样
  5. appbuild.gradleandroid节点下添加
    sourceSets {
    main {
    jni.srcDirs = []
    jniLibs.srcDirs = ['libs']
    }
    }

然后点击sync now

  1. 在使用opencv前进行初始化
    static {
    if (!OpenCVLoader.initDebug()) {
    ...
    }
    }

常见错误

  1. Caused by: CvException [org.opencv.core.CvException: OpenCV(4.1.1) /build/master_pack-android/opencv/modules/java/generator/src/cpp/utils.cpp:101: error: (-215:Assertion failed)

MatBitmap互转的时候长宽设置不对

只使用native模块

3.x-3.4.7-3.x版本

方法一

  1. CMakeLists.txt编写
    1. include头文件目录
    2. 加载libopencv动态库(libopencv_worldlibopencv_java3),命名为opencv_lib
    3. opencv_lib加载至目标文件
set(opencv_dir /home/lynx/fuck_mount/opencv/build_dir/4_1_0_shared/OpenCV-android-sdk)
set(opencv_lib libopencv_world.so) # 或libopencv_java3.so

include_directories(${opencv_dir}/sdk/native/jni/include)
add_library(opencv_lib SHARED IMPORTED)
set_target_properties(opencv_lib PROPERTIES IMPORTED_LOCATION
${opencv_dir}/sdk/native/libs/${ANDROID_ABI}/${opencv_lib})

target_link_libraries(
# 目标文件

opencv_lib
# 其他库 )
  1. 修改app的build.gradle
    • android节点下插入,否则会报错找不到libopencv_world.solibopencv_java3.so
sourceSets {
main {
jniLibs.srcDirs = ['/sdk/native/libs 对应目录']
}
}

方法二

参考:CSDN

  1. CMakeLists.txt
    1. 设置OpenCV查找的目录
    2. 查找OpenCV
    3. include头文件目录
    4. 将OpenCV的库添加至目标文件
set(sdk_dir /home/lynx/fuck_mount/opencv/build_dir/4_1_0_shared)
set(OpenCV_DIR ${sdk_dir}/OpenCV-android-sdk/sdk/native/jni)
find_package(OpenCV REQUIRED)
include_directories(${sdk_dir}/OpenCV-android-sdk/sdk/native/jni/include)

target_link_libraries(
# 目标文件

${OpenCV_LIBS}
# 其他库 )
  • 如果不设置OpenCV_DIR将无法查找OpenCV
  1. 修改app的build.gradle
sourceSets {
main {
jniLibs.srcDirs = ['/home/lynx/fuck_mount/opencv/build_dir/4_1_0_shared/OpenCV-android-sdk/sdk/native/libs']
}
}
  • 此外,务必将minSdkVersion调至21以上,否则将会只有v8a架构才能成功编译
  • 在app的build.gradle中:minSdkVersion->ANDROID_PLATFORM
  • ndkandroid.toolchain.cmake中:ANDROID_PLATFORM->ANDROID_PLATFORM_LEVEL->ANDROID_NATIVE_API_LEVEL
  • 如果不设置minSdkVersion,由于以上的确定关系,ANDROID_NATIVE_API_LEVEL会被设置为16,find_package会失败

4.x-4.1.0-4.x版本

方法一

3.x版本的方法一

方法二

3.x版本的方法二

常见问题

  1. java.lang.UnsatisfiedLinkError: dlopen failed: library "libc++_shared.so" not found(4.x版本)

stackoverflow

(不确定的解决方法)在app的gradle中修改

externalNativeBuild {
cmake {
cppFlags ""
arguments "-DANDROID_STL=c++_shared"
}
}

不要使用gnustl_sharedgnustl_static,已经过时

  1. java.lang.UnsatisfiedLinkError: dlopen failed: library "libopencv_java3.so" not found(或libopencv_java4.so)

这是由于忘记了上面的第2步.Android Studio默认的jni路径为app/src/main/jniLibs,除了在CMakeLists.txt中导入opencv的库以外还需要二选一

  • 将对应版本opencv的库(libs/下一级的各个${ANDROID_ABI}文件夹)移动到jniLibs
  • build.gradle中修改默认jni路径(见上面第2步)
  1. 各种undefined reference to *(3.x版本)

std::ios_base::Init::Init()

TODO

  1. 各类AndroidBitmap的问题(3.x版本)
undefined reference to `AndroidBitmap_getInfo'

CMakeLists.txt增加

target_link_libraries(
# TODO 解决 AndroidBitmap 报错
jnigraphics)

参考:CSDN,这是一个很小的库,展示一个稳定的,基于C语言的接口,使本机代码安全地访问Java对象的像素缓冲区的位图

source code(使用完整代码)

3.x-3.x版本(未成功,需要eclipse)

4.x-4.1.0-4.x版本

参考:CSDN

  1. 环境变量

    • JAVA_HOME

      export JAVA_HOME=/home/lynx/fuck_mount/Android_Studio/jre # 使用Android Studio的JDK位置
    • ANDROID_SDK(非必须)

      export ANDROID_SDK=/home/lynx/fuck_mount/Android_SDK
    • ANDROID_NDK(非必须)

      export ANDROID_NDK=/home/lynx/fuck_mount/Android_SDK/ndk/{版本}
  2. 调整结构

    • 修改toolchain:android ndk的ndk/build/cmake/android.toolchain.cmake(约112行)

      elseif(ANDROID_TOOLCHAIN_NAME MATCHES "-[0-9].[0-9]$")
      set(ANDROID_TOOLCHAIN clang) # 将gcc改成clang
      endif()
    • android stl,在源代码的/platforms/android/build_sdk.py(约113行)(非必须)

      self.cmake_vars = dict(
      ANDROID_STL="c++_static", # change `gnustl_static` to `c++_static` or `c++_shared`
      ANDROID_ABI=self.name,
      ANDROID_PLATFORM_ID=platform_id,
      )
    • Android Studio的android sdk文件夹下,创建软连接ln -s build-tools/{版本} tools,否则无法编译安卓模块

  3. 修改cmake参数(2选1,推荐world)(修改根CMakeLists.txt)

    • java
      • OPENCV_ENABLE_NONFREE:改为ON
      • BUILD_SHARED_LIBS:不动或者改为OFF,与生成java库冲突
      • BUILD_ANDROID_PROJECTS:不动或者改为ON
      • BUILD_FAT_JAVA_LIB:不动或者改为ON,保证生成libopencv_java4.so
      • BUILD_JAVA:不动或者改为ON
      • /samples/android/CMakeLists.txt中除了ocv_warnings_disable(CMAKE_CXX_FLAGS -Wmissing-declarations)那一行,其他全部注释掉,否则android sdk会在编译sample时报错
    • world
      • OPENCV_ENABLE_NONFREE:改为ON
      • BUILD_SHARED_LIBS:改为ON
      • BUILD_ANDROID_PROJECTS:不动或者改为ON
      • BUILD_FAT_JAVA_LIB:改为OFF,生成libopencv_world.so
      • BUILD_JAVA:不动或者改为ON
      • /samples/android/CMakeLists.txt中除了ocv_warnings_disable(CMAKE_CXX_FLAGS -Wmissing-declarations)那一行,其他全部注释掉,否则android sdk会在编译sample时报错
  4. 执行platforms/android/build_sdk.py,完成编译

./build_sdk.py --ndk_path {ndk路径} --sdk_path {android sdk路径} --extra_modules_path {path_to_contrib/modules} {目标位置} {opencv源码位置}
# example
/home/lynx/fuck_mount/opencv_4_1_0/opencv-4.1.0/platforms/android/build_sdk.py --ndk_path /home/lynx/fuck_mount/Android/SDK/ndk/18.1.5063045 --sdk_path /home/lynx/fuck_mount/Android/SDK --extra_modules_path /home/lynx/fuck_mount/opencv/source_code/opencv_contrib_4_1_0/modules /home/lynx/fuck_mount/opencv_4_1_0/android_build /home/lynx/fuck_mount/opencv_4_1_0/opencv-4.1.0

如果没有设置则默认为环境变量

  • sdk-path:Android Studio的SDK目录
  • ndk-path:Android Studio的SDK目录下ndk/{ndk版本号文件}
  1. 后续关于CMakeLists.txt(android项目内的)和build.gradle的修改同native方法

常见错误

  1. java.lang.UnsatisfiedLinkError: dalvik.system.PathClassLoader[DexPathList[[zip file "/data/app/com.example.stitch-sPWgBONIqUrdX9XLB1OY6w==/base.apk"],nativeLibraryDirectories=[/data/app/com.example.stitch-sPWgBONIqUrdX9XLB1OY6w==/lib/arm64, /data/app/com.example.stitch-sPWgBONIqUrdX9XLB1OY6w==/base.apk!/lib/arm64-v8a, /system/lib64, /product/lib64]]] couldn't find "libnative-lib.so"

缺少相应ABI的so库(目前计时在gradle里加入abiFilters也没有用),上述报错是因为没有编译全ABI.ABI配置:opencv-4.x/platforms/android/ndk-18-api-level-21.config.py

  1. 没装cmake
Executing: ['ninja', '--version']
Failed: [Errno 2] No such file or directory

Android Studio需要在SDK Manager里面预先安装CMake,否则编译的时候会找不到ninja等程序

  1. 没有libopencv_java4.so

    • BUILD_FAT_JAVA_LIBBUILD_ANDROID_PROJECTS要设置ON(或默认)
    • 记得修改android sdk tools文件结构
    • 不能同时编译动态库
  2. 编译错误

Regex: 'command line option .* is valid for .* but not for C\+\+'

TODO,可能是编译器的问题或cmake参数设置错误

  1. android project报错
A problem occurred configuring project ':face-detection'.
> NDK not configured.
Download it with SDK manager.

samples/android/CMakeLists.txt对应代码注释掉

  1. ndk报错
CMake Error at /home/lynx/fuck_mount/Android_SDK/ndk/20.1.5948944/build/cmake/android.toolchain.cmake:169 (message):
GCC is no longer supported. See
https://android.googlesource.com/platform/ndk/+/master/docs/ClangMigration.md.

需要将ndkbuild/cmake/android.toolchain.cmakeset(ANDROID_TOOLCHAIN gcc)改为clang

  1. ninja报错
CMake Error: CMake was unable to find a build program corresponding to "Ninja".  CMAKE_MAKE_PROGRAM is not set.  You probably need to select a different build tool.

将ndk的bin目录(包含ninja等程序)添加至$PATH

  1. ccache未安装(3.x版本,TODO:不确定是否为必须)

用apt安装ccache即可

  1. ld报错(3.x版本)
cannot open crtbegin_dynamic.o: 没有那个文件或目录
cannot open crtend_android.o: 没有那个文件或目录
cannot find -lstdc++
cannot find -lm
cannot find -lc
cannot find -ldl

TODO修改gcc参数(但很大程度上是由于cmake参数配置错误)

  1. 添加-nostdlib
  2. 修改--sysroot参数
  1. clang++报错
error while loading shared libraries: libtinfo.so.5: cannot open shared object file: No such file or directory

使用apt安装libtinfo5

  1. 编译错误
error: use of undeclared identifier 'vcvt_f16_f32'
float16x4_t v_dst = vcvt_f16_f32(v_src);

多种可能

  • ndk
  • opencv_contrib的路径设置错误
  1. libopencv_java3.so没有生成(3.x版本)

TODO,很大程度上是由于cmake参数配置错误

  1. cmake报错
Android SDK: Can't build Android projects as requested by
BUILD_ANDROID_PROJECTS=ON variable.
  • 4.x:android sdk build tool版本过低
  • 3.x:需要sdk整合ant(ide为eclipse)
  1. java报错
opencv init failed

检查gradlelib路径是否正确加载

额外说明

4.x版本

  • 不需要额外安装的软件:jdk,ninja-build,ndk,直接使用android studio的即可
  • 成功编译的版本:
    • ndk:20.1.5948944
    • sdk tools:28.0.3
    • cmake:3.13.4
  • 失败的版本:
    • ndk:21.0.6113669(报错undefined referrence to '__write_chk')
    • sdk tools:25.0.3(不能configure android project)

3.x版本 目前还没能成功编译android project

  • 3.x成功编译的版本:
  • 失败的版本:
    • ndk:20.1.5948944(报错undefined referrence to '__vsnprintf_chk')

使用JavaCV

4.x版本

不同导入方法,import的class位置可能不同

opencv部分功能的初始化

github原文

Loader.load(opencv_java.class);// 不能直接放在class开头

使用远程导入

appbuild.gradle示例(最外节点)

ext {
versions = [
'javacv': '1.4.4',
'ffmpeg': '4.1',
'opencv': '4.0.1'
]
}

dependencies {
...
implementation(group: 'org.bytedeco', name: 'javacv-platform', version: versions.javacv) {
exclude group: 'org.bytedeco.javacpp-presets'
}
implementation group: 'org.bytedeco.javacpp-presets', name: 'ffmpeg', version: "${versions.ffmpeg}-${versions.javacv}"
implementation group: 'org.bytedeco.javacpp-presets', name: 'ffmpeg', version: "${versions.ffmpeg}-${versions.javacv}", classifier: 'android-arm'
implementation group: 'org.bytedeco.javacpp-presets', name: 'ffmpeg', version: "${versions.ffmpeg}-${versions.javacv}", classifier: 'android-arm64'
implementation group: 'org.bytedeco.javacpp-presets', name: 'opencv', version: "${versions.opencv}-${versions.javacv}"
implementation group: 'org.bytedeco.javacpp-presets', name: 'opencv', version: "${versions.opencv}-${versions.javacv}", classifier: 'android-arm'
implementation group: 'org.bytedeco.javacpp-presets', name: 'opencv', version: "${versions.opencv}-${versions.javacv}", classifier: 'android-arm64'
}

作为lib导入

根据手机具体的cpu架构进行导入

appbuild.gradle

dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
}

将文件(视具体情况)

  • javacpp.jar
  • javacv.jar
  • openblas.jar
  • openblas-android-arm64.jar
  • opencv.jar
  • opencv-android-arm64.jar
    复制到app/libs/文件夹里

常见错误

  1. cpu架构错误/缺少(需添加-android-arm之类的库)
2019-10-27 16:01:32.439 29256-29322/? E/AndroidRuntime: FATAL EXCEPTION: AsyncTask #1
Process: com.github.crazyorr.ffmpegrecorder, PID: 29256
java.lang.RuntimeException: An error occurred while executing doInBackground()
  1. 没有对opencv初始化
2019-10-27 16:00:43.930 28933-28933/? E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.javacv, PID: 28933
java.lang.UnsatisfiedLinkError: No implementation found for long org.opencv.core.Mat.n_Mat() (tried Java_org_opencv_core_Mat_n_1Mat and Java_org_opencv_core_Mat_n_1Mat__)
  1. 缺少openblas的相关jar
2019-10-27 15:59:23.158 28618-28618/? E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.javacv, PID: 28618
java.lang.NoClassDefFoundError: Failed resolution of: Lorg/bytedeco/openblas/presets/openblas;

混用java+native模块

4.x native(或source code)+3.x java

参考:CSDN

  1. 加载native模块

  2. File->New->Import Module->选择opencv文件夹下的sdk/java文件夹,自己定义模块的名字

  3. 修改模块的gradle文件(TODO)

// 将原来的application改成library
apply plugin: 'com.android.library'

android {
// 将版本信息改得和`app`的`build.gradle`一样
compileSdkVersion 29
buildToolsVersion "29.0.2"
defaultConfig {
// 删除applicationId
minSdkVersion 15
targetSdkVersion 29
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
// 不改动
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
}
}
}
  1. 修改app的gradle文件,加载两者的lib,缺一不可
sourceSets {
main {
jniLibs.srcDirs = ['/home/lynx/fuck_mount/opencv/source_code/opencv_3_4_7_android/sdk/native/libs',
'/home/lynx/fuck_mount/opencv/build_dir/4_1_0_shared/OpenCV-android-sdk/sdk/native/libs']
}
}
  1. 修改app的gradle文件,添加java模块依赖

dependencies {
implementation project(path: ':openCVLibrary347')
}

Linux

OpenCV source code 3.x(3.4.7)

gui安装

4.x一样

常见错误

  1. fatal error: Eigen/Core: 没有那个文件或目录``#include <Eigen/Core>

    1. 修改WITH_EIGEN=OFF

    2. (或)

      • 先保证安装eigen:sudo apt install libeigen3-dev
      • 添加EIGEN_INCLUDE_PATH=/usr/include/eigen3(视具体情况)
  2. ippicv_linux_20141027.tgz下载失败

    CMake Error at 3rdparty/ippicv/downloader.cmake:71 (file):
    file DOWNLOAD HASH mismatch

    for file: [/home/lynx/fuck_mount/opencv_3_0_0/opencv/3rdparty/ippicv/downloads/linux-8b449a536a2157bcad08a2b9f266828b/ippicv_linux_20141027.tgz]
    expected hash: [8b449a536a2157bcad08a2b9f266828b]
    actual hash: [5c4f36bf7b2421d52289f0297ba1406f]
    status: [28;"Timeout was reached"]

TODO

  1. ippicv_2019_lnx_intel64_general_20180723.tgz下载超时

    IPPICV: Download: ippicv_2019_lnx_intel64_general_20180723.tgz
    CMake Warning at cmake/OpenCVDownload.cmake:193 (message):
    IPPICV: Download failed: 28;"Timeout was reached"
    1. opencv/opencv_3rdpartyippicv对应分支中下载对应的tgz

    2. tgz放入/home/lynx/Downloads/

    3. 修改opencv的source code: vi /3rdparty/ippicv/ippicv.cmake,将ippicvhttps地址改为file:/home/lynx/Downloads/

    4. 重新cmake-gui

OpenCV source code 4.x(4.1.0)

依赖包

sudo apt install libgtk2.0-dev pkg-config

一定要安装,否则会报错

  • 缺少gtk
terminate called after throwing an instance of 'cv::Exception'
what(): OpenCV(4.1.0) /home/lynx/fuck_mount/opencv/source_code/opencv_4_1_0/modules/highgui/src/window.cpp:610: error: (-2:Unspecified error) The function is not implemented. Rebuild the library with Windows, GTK+ 2.x or Cocoa support. If you are on Ubuntu or Debian, install libgtk2.0-dev and pkg-config, then re-run cmake or configure script in function 'cvNamedWindow'

命令行安装(TODO)

  1. cmake
cd {生成makefile的位置}
cmake {source的位置}
  1. make
cd {生成makefile的位置}
make
  1. make install
make install {安装的位置}

gui安装

参考:CSDN

  1. 安装cmake-gui
sudo apt install cmake-gui
  1. 启动cmake-gui
cd {build二进制文件的目录}
cmake-gui {opencv source code}
  1. Configure->Unix Makefiles:Use default native compilers->finish

  2. 狂点Configure直到没有红色区域

  3. 赋值

变量名 赋值
BUILD_EXAMPLES 勾选
CMAKE_BUILD_TYPE Release
CMAKE_INSTALL_PREFIX {自己定的cmake_install路径}
OPENCV_ENABLE_NONFREE 勾选
OPENCV_EXTRA_MODULES_PATH {opencv-contrib source code}/modules
OPENCV_GENERATE_PKGCONFIG 勾选
  1. 狂点Configure

  2. Generate,等到Generating done

  3. 在build路径make

sudo make -j4 # 具体看有多少cpu
cat /proc/cpuinfo | grep "processor" | wc -l # 查看cpu个数
sudo make install
  1. 配置opencv4.pc(2选1)

    • 修改PKG_CONFIG_PATH:增加{你cmake_install的路径}/lib/pkgconfig(opencv4.pc所在的路径)
    • (TODO,没试过)复制opencv4.pc/usr/lib/pkgconfig
  2. 配置库路径,(新建)/etc/ld.so.conf.d/opencv.conf

{你cmake_install路径}/lib/ # 自己的lib路径
sudo ldconfig
  1. 编译测试

如果是opencv.pcopencv4改成opencv

pkg-config --modversion opencv4
g++ a.cpp `pkg-config --cflags --libs opencv4` -o test && ./test

常见问题

  1. 在其他项目中用CMake导入OpenCV模块:
    find_package(OpenCV REQUIRED)
    include_directories(${OpenCV_INCLUDE_DIRS})

之后cmake出现By not providing "FindOpenCV.cmake" in CMAKE_MODULE_PATH ...:

这是由于没有设置环境变量OpenCV_DIR,设置为OpenCV编译后的目录下含有OpenCVConfig.cmake的对应路径

xml笔记

Palette说明

Common

Text

  • android:gravity="start|top":和文字位置相关

  • android:ems="10":没有设定宽度时的下划线长度?(TODO)

  • android:text="AutoCompletView":默认字符

  • tools:layout_editor_absoluteX="200dp":不知道

  • app:layout_constraintTop_toTopOf="parent":约束布局,参照为parent

android:inputType

  • Plain Text

    • EditText
    • textPersonName
    • 单行,超出宽度不会换行
  • Multiline Text

    • EditText
    • textMultiLine
    • 多行,自动换行,超出高度可以上下翻
  • Time

    • EditText
    • time
    • 单行,只能输入数字
  • AutoCompleteTextView

    • AutoCompleteTextView
    • AutoCompleteTextView
    • 自动换行,下划线自动长度,(TODO:输入提示)
  • MultiAutoCompleteTextView

    • MultiAutoCompleteTextView
    • MultiAutoCompleteTextView
    • TODO
Android开发笔记

Music开发笔记

CSDN:实例
cnblogs:其他几种方式

音乐进度

MediaPlayer

MediaPlayer参数–简书

时长

CSDN:数字格式化

total_time = MainPlayer.player.getDuration();
SimpleDateFormat format = new SimpleDateFormat("mm:ss");

// TODO 更新总时长
tmp = new Date(total_time);
formatTime = format.format(tmp);
MainPlayer.totalTime.setText(formatTime);

进度条

媒体信号

  • 蓝牙

CSDN:配对全过程
CSDN:简易

  • 有线耳机

CSDN

  1. 创建一个继承BroadcastReceiver的类
public class MediaReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {// 重载方法
String action = intent.getAction();
if (action != null) {
MainPlayer.infoLog("action: " + action);// TODO debug
switch (action) {
// 有线耳机状态改变
case Intent.ACTION_HEADSET_PLUG:
int mediaState = intent.getIntExtra("state", 0);// 判断插拔

// 蓝牙连接状态改变
case BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED:// 安卓端主动改变蓝牙状态
int bluetoothState = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, 0);// 获取蓝牙状态

// 接收蓝牙/媒体按键信号
case Intent.ACTION_MEDIA_BUTTON:
KeyEvent keyEvent = (KeyEvent) intent.getParcelableExtra(Intent.EXTRA_KEY_EVENT);// 获取键码
}
}
}

// receiver注册函数
public void registerReceiver(Context context) {
AudioManager audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
ComponentName name = new ComponentName(context.getPackageName(), MediaReceiver.class.getName());
audioManager.registerMediaButtonEventReceiver(name);
}

public void unregisterReceiver(Context context){
AudioManager audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
ComponentName name = new ComponentName(context.getPackageName(), MediaReceiver.class.getName());
audioManager.unregisterMediaButtonEventReceiver(name);
}
}

注意点:

  • 注册函数的函数名随意,可以在onCreateonResume等函数中调用注册函数
  • BroadcastReceiver子类必须要有无参的构造方法,否则会直接崩溃
  1. 修改AndroidManifest.xml

父节点为application,android:name要和BroadcastReceiver的子类名相同,priority可以不要

<receiver android:name=".MediaReceiver">
<intent-filter android:priority="1000">
<action android:name="android.intent.action.MEDIA_BUTTON"></action>
</intent-filter>
</receiver>
  1. 初始化MediaReceiver
bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();// 获取蓝牙适配器
receiver = new MediaReceiver(this);// 接收蓝牙信号

IntentFilter intentFilter = new IntentFilter();

intentFilter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);// 监视蓝牙设备与APP连接的状态
intentFilter.addAction(BluetoothDevice.ACTION_ACL_DISCONNECTED);
intentFilter.addAction(BluetoothDevice.ACTION_ACL_CONNECTED);
intentFilter.addAction(Intent.ACTION_HEADSET_PLUG);// 监听有线耳机的插拔
intentFilter.addAction(Intent.ACTION_MEDIA_BUTTON);// TODO

registerReceiver(this.receiver, intentFilter);// 注册广播
receiver.registerReceiver(this);// 初始化广播

adb

华为手机配置adb:*#*#2846579#*#*->后台设置->usb端口设置->生产模式

adb devices
adb tcpip 5555
# 拔掉数据线
adb connect 手机ip

若安卓设备显示offline,可能是由于adb版本过低

蓝牙连接管理

无需在AndroidManifest里注册

蓝牙连接

Method createBond = device.getClass().getMethod("createBond");
createBond.setAccessible(true);
result = (Boolean) createBond.invoke(device);
  1. 注意区分已经配对的设备
  2. 特殊的蓝牙设备仍未解决

状态栏部件

创建

简书:notification channel

可使用NotificationCompatNotification,注意常量取值

NotificationManager notificationManager = null;

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
notificationManager = getSystemService(NotificationManager.class);
CharSequence name = "fuck";// 通知渠道名称
String description = "shit";
String id = "111";
NotificationChannel channel = new NotificationChannel(id, name, NotificationManager.IMPORTANCE_HIGH);
channel.setDescription(description);
notificationManager.createNotificationChannel(channel);
}

NotificationCompat.Builder builder = new NotificationCompat.Builder(MainActivity.this, id)
.setSmallIcon(R.drawable.ic_launcher_background)
// .setPriority(NotificationCompat.PRIORITY_MAX)
.setVisibility(NotificationCompat.VISIBILITY_PUBLIC);

显示

  1. 首先保证系统更新并能够支持notification category

  2. 保证给应用程序提供锁屏通知权限

startForeground

常驻通知栏

for (int i = 0; i < 10; i ++) {
stopForeground(true);
Thread.sleep(500);
startForeground(10, builder.build());
}
  1. mainifest节点下增加权限

    <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
  2. 清除通知不要使用deleteNotificationChannel,否则无法控制音效/震动,使用stopForeground

notify

可以被作为通知清除

for (int i = 0; i < 10; i ++) {
notificationManager.cancel(0);
Thread.sleep(500);
notificationManager.notify(0, builder.build());
}

注意channelidBuilderid要一致

通信

  1. 注意不同intent要使用不同的requestCode

  2. 切换到MainActivity,MainActivity要使用singleTask

    Intent intent = new Intent(this, MusicList.class);
    remoteViews.setOnClickPendingIntent(R.id.button_open, PendingIntent.getActivity(this, 6, intent, 0));
  3. 使用空pendingIntent来防止点击通知会消失

锁屏通知

只能够从系统中手动打开权限

事件 intent
亮屏 Intent.ACTION_SCREEN_ON
关屏 Intent.ACTION_SCREEN_OFF
解锁 Intent.ACTION_USER_PRESENT

桌面部件

在进程完全被杀死后通过widget启动app

  1. PendingIntent.getActivity()/startActivity()
  2. PendingIntent.getForegroundService()/startForegroundService(),不要使用Service

Editor开发笔记

获取读写权限

AndroidManifest

<!-- manifest节点下  -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>

Activity

String permission = "android.permission.WRITE_EXTERNAL_STORAGE";
int check_result = ActivityCompat.checkSelfPermission(this, permission);// `允许`返回0,`拒绝`返回-1
if (check_result != PackageManager.PERMISSION_GRANTED) {// 没有`写`权限
ActivityCompat.requestPermissions(this, new String[]{permission}, 1);// 获取`写`权限
}

关联文件类型

文本文件

<intent-filter android:scheme="http"
tools:ignore="AppLinkUrlError">
<action android:name="android.intent.action.VIEW"/>
<category android:name="android.intent.category.DEFAULT"/>
<data android:mimeType="text/*"/>
</intent-filter>

修改默认Toast

static public void info(Context context, String log) {
Toast toast = Toast.makeText(context, log, Toast.LENGTH_SHORT);
View view = toast.getView();
view.setBackgroundResource(R.drawable.toast);
TextView textView = view.findViewById(android.R.id.message);
textView.setTextColor(Color.rgb(0xff, 0xff, 0xff));
toast.show();
}

由外部打开文件

Intent intent = getIntent();
String action = intent.getAction();// 判断本activity启动的方式
if (action.equals("android.intent.action.VIEW")) {// 由其他软件打开本软件
}

控制activity数目

<activity android:name=".Editor"
android:launchMode="singleTask">

获取根view

View view = getWindow().getDecorView().findViewById(android.R.id.content);

数据保存

SharedPreferences

SharedPreferences:基于xml的键值对,存储于/data/data/应用程序包/shared_prefs

提示框/窗口

Dialog

参考

protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.save_layout);

// 初始化`保存`按钮
yes.setOnClickListener(new View.OnClickListener() {//
});

// 初始化`取消`按钮
cancel.setOnClickListener(new View.OnClickListener() {
});

// 初始化`删除`按钮
no.setOnClickListener(new View.OnClickListener() {
});
}

private void initButton() {
// 初始化按钮
yes = findViewById(R.id.yes_button);
cancel = findViewById(R.id.cancel_button);
no = findViewById(R.id.no_button);
}
myWindow = new MyWindow(MainActivity.this, R.style.save_style);
myWindow.setCanceledOnTouchOutside(false);
myWindow.setOnDismissListener(new DialogInterface.OnDismissListener() {
});
myWindow.show();// TODO 获取点击结果
public class MyWindow extends PopupWindow {
public Button yes;
public Button cancel;
public Button no;
public int result;

public MyWindow(Context context, View view) {
super(context);
this.setContentView(LayoutInflater.from(context).inflate(R.layout.manager_layout, null));
// this.setOutsideTouchable(false);
this.setFocusable(true);// 否则无法进行edittext输入

this.showAsDropDown(view);
this.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE);
this.setInputMethodMode(PopupWindow.INPUT_METHOD_NEEDED);
}
}
  • 响应键盘:this.setFocusable(true);,否则无法进行EditText输入

DialogFragment

参考

public class MyWindow extends DialogFragment {
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.manager_layout, container);
getDialog().getWindow().setBackgroundDrawable(new ColorDrawable(0x00000000));
return view;
}

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setStyle(STYLE_NO_FRAME, android.R.style.Theme);
}
}
myWindow = new MyWindow();
myWindow.show(getSupportFragmentManager(), "edit");

过期内容

调用系统文件浏览器

1.绑定点击事件

Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
intent.setType("*/*");// 所有类型文件
intent.addCategory(Intent.CATEGORY_OPENABLE);
startActivityForResult(intent, 1);

2.根据requestCode接收数据

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (resultCode == Activity.RESULT_OK) {
if (requestCode == 1) {// `打开`按钮
...
}
}
}
}
  1. Intent.ACTION_GET_CONTENT:用于调用系统程序,比如一个打开一个文件的时候会提示你用哪个软件打开

  2. Intent.setType():设置默认打开格式,如"video/*","audio/amr"

调用相册

Intent intent = new Intent(Intent.ACTION_PICK);//intent  action属性
intent.setType("image/*");
startActivityForResult(intent, 2);

通用框架修改

drawable

添加buttondialog

values

删掉styles,修改colors,添加styles_button(按钮)和styles_tab(工具栏)

manifests

增加权限,删除label,增加android:launchMode="singleTask"

相机相关

Android Studio笔记

安装

官方文档
国内网站

Linux

  • 运行程序:android-studio/bin/studio.sh

  • 64位机器需要安装32位库

sudo apt-get install libc6:i386 libncurses5:i386 libstdc++6:i386 lib32z1 libbz2-1.0:i386
  • 设置代理(不推荐,会搞出一堆问题)

手动设置:mirrors.neusoft.edu.cn:80

汉化

教程

汉化包

使用

windows

配置文件夹位置:C:/Users/lynx/.AndroidStudio3.5

增加虚拟设备:Tools->AVD Manager

android device monitor位置:E:\Android\Sdk\tools\monitor.bat

memory monitor 打开:Run->Profiler

解决网络问题:Configure->Setting->System Setting->HTTP Proxy->Auto-detect proxy settings

布局编辑器打开:打开一个xml文件->底部选择Design

Linux

清除缓存:Build->Clear Project

快捷键

  • 向前/后跳转:alt+shift+left/right
  • 打开Logcat:alt+6
  • 重构:shift+f6
  • 运行:shift+f10

常见错误

  1. Android resource linking failed

查看app的gradle有没有缺少implementation

  1. SDK tools directory is missing

TODO

  1. SDK does not contain any platforms

SDK的目录下要有名为platforms的文件夹

  1. Connection failed

TODO

  1. Could not install Gradle distribution from 'https://services.gradle.org/distributions/gradle-x.x.x-all.zip'

  2. Gradle sync failed: Unable to tunnel through proxy. Proxy returns "HTTP/1.1 400 Bad Request" (973 ms)

直接下载解压相应文件到本地,修改gradle配置:Setting->Build, Execution, Deployment->Gradle

  1. Could not GET ...

不使用代理(No proxy),同时在gradle目录下编辑gradle.properties,删除所有代理

1 / 1