咸鱼

咸鱼是以盐腌渍后,晒干的鱼

0%

server.xml的Host节点

1
2
<Context path="/demo" docBase="D:\SourceCode\MyEclipse\KevinServlet\WebRoot" reloadable="true" />
<Context path="/example" docBase="D:\SourceCode\MyEclipse\examples" reloadable="true" />

项目地址

文档传送门 ,根据网站底部的说明:
此文档由 docsify 生成
docsify 是一个动态生成文档网站的工具。不同于 GitBook、Hexo 的地方是它不会生成将 .md 转成 .html 文件,所有转换工作都是在运行时进行。

使用教程

其实原理就是将 https://github.com/Binaryify/NeteaseCloudMusicApi/blob/master/docs
目录的md文件生成github page ,在index.html引入docsify.js

阅读全文 »

1、首页全局安装gulp

npm install --global gulp

2、其次局部安装gulp

npm install gulp --save-dev

3、安装依赖

阅读全文 »

【Lottie】 是Airbnb开源的一个面向 iOS、Android、React Native 的动画库,能分析 Adobe After Effects 导出的动画,并且能让原生 App 像使用静态素材一样使用这些动画,完美实现动画效果。

android 项目地址:https://github.com/airbnb/lottie-android

1
2
3
dependencies {
implementation 'com.airbnb.android:lottie:4.2.0'
}

本翻译文章原文链接
这篇文章最新的内容在 《向您的项目添加 C 和 C++ 代码》

注:官网上面的技术文章也在不断地汉化中,只是进度有点慢。在我翻译本篇文章的时候,官网没有对应的中文教程。经人提醒,该文章现在在官网已经有对应的中文版教程了,链接地址:向您的项目添加 C 和 C++代码。有需要的朋友可以直接阅读官方中文解说。

———–分割线————-

Android Studio 2.2 正式版发布后,看到更新内容中有提到对 C/C++ 支持的完善,表示非常高兴。然后将官网上这一部分内容翻译出来,如有错误,欢迎指正。
原文链接:Add C and C++ Code to Your Project

使用 Android studio,你可以将 C 和 C++ 代码编译成 native library(即 .so 文件),然后打包到你的 APK 中。你的 Java 代码可以通过 Java Native Interface(JNI)调用 native library 中的方法。

阅读全文 »

Android 上有很多优秀的第三方下载库,功能很强大,如断点续传,异步等。

为了快速下载一个小文件,有时候并不需要牛刀,利用Android自带的 java.net.HttpURLConnection 即可以完成下载,应用场景,比如小的缓存文件,用子线程同步下载即可。

步骤(经典的阻塞输入/输出流读写):

  1. 连接
  2. 获取输入流
  3. 读取buffer写入到本地文件输出流
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
import android.util.Log;

import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigInteger;
import java.net.HttpURLConnection;
import java.net.URL;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

