Mr.HeXiang Blog

记录学习,学习记录


  • 首页

  • 关于

  • 标签

  • 分类

  • 归档

  • 公益404

SurfaceView预览camera

贺祥 | 发表于 2018-02-02 | 分类于 Android

SurfaceView 预览Camera
实现步骤

1.增加权限
1
<uses-permission android:name="android.permission.CAMERA"/>
2.动态申请权限
//检查访问摄像头权限
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
    ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.CAMERA}, 100);
} else {
    //拥有权限
    initCameraView();
}
3.为SurfaceView的SurfaceHolder增加回调

类中要实现回调 implements SurfaceHolder.Callback

1
2
3
4
5
private void initCameraView() {
surfaceView = findViewById(R.id.surfaceview);
surfaceHolder = surfaceView.getHolder();
surfaceHolder.addCallback(this);
}
阅读全文 »

用nginx-rtmp-module搭建rtmp流媒体服务器

贺祥 | 发表于 2018-01-30 | 分类于 音视频
前言

利用开源的nginx-rtmp-module和Nginx搭建流媒体服务器。Nginx是一个非常出色的http服务器,nginx-rtmp-module是一个开源的Nginx扩展模块,拥有很多功能特性,像接收rtmp推流拉流,hls直播等:

1.RTMP/HLS/MPEG-DASH live streaming
2.RTMP Video on demand FLV/MP4, playing from local filesystem or HTTP
3.Stream relay support for distributed streaming: push & pull models
4.Recording streams in multiple FLVs
5.H264/AAC support
6.Online transcoding with FFmpeg
7.HTTP callbacks (publish/play/record/update etc)
8.Running external programs on certain events (exec)
9.HTTP control module for recording audio/video and dropping clients
10.Advanced buffering techniques to keep memory allocations at a minimum level for faster streaming and low memory footprint
11.Proved to work with Wirecast, FMS, Wowza, JWPlayer, FlowPlayer, StrobeMediaPlayback, ffmpeg, avconv, rtmpdump, flvstreamer and many more
12.Statistics in XML/XSL in machine- & human- readable form
13.Linux/FreeBSD/MacOS/Windows

下面是配置安装使用详细过程
阅读全文 »

bugly的tinker热修复使用

贺祥 | 发表于 2018-01-25 | 分类于 Android

前言

bugly 热修复使用的是微信的tinker,然后封装好了,不需要在进行后台开发,简化了步骤,简单几部就可以集成了。
热修复:在用户不知情的情况升级补丁,修复bug~~~ 告别重新下载安装App
微信提供的tinker,没得说上亿的用户摆在那

Android Studio IDE环境设置
tinker不支持instant run模式,你需要找到File->Settings->Build,Execution,Deployment->instant run并关闭,日常调试可以tinker关闭来使用instant run。

相关资源
bugly 热修复及官方方文档

1
https://bugly.qq.com/docs/user-guide/instruction-manual-android-hotfix/?v=20180119105842

tinker 源码

1
https://github.com/Tencent/tinker
下面是集成及使用的详细过程
阅读全文 »

自定义实现向量图标动画VectorDrawable

贺祥 | 发表于 2018-01-14 | 分类于 Android
前言

从5.0(API等级21)开始,android开始支持矢量图了。利用矢量动画可以实现一些很酷炫的效果。
前阵子有个需求要实现一个酷炫输入框,利用矢量动画完美解决。

思路:画个路径,然后是加个分开和合并动画
向量动画结合TextInputLayout封装成一个输入框组件
Android 官网提示利用 AnimatedVectorDrawableCompat类兼容 Android 3.0(API 级别 11)及更高版本的

效果如下:
Alt text

阅读全文 »

openssl转换证书及查看证书信息

贺祥 | 发表于 2018-01-04 | 分类于 Android

生成客户端文件

