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

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

OpenCV for Android 3.x:只使用java模块

参考:CSDN,示例:压缩图片

  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互转的时候长宽设置不对

OpenCV for Android 3.x:使用native模块

方法一

  1. CMakeLists.txt编写

CMakeLists.txt中确定两个关键路径

  • /sdk/native/jni/include:头文件位置
  • /sdk/native/libs/${ANDROID_ABI}/libopencv_java3.so:库位置
cmake_minimum_required(VERSION 3.4.1)

#1
set(opencv_version OpenCV4-android-sdk)
set(opencv_lib libopencv_java4.so)

#2
include_directories(/home/lynx/fuck_mount/Android/Proj/${opencv_version}/sdk/native/jni/include)
add_library(fuck SHARED IMPORTED)
set_target_properties(fuck PROPERTIES IMPORTED_LOCATION
/home/lynx/fuck_mount/Android/Proj/${opencv_version}/sdk/native/libs/${ANDROID_ABI}/${opencv_lib})


add_library(保持原样)

find_library(保持原样)

target_link_libraries(
native-lib

#3
fuck

${log-lib})
  1. 修改app的build.gradle

android节点下插入

sourceSets {
main {
jniLibs.srcDirs = ['/home/lynx/fuck_mount/Android/Proj/OpenCV4-android-sdk/sdk/native/libs']
}
}

方法二

参考:CSDN

还没有成功

  1. CMakeLists.txt编写

CMakeLists.txt中确定一个关键路径

  • /sdk/native/jni/include:头文件位置
cmake_minimum_required(VERSION 3.4.1)

#1
set(opencv_version OpenCV4-android-sdk)
set(opencv_lib libopencv_java4.so)

#2
set(OpenCV_STATIC ON)
set(OpenCV_DIR /home/lynx/fuck_mount/Android/Proj/${opencv_version}/sdk/native/jni)
find_package(OpenCV REQUIRED)
if (OpenCV_FOUND)
message(WARNING "opencv libs: ${OpenCV_LIBS}")
else (OpenCV_FOUND)
message(WARNING "opencv not found")
endif(OpenCV_FOUND)

add_library(保持原样)

find_library(保持原样)

target_link_libraries(
native-lib

${log-lib}

#3
${OpenCV_LIBS})

常见问题

  1. java.lang.UnsatisfiedLinkError: dlopen failed: library "libopencv_java3.so" not found

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

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

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

未解决

  1. undefined reference to `AndroidBitmap_getInfo'

各类AndroidBitmap的问题

CMakeLists.txt增加

target_link_libraries(
# TODO 解决 AndroidBitmap 报错
jnigraphics)

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

OpenCV for Android 4.x:使用native模块

方法一

3.x版本的方法一

常见问题

  1. java.lang.UnsatisfiedLinkError: dlopen failed: library "libc++_shared.so" not found

stackoverflow

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

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

不要使用gnustl_sharedgnustl_static,已经过时

  1. java.lang.UnsatisfiedLinkError: dlopen failed: library "libopencv_java4.so" not found

解决方案同3.x版本

OpenCV for Android 4.x:使用java+native模块

参考:CSDN

  1. 加载native模块

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

  3. 修改模块的gradle文件

// 将原来的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文件,加载native/lib模块

javacv(使用不完整OpenCV 4.1.0)

不同导入方法,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;

OpenCV 4.x source code

参考:CSDN

  1. 修改参数

Android Studio的sdk下的ndk:ndk/build/cmake/android.toolchain.cmake(第112行)

elseif(ANDROID_TOOLCHAIN_NAME MATCHES "-[0-9].[0-9]$")
set(ANDROID_TOOLCHAIN clang) # 将gcc改成clang
endif()

opencv 4.x源码:/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,
)

opencv 4.x源码:/CMakeLists.txt(第426行和429行)(可以根据需要修改)

# OCV_OPTION(BUILD_SHARED_LIBS        "Build shared libraries (.dll/.so) instead of static ones (.lib/.a)" NOT (ANDROID OR APPLE_FRAMEWORK) )
OCV_OPTION(BUILD_SHARED_LIBS "Build shared libraries (.dll/.so) instead of static ones (.lib/.a)" ON ) # 生成动态库
OCV_OPTION(BUILD_opencv_apps "Build utility applications (used for example to train classifiers)" (NOT ANDROID AND NOT WINRT) IF (NOT APPLE_FRAMEWORK) )
OCV_OPTION(BUILD_opencv_js "Build JavaScript bindings by Emscripten" OFF )
OCV_OPTION(BUILD_ANDROID_PROJECTS "Build Android projects providing .apk files" OFF )
# OCV_OPTION(BUILD_ANDROID_PROJECTS "Build Android projects providing .apk files" ON IF ANDROID )
  1. 配置JAVA_HOME

使用Android Studio的JDK位置

export JAVA_HOME=/home/lynx/fuck_mount/AS/jre
  1. 执行platforms/android/build_sdk.py,完成编译
./build_sdk.py --ndk-path {ndk路径} --sdk_path {android sdk路径} {目标位置} {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 /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版本号文件}

额外说明

不需要额外安装的软件:jdk,ninja-build,ndk.直接使用android studio的即可
不需要安装的软件:ant,ccache

目前还没能成功编译android project

能够混合使用:

  • OpenCV 3.xjava库(配置见上)
  • TODO

常见问题

  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

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

OpenCV source code 4.x(4.1.0)

依赖包

sudo apt install libgtk2.0-dev pkg-config

命令行安装(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源代码}
  1. Configure->Unix Makefiles:Use default native compilers->finish

  2. 狂点Configure知道没有红色区域

  3. 赋值

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

  2. Generate,等到Generating done

  3. 在源代码路径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/(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
  • 向前/后跳转:alt+shift+left/right

汉化

教程

汉化包

其他(TODO)

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

常见错误

  1. Android resource linking failed

查看app的gradle有没有缺少implementation

1 / 1