public class MiniFileDownload {

private static final String TAG = "MiniFileDownload";
interface DownloadCallBack{
void onError(Exception e);
void onOK(File file);
void onProgress(float progress);
}
public static void start(String url, File saveFile, DownloadCallBack callBack) {

if(saveFile.exists()){
saveFile.delete();
}
if(callBack == null){
return;
}
HttpURLConnection conn;
try {

//连接URL服务器
conn = (HttpURLConnection)new URL(url).openConnection();
conn.setConnectTimeout(3 * 1000);
conn.setUseCaches(false);
} catch (IOException e) {
e.printStackTrace();
callBack.onError(e);
return;
}

InputStream is = null;
BufferedOutputStream bos = null;
try {

//判断响应码,如果服务器不响应错误,开始下载。
if (conn.getResponseCode() != 200){
Log.e(TAG,"ResponseCode = " + conn.getResponseCode());
return;
}
//获取文件总大小
int contentLength = conn.getContentLength();
Log.d(TAG,"content Length = " + contentLength);
byte[] buffer = new byte[1024];
int offset = 0 ;
int len;

//本地文件输出流
bos = new BufferedOutputStream( new FileOutputStream(saveFile) );

//获取输入流
is = conn.getInputStream();
//循环读(下载)
while ((len = is.read(buffer)) != -1) {

Log.d(TAG,"read buffer len = " + len);
bos.write(buffer, 0, len);
offset += len;
Log.d(TAG,"offset = " + offset + " ;total=" + contentLength);
//计算进度
float progress = (float)offset / (float)contentLength;
Log.d(TAG,"progress = " + progress);
//更新进度到回调,UI层可以显示下载进度
callBack.onProgress(progress);
}
Log.d(TAG,"ok");
callBack.onOK(saveFile);
} catch (IOException e) {
e.printStackTrace();
callBack.onError(e);
}finally {

//关闭资源
if(is != null){
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}

if(bos != null){
try {
bos.flush();
bos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
conn.disconnect();
}
}

}

GridLayoutManager 很少用,所以它的Decoration用法这里做一下备忘。

  • 主要记住行、列的计算,第一行、最后一行、第一列、最后一列的计算。
  • Item的布局要用 match_parent 采用自动适应的效果。
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
public class TestGridDecoration extends RecyclerView.ItemDecoration{

private int offset;

public TestGridDecoration(int offset) {
this.offset = offset;
}

@Override
public void getItemOffsets(@NonNull Rect outRect, @NonNull View view, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) {
super.getItemOffsets(outRect, view, parent, state);

int childLayoutPosition = parent.getChildLayoutPosition(view);

//每行的元素数量
int spanCount = ((GridLayoutManager)parent.getLayoutManager()).getSpanCount();

//总行数
int maxRow = state.getItemCount() / spanCount;
//所处的行号
int row = childLayoutPosition / spanCount;
//所处的列号
int column = childLayoutPosition % spanCount;


if(row == 0){
//第一行
outRect.top = 0;
outRect.bottom = 0;
}else if(row == maxRow){
//最后一行
outRect.top = offset;
outRect.bottom = offset;
}else{
//中间行
outRect.top = offset;
outRect.bottom = 0;
}


if(column == 0){
//第一列
outRect.left = offset;
outRect.right = offset / 2;
}else if(column == spanCount - 1){
//最后一列
outRect.left = offset / 2;
outRect.right = offset;
}else{
//中间列
outRect.left = offset / 2;
outRect.right = offset / 2;
}

}
}

1. 运行时找不到so文件

具体表现为:已经在libs目录添加了所有平台的so文件,但是运行是依然提示找不到so文件。

如:

1
2
java.lang.UnsatisfiedLinkError: dalvik.system.PathClassLoader[DexPathList[[zip file "/data/app/com.example.ijkplayer-CyD2mFQ8g6fyehi-g_1ALQ==/base.apk"],nativeLibraryDirectories=[/data/app/com.example.ijkplayer-CyD2mFQ8g6fyehi-g_1ALQ==/lib/arm64, /system/lib64, /vendor/lib64]]] couldn't find "libijkffmpeg.so"
at java.lang.Runtime.loadLibrary0(Runtime.java:1012)

问题:
编译时,jniLibs默认的路径是 /app/src/main/jniLibs ,如果so文件放在 /app/libs 需指定目录。

阅读全文 »

拷贝以下的内容(https://developer.android.com/studio/build/shrink-code.html
),以防平时不能访问 ,有条件的可以访问原文,排版更好,看得舒服。

压缩代码和资源

要尽可能减小 APK 文件,您应该启用压缩来移除发布构建中未使用的代码和资源。此页面介绍如何执行该操作,以及如何指定要在构建时保留或舍弃的代码和资源。
代码压缩通过 ProGuard 提供,ProGuard 会检测和移除封装应用中未使用的类、字段、方法和属性,包括自带代码库中的未使用项(这使其成为以变通方式解决 64k 引用限制的有用工具)。ProGuard 还可优化字节码,移除未使用的代码指令,以及用短名称混淆其余的类、字段和方法。混淆过的代码可令您的 APK 难以被逆向工程,这在应用使用许可验证等安全敏感性功能时特别有用。
资源压缩通过适用于 Gradle 的 Android 插件提供,该插件会移除封装应用中未使用的资源,包括代码库中未使用的资源。它可与代码压缩发挥协同效应,使得在移除未使用的代码后,任何不再被引用的资源也能安全地移除。
本文介绍的功能依赖下列组件:
SDK Tools 25.0.10 或更高版本
适用于 Gradle 的 Android 插件 2.0.0 或更高版本

压缩代码

要通过 ProGuard 启用代码压缩,请在 build.gradle
 文件内相应的构建类型中添加 minifyEnabled true

请注意,代码压缩会拖慢构建速度,因此您应该尽可能避免在调试构建中使用。不过,重要的是您一定要为用于测试的最终 APK 启用代码压缩,因为如果您不能充分地自定义要保留的代码,可能会引入错误。
例如,下面这段来自 build.gradle
 文件的代码用于为发布构建启用代码压缩:
android { buildTypes { release { minifyEnabled true proguardFiles getDefaultProguardFile(‘proguard-android.txt’), ‘proguard-rules.pro’ } } …}
:Android Studio 会在使用 Instant Run 时停用 ProGuard。如果您需要为增量式构建压缩代码,请尝试试用 Gradle 压缩器
除了 minifyEnabled
 属性外,还有用于定义 ProGuard 规则的 proguardFiles
 属性:
getDefaultProguardFile(‘proguard-android.txt’)
 方法可从 Android SDK tools/proguard/
 文件夹获取默认的 ProGuard 设置。提示:要想做进一步的代码压缩,请尝试使用位于同一位置的 proguard-android-optimize.txt
 文件。它包括相同的 ProGuard 规则,但还包括其他在字节码一级(方法内和方法间)执行分析的优化,以进一步减小 APK 大小和帮助提高其运行速度。

阅读全文 »

Java8

Java8上的自带Base64工具 java.util.Base64;

1
2
3
4
5
6
//编码
Base64.getEncoder().encodeToString("Hello".getBytes("utf-8"));

//解码
byte[] asBytes = Base64.getDecoder().decode("SGVsbG8=");
System.out.println(new String(asBytes, "utf-8"));

Android

Android SDK 自带 android.util.Base64;

阅读全文 »

apktool是apk反编译的核心,其他GUI工具内部都是用apktool来执行反编译任务。

主页和下载地址

主页地址: https://ibotpeaches.github.io/Apktool/install/
下载apktool.jar: https://bitbucket.org/iBotPeaches/apktool/downloads/
下载apktool.bat:https://raw.githubusercontent.com/iBotPeaches/Apktool/master/scripts/windows/apktool.bat

apktool.bat内容如下:

1
2
3
4
5
@echo off
if "%PATH_BASE%" == "" set PATH_BASE=%PATH%
set PATH=%CD%;%PATH_BASE%;
chcp 65001 2>nul >nul
java -jar -Duser.language=en -Dfile.encoding=UTF8 "%~dp0\apktool.jar" %*
阅读全文 »

由于不太想用Eclipse的库,寻求其他库来试试。

org.fusesource.mqtt-client 也是MQTT推荐 client 端的库,github的start也有500+吧,fork也有200+

引用库

1
compile 'org.fusesource.mqtt-client:mqtt-client:1.12'

作者给出了三种使用方法:1.阻塞;2.非阻塞(推荐);3.Future(没理解?)

阅读全文 »

Android机子刷机,遇到个频率(几秒一次)弹广告的内置流氓软件,作为service运行,可以进程保活,也就是强行关闭进程,它可以重新启动,非常恶心,时不时就来一个全屏广告,自动下载其他的apk安装包,自动安装。电脑管家是识别为木马的。
看了一下他的 AndroidManifest.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
33
34
35
36
37
38
39
40
41
<?xml version="1.0" encoding="utf-8" standalone="no"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.xym.ma" platformBuildVersionCode="19" platformBuildVersionName="4.4.2-1456859">
<application android:icon="@drawable/ic_launcher" android:label="xym" android:name="com.xym.ma.a">
<activity android:exported="true" android:name="com.xym.ma.b" android:screenOrientation="portrait" android:theme="@android:style/Theme.Translucent"/>
<meta-data android:name="googlepotatooid" android:value="712c9cef25b42dc4"/>
<meta-data android:name="googlepotatoo_channel" android:value="ch0117"/>
<meta-data android:name="googlepotatoo_jd" android:value="true"/>
<activity android:name="com.zuhn.mkn.d.a" android:screenOrientation="portrait" android:theme="@android:style/Theme.Translucent.NoTitleBar">
<intent-filter>
<action android:name="com.zuhn.mkn.activity"/>
</intent-filter>
</activity>
<service android:exported="true" android:name="com.zuhn.mkn.b.a"/>
<receiver android:name="com.zuhn.mkn.a.b">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED"/>
<action android:name="android.net.conn.CONNECTIVITY_CHANGE"/>
<action android:name="android.intent.action.USER_PRESENT"/>
<action android:name="com.zuhn.mkn.destory"/>
</intent-filter>
</receiver>
<activity android:label="JDBrowserActivity" android:name="com.jd.jdadsdk.JDAdBrowser" android:screenOrientation="portrait" android:theme="@android:style/Theme.Translucent.NoTitleBar"/>
<service android:exported="false" android:name="com.qq.e.comm.DownloadService"/>
<activity android:configChanges="keyboard|keyboardHidden|orientation|screenSize" android:name="com.qq.e.ads.ADActivity"/>
</application>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
<uses-permission android:name="com.android.launcher.permission.UNINSTALL_SHORTCUT"/>
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
<uses-permission android:name="com.android.launcher.permission.INSTALL_SHORTCUT"/>
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<uses-permission android:name="android.permission.GET_TASKS"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_CALL_LOG"/>
<uses-permission android:name="android.permission.READ_SMS"/>
</manifest>

http://square.github.io/retrofit/

准备

引入
1
2
compile 'com.squareup.retrofit2:retrofit:2.0.0'
compile 'com.squareup.retrofit2:converter-gson:2.+'

权限
1
<uses-permission android:name="android.permission.INTERNET" />

协议
1
2
/api/v1/user/login/{name}/{passwd}


Curl
1
curl -X GET --header 'Accept: application/json' 'http://192.168.1.219/api/v1/user/login/sam/123'

开始写代码

写一个API接口

阅读全文 »

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
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

public class Test {

public static void main(String[] args) throws IOException {

//cat /proc/meminfo

String commands="cat /proc/meminfo";

//String message= runCommands(commands);
//System.out.println(message);

getDiskInfo(1);
}

public static String runCommands(String commands) throws IOException{

Process process = Runtime.getRuntime().exec(commands);
InputStreamReader ir = new InputStreamReader(process.getInputStream(), "UTF-8");
BufferedReader input = new BufferedReader(ir);
String line;
String message="";
while ((line = input.readLine()) != null) {
//System.out.println("+++"+line);
message = message + line + "\n" ;
}
return message;
}

public static List<List> getDiskInfo(int sda_number) throws IOException{
String commands = "df -h |grep /dev/sda"+sda_number;
// String commands = "df -h";

Process process = Runtime.getRuntime().exec(commands);
InputStreamReader ir = new InputStreamReader(process.getInputStream(), "UTF-8");
BufferedReader input = new BufferedReader(ir);
String line;

List<List> result = new ArrayList();
/**
* [文件系统, 容量, 已用, 可用, 已用%, 挂载点]
* [/dev/sda1, 8.3G, 6.4G, 1.5G, 82%, /]
*/
while ((line = input.readLine()) != null) {
//System.out.println("----------"+line);
String[] temp = line.split(" ");
List<String> list_dev_sda = new ArrayList();
for (String string : temp) {
string = string.replaceAll(" ", "");
if(!string.equals("")){
//System.out.println(string);
list_dev_sda.add(string);
}
}
System.out.println(list_dev_sda.toString());
result.add(list_dev_sda);
}
return result;
}

public static HashMap<String, Float> getMemInfo() throws IOException{

String commands = "cat /proc/meminfo";
Process process = Runtime.getRuntime().exec(commands);
InputStreamReader ir = new InputStreamReader(process.getInputStream(), "UTF-8");
BufferedReader input = new BufferedReader(ir);
//读第一行和第二行
String[] memTotalArray = input.readLine().replace(" ", "").split(":");
String[] memFreeArray = input.readLine().replace(" ", "").split(":");

float memTotal = Float.valueOf(memTotalArray[1].replace("kB", ""));
float memFree = Float.valueOf(memFreeArray[1].replace("kB", ""));

System.out.println("memTotal = "+memTotal/(1024*1024) + "GB");
System.out.println("memFree = "+memFree/1024 + "MB");
HashMap<String, Float> mem = new HashMap<>();
mem.put("memTotal", memTotal);
mem.put("memFree", memFree);
return mem;
}
}

Apache Maven 入门篇 ( 上 )
本文着重动手,用 maven 来构建运行 hellow world 程序,体会一下不用任何 IDE ,只用 maven 是咋回事。

Apache Maven 入门篇(下)
* POM (Project Object Model)
* Maven 插件
* Maven 生命周期
* Maven 依赖管理
* Maven 库
我的 Maven Setting.xml 的mirrors配置

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
<mirrors>  

<mirror>
<id>aliyunmaven</id>
<name>aliyun public maven</name>
<url>https://maven.aliyun.com/repository/public</url>
<mirrorOf>public</mirrorOf>
</mirror>


<mirror>
<id>alimaven</id>
<name>aliyun central maven</name>
<url>http://maven.aliyun.com/nexus/content/groups/public/</url>
<mirrorOf>central</mirrorOf>
</mirror>

<mirror>
<id>ui</id>
<mirrorOf>central</mirrorOf>
<name>Human Readable Name for this Mirror.</name>
<url>http://uk.maven.org/maven2/</url>
</mirror>

<mirror>
<id>jboss-public-repository-group</id>
<mirrorOf>central</mirrorOf>
<name>JBoss Public Repository Group</name>
<url>http://repository.jboss.org/nexus/content/groups/public</url>
</mirror>



</mirrors>