1.生成客户端key
1
openssl genrsa -out 214344674390250.key 1024
2.利用private key生成客户端请求文件
1
openssl req -new -out client-req.csr -key 214344674390250.key  -config openssl.cnf
3.生成客户端证书(root证书,rootkey,客户端key,客户端请求文件这4个生成客户端证书)
1
openssl x509 -req -in client-req.csr -out client-cert.cer -signkey 214344674390250.key

打印出证书的全部内容

1
openssl x509 -in 214344674390250.pem -noout -text

将PEM转换为CRT(.CRT文件)

1
openssl x509 -outform der -in 214344674390250.pem -out certificate.crt

crt转换cer

windows 下双击- detail -复制到文件 -选择cer 保存

查看证书cer的信息

1
openssl x509 -in CA.cer -noout -text

nginx url中带中文不能访问

贺祥 | 发表于 2018-01-04 | 分类于 Android

解决nginx 部署,url中带中文不能访问

利用rz命令上传windows网站部署文件
输入rz回车会弹出文件夹选择 上传文件

之前用zip压缩文件打包,发现文件变乱码,用7z压缩 就正常了

一、文件上传

搜索7z安装包

1
apt-cache search "7z"

安装7z

1
apt install p7zip-full

用之前解压windows的zip有乱码换成7z的就好了
把压缩包解压到blog -r递归的意思-o指定解压目录,-o和目录不能有空格

1
7za x public.7z -r-oblog

递归给blog文件夹添加执行许可,否则会报403 fobidden

1
chmod -R +x blog

nginx 配置
编辑nginx.conf 中server 节点设置字符及目录,然后重启nginx

1
2
charset utf-8;
root /phpstudy/www/blog/;

Android消息机制及Handler与Looper和Message的关系

贺祥 | 发表于 2017-12-16 | 分类于 Android

一、Android 消息机制:

主线程在创建完后,会创建个Looper 类不停的循环。
直到读取到Message Queue消息队列的消息,处理响应消息然后移除消息。继续循环。
(只要有一个消息遇到了耗时操作,会导致其他消息无法响应,这就是ANR的产生的原因)

二、Handler 与Looper 及Message的关系

Handler 可以发送消息Message 给Message Queue消息队列,Looper读到Message消息,
并响应消息回调Handler 的handleMessage方法(这个方法是运行在主线程中的)。

三、下面是一个使用简单列子

发送消息给消息队列

1
mHandler.sendEmptyMessage(RESULT_OK);

覆写回调方法

1
2
3
4
5
6
7
8
9
10
Handler mHandler=new Handler(){
@Override
public void handleMessage(Message msg) {
// TODO Auto-generated method stub
super.handleMessage(msg);
/**
* Looper回调此方法,复写这个方法
*/
}
};

产生ANR的原因及如何避免

贺祥 | 发表于 2017-12-16 | 分类于 Android

一、主线程和是UI线程的关系

在Android中主线程就我们常说的UI线程,只有在主线程中才能修改界面。其他线程修改会报错。

二、什么是ANR?

全称为application is not responding ,应用失去响应。
如果主线程某个事件超过5秒没响应,Android就会弹出一个应用程序没有响应的对话框,你的Activity将会被杀掉。

三、产生ANR的常见原因:

1.网络请求图片大文件上传等
2.IO读写处理
3.复杂的算法,死循环,大量数据计算

四、避免ANR,UI线程中的操作时间要尽量短小,保证用户体验。

另起线程异步执行耗时操作。
即便小于5秒的操作,也会导致一时间的用户无法做其他操作,阻碍其他事件。

如何避免使用Handler造成的内存泄漏

贺祥 | 发表于 2017-12-16 | 分类于 Android

一、什么是内存泄漏?

对象已经没有被应用程序使用,由于引用或者其它垃圾回收器不能或者无法回收它们。

二、Activity中使用Handler为什么会造成泄漏

1.非静态的内部类和匿名内部类都会隐式地持有其外部类的引用

2.new Handler(){}是匿名内部内构造对象的格式

1
2
3
4
new 父类构造器(参数列表)|实现接口()  
{
//匿名内部类的类体部分
}

匿部类的形式构造Handler

1
2
3
4
5
6
7
8
9
10
/**
* 匿名内部类构造Handeler对象,默认持有外部类引用
*/
private Handler mHandler=new Handler()
{
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
}
};

三、如何避免使用Handler造成内存泄漏

1.声明静态内部内和弱引用

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
private MyHandler myHandler=new MyHandler(this);
/**
*1. 声明静态内部类(静态的内部类不会持有外部类的引用)
* 2.声明弱引用(GC在回收时会忽略掉弱引用,直接回收)
*/
static class MyHandler extends Handler {
WeakReference<Activity> mActivityReference;
MyHandler(Activity activity) {
//弱引用
mActivityReference= new WeakReference<Activity>(activity);
}
@Override
public void handleMessage(Message msg) {
switch (msg.what)
{
case 1:
final Activity activity = mActivityReference.get();
/**
* 执行些界面操作,更新等
*
*/
Log.w("leakHandler","MyHandler没有释放,还在执行任务哦~o~:");
break;
}

}
}

2.onDestroy()的时候调用Handler的removeCallbacksAndMessages(null),清除所有回调和消息

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@Override
protected void onDestroy() {
super.onDestroy();
/**
* 移除回调和消息
*/
if (myHandler != null)
myHandler.removeCallbacksAndMessages(null);
/**
* leakCanary去观察myHandler是否泄露了
*/
//MyApp.getRefWatcher(this).watch(myHandler);

}

创建多线程的3种方法

贺祥 | 发表于 2017-12-15 | 分类于 Android

多线程实现有3种方法,其中前两中是常用的方法,推荐第二种方法,一个类应该在其修改或者加强是才继承

1.继承Thread类,重写run()方法,实例化该类,调用线程start()方法

(1)自定义类,继承Thread类,重写run()方法
(2)创建该Thread子类实例
(3)然后调用线程start()方法

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
public class TestThread extends  Thread{
@Override
public void run() {
printThreadMsg("1.2.new TestThread run");
}
}
/**
* 打印线程信息
* @param msg
*/
private void printThreadMsg(String msg)
{
System.out.println(msg+":threadName:"+Thread.currentThread().getName()+",threadId:"+Thread.currentThread().getId());
}

/**
* 1.1 匿名内部类(继承Thread类,重写run()方法)
*/
new Thread(){
@Override
public void run() {
printThreadMsg("1.1 new Thread() run");
}
}.start();
/**
* 1.2 继承Thread类,重写run()方法
*/
new TestThread().start();

2.实现Runnable接口,并实现该接口的run()的方法,

具体步骤:
(1)自定义类,并实现Runnable接口,实现run()方法
(2)创建Thread子类实例:用实现Runnable接口的对象作为参数实例化个Thread对象
(3)然后调用线程start()方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class TestRunnable implements  Runnable{
@Override
public void run() {
printThreadMsg("2.2.TestRunnable run");
}
}

/**
* 2.1实现Runnable接口,并实现该接口的run()的方法,然后用实现Runnable接口的对象作为参数实例化Thread对象
*/
new Thread(new TestRunnable()).start();

/**
* 2.2实现Runnable接口,并实现该接口的run()的方法,然后用实现Runnable接口的对象作为参数实例化Thread对象
*/
new Thread(new Runnable() {
@Override
public void run() {
printThreadMsg("2.2. new Thread.new Runnable run");
}
}).start();

3.实现Callable接口,重写call()方法

(1)自定义类,实现Callable接口,实现call()方法
(2)实例化ExecutorService 对象,实例化个刚刚自定义类(实现Callable接口)的对象,把它作为参数调用submit()方法
(3)注意get()方法获取结果会造成阻塞

public static class TestCallable implements Callable{
@Override
public Object call() throws Exception {
/**

     * 沉睡6秒,模拟耗时操作
     */
    Thread.sleep(6000);
    System.out.println("3.TestCallable  call:threadName:"+Thread.currentThread().getName()+",threadId:"+Thread.currentThread().getId());

    return "这是 TestCallable call 执行完 返回的结果";
}

}

/
实现Callable接口,重写call()方法 /
ExecutorService mExecutorService= Executors.newSingleThreadExecutor();
Future future=mExecutorService.submit(new TestCallable());
try {
/

     * future.get()用来获取结果,  会造成线程阻塞,直到call()结束
     * 等待线程结束,并且返回结果
     * 线程阻塞了
     */
String result= String.valueOf(future.get());
System.out.println("3.TestCallable call return:"+result+","+Thread.currentThread().getName()+",threadId:"+Thread.currentThread().getId());

} catch (Exception e) {
    e.printStackTrace();
}

最后附上所有代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
package com.hex168.demo.therad;

import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import java.lang.ref.WeakReference;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

/**
* author:dz_hexiang on 2017/9/23 13:06
* email:472482006@qq.com
* 测试线程创建
*/
public class ThreadActivity extends Activity {

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_therad);
/**
* 1.1 匿名内部类(继承Thread类,重写run()方法)
*/
new Thread(){
@Override
public void run() {
printThreadMsg("1.1 new Thread() run");
}
}.start();
/**
* 1.2 继承Thread类,重写run()方法
*/
new TestThread().start();

/**
* 2.1实现Runnable接口,并实现该接口的run()的方法,然后用实现Runnable接口的对象作为参数实例化Thread对象
*/
new Thread(new TestRunnable()).start();

/**
* 2.2实现Runnable接口,并实现该接口的run()的方法,然后用实现Runnable接口的对象作为参数实例化Thread对象
*/
new Thread(new Runnable() {
@Override
public void run() {
printThreadMsg("2.2. new Thread.new Runnable run");
}
}).start();


/**
*实现Callable接口,重写call()方法
*/
ExecutorService mExecutorService= Executors.newSingleThreadExecutor();
Future future=mExecutorService.submit(new TestCallable());
try {
/**
* future.get()用来获取结果, 会造成线程阻塞,直到call()结束
* 等待线程结束,并且返回结果
* 线程阻塞了
*/
String result= String.valueOf(future.get());
System.out.println("3.TestCallable call return:"+result+","+Thread.currentThread().getName()+",threadId:"+Thread.currentThread().getId());

} catch (Exception e) {
e.printStackTrace();
}
/**
* handler 及runnable都是在主线程
*/
handler.post(handlerRunnable);
}

public class TestThread extends Thread{
@Override
public void run() {
printThreadMsg("1.2.new TestThread run");
}
}

public class TestRunnable implements Runnable{
@Override
public void run() {
printThreadMsg("2.2.TestRunnable run");
}
}

public Runnable handlerRunnable =new Runnable() {
@Override
public void run() {
printThreadMsg("4.handler handlerRunnable run");
}
};

/**
* 打印线程信息
* @param msg
*/
private void printThreadMsg(String msg)
{
System.out.println(msg+":threadName:"+Thread.currentThread().getName()+",threadId:"+Thread.currentThread().getId());
}

private MyHandler handler=new MyHandler(this);
static class MyHandler extends Handler{
WeakReference<Activity> activityWeakReference;

MyHandler(Activity c)
{
activityWeakReference=new WeakReference<Activity>(c);
}
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
}
}

public static class TestCallable implements Callable{
@Override
public Object call() throws Exception {
/**
* 沉睡6秒,模拟耗时操作
*/
Thread.sleep(6000);
System.out.println("3.TestCallable call:threadName:"+Thread.currentThread().getName()+",threadId:"+Thread.currentThread().getId());

return "这是 TestCallable call 执行完 返回的结果";
}
}
}

运行结果

enter image description here

1…678…13
贺祥

贺祥

记学学记

123 日志
10 分类
65 标签
© 2023 贺祥
由 Hexo 强力驱动「Hosted by Coding Pages」
|
主题 — NexT.Pisces v5.1.3