随手写,想哪写哪,不定期更
simpleTag
等作为into()
对象时,需设置override()
属性避免加载图片过大导致OOM
Bitmap.createBitmap(scaleBitmap, 0, 0, w, h)
进行裁剪CornerTransform transformation = new CornerTransform(context, dip2px(context,radius));
//只是绘制左上角和右上角圆角
transformation.setExceptCorner(false, false, false, false);
MultiTransformation<Bitmap> mation = new MultiTransformation<>(new CenterCrop(), transformation);
可以设置圆角,但必须先指定宽高override(w,h);
6. 某些设备设置565之后,出现图片宽高与原宽高不一致,等比例缩小了,具体原因不明,使用 Bitmap bitmap565 = bitmap.copy(Bitmap.Config.RGB_565,true);
代替
// Bitmap bitmap5651 = bitmapPool.get(bitmap.getWidth(), bitmap.getHeight(), Bitmap.Config.RGB_565);
//Canvas canvas = new Canvas(bitmap565);
// 设置背景色,防止透明图出现黑色的情况
//canvas.drawColor(Color.WHITE);
//Paint paint=new Paint();
//paint.setColor(Color.WHITE);
//canvas.drawBitmap(bitmap, 0, 0, null);
Glide.with(content).clear(tag)
,取消任务时,再次回到当前页可能会导致try to use recy bitmap 的崩溃;这种情况一般发送在into(new SimpleTag<>())的使用方式上,只要在加载前设置背景色可解决此问题。可参考 https://blog.csdn.net/Conan9715/article/details/1179145061.在使用WebView比较频繁的项目中,可提前初始化一个WebView待用,需要时直接引用,app退出时销毁,具体可参考H5实现秒开
2.销毁WebView
@Override
protected void onDestroy() {
super.onDestroy();
// 先从父控件中移除WebView
mWebViewContainer.removeView(mWebView);
mWebView.stopLoading();
mWebView.getSettings().setJavaScriptEnabled(false);
mWebView.clearHistory();
mWebView.removeAllViews();
mWebView.destroy();
}
webView.addJavascriptInterface(new JavaObject(),"AndroidObject");
public class JavaObject{
@JavascriptInterface
public void clickWebBtn(String arg1,String arg2,String arg3){
android:textCursorDrawable="@drawable/my_cursor"
属性进行设置<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="@color/green" />
<size android:width="1dp" />
</shape>
ArrayMap的使用跟HashMap是一样的。当数据结构为
的时候(key的hash值为value的下标),都可以使用ArrayMap替代。
但是相较于HashMap,ArrayMap在Android中也不总是高效的。当数据量大了(数百)之后,其性能就会下降至少50%。所以,当数据量小的时候,使用ArrayMap效率还是蛮高的,HashMap 中数组的默认容量16,装载因子0.75,2倍扩容,初始化指定大小最好是2的幂,不是2的幂的会转换成2的幂, 比Math.ceil(n/0.75)大的最近的2的幂,这样在扩容时可直接进行位运算,无需转换10进制,同时减少hash碰撞(开放寻址法和拉链法解决hash碰撞)
也是用一个
对
SparseIntArray:当map的结构为Map的时候使用,效率较高。
SparseBooleanArray: 当map的结构为Map的时候使用,效率较高。
SparseLongArray: 当map的结构为Map的时候使用,效率较高。
LongSparseArray: 当map的结构为Map的时候使用,效率较高。
和ArrayMap的目的类似,用来提高HashSet的效率。使用方法跟HashSet类似
compile 'com.google.guava:guava:26.0-jre'
list->String : String s=Joiner.on(“,”).join(list);
String->list: List< String > listSplitter.on(“-”).splitToList(str)
内部以数组方式实现,初始长度0,有默认长容量DEFAULT_CAPACITY=10(jdk1.6,jdk1.7默认是空数组),在首次add时添加,扩容按1.5倍容量扩容;易查询,插入慢。长度初始化为默认长度就行,因为第一次扩容就是DEFAULT_CAPACITY长。
与ArrayList类似,不同的是支持多线程,
内部以循环双向链表结构实现,初始长度0,查询慢,插入快。
1.NestScrollView 与RecyclerView 嵌套会导致recycler不能复用,导致滑动卡顿
滑动嵌套处理
2. 分页查询由于新增数据导致重复数据解决 主要思想在于出入最后的ID给后台,后台在取值时永远取第一页,同时比较ID大小确认该页数据,避免因删除或插入导致之后的数据不准确
3. viewGroup可设置layoutAnimation动画效果,可设置子项延迟时间,子项动画效果,执行顺序等;但recyclerView这类填充视图设置后需在数据填充后手动执行startLayoutAnimation()
方法
<layoutAnimation xmlns:android="http://schemas.android.com/apk/res/android"
android:animation="@anim/item_anim"
android:animationOrder="normal"
android:delay="20%" />
其中item_anim
就是普通的set动画集
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate
android:duration="400"
android:fromYDelta="-100%"
android:fromXDelta="0"
android:toYDelta="0"
android:toXDelta="0"/>
<alpha
android:duration="400"
android:fromAlpha="0"
android:toAlpha="1"
/>
</set>
4.参考使用合集
android:stateListAnimator="@null"
setOnEditorActionListener
,EditorInfo
判断设置类别ClickSpan
进行点击设置时,会有点击冲突,解决同时触发点击事件的冲突可以去掉textView上的点击事件,在父控件上添加点击事件,同时自定义LinkMovementMethodif(text instanceof Spannable){
Spannable spannable= (Spannable) text;
Object[] spans = spannable.getSpans(0, text.length(), Object.class);
for (Object span: spans) {
spannable.removeSpan(span);
}
}
public class OnGlobalLayoutListenerByEllipSize implements ViewTreeObserver.OnGlobalLayoutListener {
private TextView mTextView;
private int mMaxLines; //最大行数
public OnGlobalLayoutListenerByEllipSize(TextView textView,int maxLines){
if(maxLines <= 0)
throw new IllegalArgumentException("maxLines不能小于等于0");
this.mTextView = textView;
this.mMaxLines = maxLines;
this.mTextView.setMaxLines(mMaxLines);
// this.mTextView.setSingleLine(false);
}
@Override
public void onGlobalLayout() {
mTextView.getViewTreeObserver().removeOnGlobalLayoutListener(this);
LogUtils.i("lineCount:"+mTextView.getLineCount()+" mMaxLine:"+mMaxLines);
if(mTextView.getLineCount() > mMaxLines){
int line = mTextView.getLayout().getLineEnd(mMaxLines-1);
CharSequence truncate = "...";//定义成CharSequence类型,是为了兼容emoji表情,如果使用String类型则会造成emoji无法显示
CharSequence text = mTextView.getText();
try {
text = text.subSequence(0, line -3);
}catch (Exception e){
truncate = "";
text = mTextView.getText();
}
TextUtils.TruncateAt at = mTextView.getEllipsize();
if(at == TextUtils.TruncateAt.START) {
mTextView.setText(truncate);
mTextView.append(text);
}else if(at == TextUtils.TruncateAt.MIDDLE){
mTextView.setText(text.subSequence(0,text.length()/2));
mTextView.append(truncate);
mTextView.append(text.subSequence(text.length()/2,text.length()));
}else {
mTextView.setText(text);
mTextView.append(truncate);
}
}
}
}
android:textCursorDrawable="@drawable/my_cursor"
,shape中设置宽度就能看到关标1.MaterialButton,提供圆角,边框,ripper 的快速实现,指定app:的相关属性即可
1.cardView 需显示指定backgroundColor ,否则在不同手机上默认的背景色不一致
2.使用setXfermode与图片组合使用时,设置模式的paint与绘制的paint不是同一个paint,设置模式的paint只针对使用的bitmap使用,该bitmap需绘制在新建的canvas中,bitmap通过eraseColor设置颜色,到画布需绘制时使用canvas.drawBitmap(mBitmap, mOldRects, mNeedDrawRect, paint);来绘制路径。
3.cardView的上位替代MaterialCardView,新增边线,点击状态,波纹等属性
1.在绘制线性布局的UI时,常常需要绘制分割线,使用LinearLayoutCompat可以轻松的实现而不需要设置view的背景来实现,使用app:divider
属性来设置,该属性值为drawable,并且shape中需要指定shape的高度,显示区域可通过app:showDivideers
设置值middle代表两控件之间,beginning代表控件上分,end代表控件下方,app:dividerPadding
代表分割线的padding,可缩进一定的位置
1.
设置最大屏占比,避免某些手机因过长而有黑边的情况
2. 解决启动黑白屏设置,设置的style与application标签中设置的style写在同一文件下,否则可能存在启动preDraw不显示问题
if (savedInstanceState != null) { savedInstanceState.putParcelable("android:support:fragments", null); }
,但仍然发现activity中的adapter还是fragment的数据,新建的fragment没有被使用,可以重写adapter去除 @NonNull
@Override
public Object instantiateItem(@NonNull ViewGroup container, int position) {
try {//清除保留的fragment
Field mFragments = getClass().getSuperclass().getDeclaredField("mFragments");
mFragments.setAccessible(true);
((ArrayList) mFragments.get(this)).clear();
Field mSavedState = getClass().getSuperclass().getDeclaredField("mSavedState");
mSavedState.setAccessible(true);
((ArrayList) mSavedState.get(this)).clear();
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
return super.instantiateItem(container, position);
}
1.自定义contentProvide通过authorities定位位置,提供方设定好路径和查询实现,使用方使用对应的URI进行访问,提供方需设置export属性为true,表明允许其他应用访问,使用方需指定
或者
表明会与该包或该内容提供方可见(在android11引入的),之后才能通过ContentResolver方法访问ContentProvide中的数据
1.使用rxjava进行任务时如果出现异常,任务取消状态下没有线程处理异常会导致事件无法下发,引发崩溃;需配置 RxJavaPlugins.setErrorHandler(throwable -> { throwable.printStackTrace(); //Trace.e("MyApplication", "MyApplication setRxJavaErrorHandler " + throwable.getMessage()); });
1.视频解码成帧图片,自带的MediaMetadataRetriever方法速度慢,api简单;MediaCode 速度快,但api复杂
extractor = initMediaExtractor(file);
mediaFormat = initMediaFormat(videoPath, extractor);
decoder = initMediaCodec(mediaFormat);
decoder.configure(mediaFormat, null, null, 0);
decoder.start();
Log.i("totalSec", "totalSec:" + totalSec+" addSp:"+addSplit);
for (long time = 0; time < totalSec; time += addSplit) {
//获取这一帧图片
Bitmap bitmap = getBitmapBySec(extractor, mediaFormat, decoder, time);
if (bitmap == null){
continue;
}
}
private static Bitmap getBitmapBySec(MediaExtractor extractor, MediaFormat mediaFormat, MediaCodec decoder, long sec) throws IOException {
MediaCodec.BufferInfo info = new MediaCodec.BufferInfo();
Bitmap bitmap = null;
boolean sawInputEOS = false;
boolean sawOutputEOS = false;
boolean stopDecode = false;
final int width = mediaFormat.getInteger(MediaFormat.KEY_WIDTH);
final int height = mediaFormat.getInteger(MediaFormat.KEY_HEIGHT);
Log.i("getBitmapBySec", "w: " + width);
long presentationTimeUs = -1;
int outputBufferId;
Image image = null;
extractor.seekTo(sec, MediaExtractor.SEEK_TO_PREVIOUS_SYNC);
while (!sawOutputEOS && !stopDecode) {
if (!sawInputEOS) {
//Log.i("getBitmapBySec", "sawInputEOS: " + sawInputEOS);
int inputBufferId = decoder.dequeueInputBuffer(-1);
//Log.i("getBitmapBySec", "inputBufferId: " + inputBufferId);
if (inputBufferId >= 0) {
ByteBuffer inputBuffer = decoder.getInputBuffer(inputBufferId);
int sampleSize = extractor.readSampleData(inputBuffer, 0);
if (sampleSize < 0) {
//Log.i("getBitmapBySec", "sampleSize<0 ");
decoder.queueInputBuffer(inputBufferId, 0, 0, 0L, MediaCodec.BUFFER_FLAG_END_OF_STREAM);
sawInputEOS = true;
} else {
presentationTimeUs = extractor.getSampleTime();
//Log.i("getBitmapBySec", "presentationTimeUs: " + presentationTimeUs);
decoder.queueInputBuffer(inputBufferId, 0, sampleSize, presentationTimeUs, 0);
extractor.advance();
}
}
}
outputBufferId = decoder.dequeueOutputBuffer(info, DEFAULT_TIMEOUT_US);
if (outputBufferId >= 0) {
if ((info.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0 | presentationTimeUs >= sec) {
Log.i("getBitmapBySec", "sec: " + sec);
sawOutputEOS = true;
boolean doRender = (info.size != 0);
if (doRender) {
Log.i("getBitmapBySec", "deal bitmap which at " + presentationTimeUs);
image = decoder.getOutputImage(outputBufferId);
YuvImage yuvImage = new YuvImage(YUV_420_888toNV21(image), ImageFormat.NV21, width, height, null);
ByteArrayOutputStream stream = new ByteArrayOutputStream();
yuvImage.compressToJpeg(new Rect(0, 0, width, height), 100, stream);
bitmap = BitmapFactory.decodeByteArray(stream.toByteArray(), 0, stream.size());
stream.close();
image.close();
}
}
decoder.releaseOutputBuffer(outputBufferId, true);
}
}
return bitmap;
}
1.接口缓存,分两种:
有网状态,添加addNetworkInterceptor()
拦截器
设置max-age用于在一定时间内重复调用取缓存数据,超过时间重新获取。
public class CacheOnlineInterceptor implements Interceptor {
private CacheOnlineInterceptor(){}
private static CacheOnlineInterceptor cacheInterceptor;
public static CacheOnlineInterceptor getInstance(){
if(cacheInterceptor==null){
cacheInterceptor=new CacheOnlineInterceptor();
}
return cacheInterceptor;
}
@NonNull
@Override
public Response intercept(@NonNull Chain chain) throws IOException {
Request request=chain.request();
Response response=chain.proceed(request);
return response.newBuilder().header("Cache-Control","public,max-age=30")
.removeHeader("Pragma")
.build();
}
}
无网状态 添加应用拦截器addInterceptor()
可以设置FORCE_CACHE策略,直接取缓存,没有就报504错误;也可以设置max-stale缓存失效时间,超过时间不使用缓存。
public class CacheInterceptor implements Interceptor {
private CacheInterceptor(){}
private static CacheInterceptor cacheInterceptor;
public static CacheInterceptor getInstance(){
if(cacheInterceptor==null){
cacheInterceptor=new CacheInterceptor();
}
return cacheInterceptor;
}
@NonNull
@Override
public Response intercept(@NonNull Chain chain) throws IOException {
Request request = chain.request();
Request.Builder requestBuilder = request.newBuilder();
if (!NetworkUtils.isConnected()) {
Log.i("testHttpUtils","no netWork");
// requestBuilder.header("Cache-Control","public,only-if-cached,max-stale=600");
requestBuilder.cacheControl(CacheControl.FORCE_CACHE); // 直接使用缓存
}
return chain.proceed(requestBuilder.build());
}
}
需注意缓存接口在调用前后完全一致才会其作用,如果入参在有网和没网时候有不同,比如传了网络状态或时间戳,那接口不一致就无法使用缓存的数据。且OKHttp只对Get请求有缓存,POST请求没有缓存
2. 只对指定接口进行缓存时,首先接口处设置对应的head 如
@Headers("Cache-Control: public, max-age=" + 24 * 3600)
@GET("url")
Observable<?> queryInfo(@Query("userName") String userName);
这样在拦截器处读取String cacheControl = request.cacheControl().toString();
头文件中的值判断是否需要使用缓存
3. 在添加网络拦截器时可去除可变参数,请求时判断是否有网,无网就不添加该参数,这样可以使得无网情况下获取到对应缓存而不受可变参数的影响;对于一些特殊参数:比如碰到类似传入时间戳的接口,可以将时间在一定时间内向下取整,保证一段时间内的时间戳相同,在有网状态下可以规避调因参数的不同而无法使用缓存的情况,该方法与去除参数缓存方案不可共存。
HttpUrl newUrl=chain.request().url().newBuilder().removeAllQueryParameters("timestamp").build();
Request newRequest=chain.request().newBuilder().url(newUrl).build();
return response.newBuilder().request(newRequest).header("Cache-Control","public,max-age=30")
.removeHeader("Pragma")
.build();
1.lancet 使用可参考:https://mp.weixin.qq.com/s?__biz=MzAxMTI4MTkwNQ==&mid=2650840653&idx=1&sn=b862759352e0f8bb7c2675006d2e63af&chksm=80b74ad3b7c0c3c547f18e2a50571695b0f9568e6b9c5d995d468d9f140410cd4b9d70b3ad59&scene=21#wechat_redirect
合理运用运算符 &、|、^、>>、<< 可以快捷方便的进行一些运算
符号 | 规则 | 应用 |
---|---|---|
& | 都为1结果为1 | 1.清零:a&0=0 2.取一个数的指定位(二进制下):a&0111 就是指定后三位 3.判断奇偶:a&1==0 为偶 |
| | 有一个为1结果为1 | 1.一个数某些位设置为1(二进制下):a |
^ | 相同为0不同为1 | 1.指定位翻转:a^0111 就是将后三位翻转 2.与0异或结果为本身:a^0=a 3.交换两值:a=a ^ b;b=a ^ b;a=a ^ b 4.与自身异或结果为0 |
~ | 取反 | ~1=0; ~0=1 |
>> | 向右移动若干位,正数补0负数补1 | 1.a>>n = a除于 2的n次方 |
<< | 向左移动若干位,补0 | 1.a< |
音频识别框架:https://juejin.cn/post/7268960029272473635
AcousticEchoCanceler
继承AudioEffect
回音消除AcousticEchoCanceler.isAvailable()
使用android.permission.RECORD_AUDIO
audioTrack=new AudioTrack(AudioManager.STREAM_MUSIC, 8000, AudioFormat.CHANNEL_OUT_MONO, AudioFormat.ENCODING_PCM_16BIT, mRecorderBufferSize * 2 , AudioTrack.MODE_STREAM, audioSessionId);
sessionId
也可以尝试通过AudioSystem audioSystem = AudioSystem.getAudioSystem( AudioSystem.LOCATOR_PROTOCOL_AUDIORECORD);audioSession = audioSystem.getAudioSessionId();
获取 AudioEffect
AudioEffect
是音频播放的进行音效控制的基础类,一般使用他的派生类Equalizer
均衡器(控制某一频率的声响大小)、Equalizer equalizer = new Equalizer(0, mediaPlayer.getAudioSessionId());
equalizer.setEnabled(true);
//获取均衡器引擎支持的频段数
short bands = equalizer.getNumberOfBands();
//获取最大和最小增益
final short minEQLevel = equalizer.getBandLevelRange()[0];
final short maxEQLevel = equalizer.getBandLevelRange()[1];
for (short i = 0; i < bands; i++) {
final short band = i;
//获取当前频段的中心频率,分别为:60Hz,230Hz,910Hz,3600Hz,14000Hz
int currentFreq = equalizer.getCenterFreq(band);
//获取给定均衡器频段的增益
short level = equalizer.getBandLevel(band);
Log.d("Equalizer","currentFreq is: " + currentFreq + ", band level is: " + level);
//为给定的均衡器频带设置增益值
equalizer.setBandLevel(band,xx);
}
short presets= equalizer.getNumberOfPresets();//增益参数
//获取系统预设的增益
for (short i = 0; i < presets; i++) {
Log.d("presets",equalizer.getPresetName(i));
}
//Normal、Classical、Dance、Flat、Folk、Heavy Metal、Hip hop、Jazz、Pop、Rock。
equalizer.usePreset(i);//设置参数
Virtualizer
环绕音(让声音产生空间感)、Virtualizer mVirtualizer= new Virtualizer (0, mMediaPlayer.getAudioSessionId()); //优先级为0
mVirtualizer.setEnabled(true);
if (mVirtualizer.getStrengthSupported())
{
short strength = mVirtualizer.getRoundedStrength();
mVirtualizer.setStrength((short)strength);//设置力度 力度越大声音越远
}
getRoundedStrength() :获取特效力度,特效力度值在0~1000间变化。
BassBoost
重低音控制器(增强低音强度)、BassBoost bassBoost = new BassBoost(0,mediaPlayer.getAudioSessionId());
bassBoost.setEnabled(true);
if (bassBoost.getStrengthSupported()){
bassBoost.setStrength((short) 100);
}
PresetReverb
混响(一般用于音乐,反射叠加产生的音效如流行,爵士等)、PresetReverb presetReverb = new PresetReverb(0,mediaPlayer.getAudioSessionId());
presetReverb.setEnabled(true);
presetReverb.setPreset(PresetReverb.PRESET_LARGEROOM);//0-6空间逐渐增大
EnvironmentalReverb
环境混响(一般用于游戏,如马路,大厅,室内等)setDecayHFRatio:
设置高频到中频衰减比率。范围是[100, 2000] ,如果设为1000,则全部衰减相同。setDecayTime:
中频混响衰减时间。[100, 20000]setDensity:
在后期混响衰减,控制模态密度的值。[0, 1000]setDiffusion:
在后期混响衰减,控制回声密度的值。 [0, 1000]setReflectionsDelay:
初始反射延迟时间。[0, 300]setReflectionsLevel:
对于环境效果的早期反射等级。[-9000, 1000]setReverbDelay:
先对于初始反射的后期混响延迟时间。 [0, 100]setReverbLevel:
相对于环境效果的后期混响等级。[-9000, 2000]setRoomHFLevel:
相对于高频环境效果等级。 [-9000, 0]setRoomLevel:
相对于低频环境效果等级。[-9000, 0]DynamicsProcessing
//创建对象
int audioSessionId = mediaPlayer.getAudioSessionId();
DynamicsProcessing.Config.Builder builder = new DynamicsProcessing.Config.Builder(
0,//variant
1,//channelCount
true,//preEqInUse
10,//preEqBandCount
true,//mbcInUse
10,//mbcBandCount
true,//postEqInUse
10,//postEqBandCount
true//limiterInUse
);
DynamicsProcessing mDynamicsProcessing = new DynamicsProcessing(0, audioSessionId, builder.build());
mDynamicsProcessing.setEnabled(true);
//创建均衡器对象
//创建用于调节的10个频段
private static final int[] bandVal = {31, 62, 125, 250, 500, 1000, 2000, 4000, 8000, 16000};
private static final int maxBandCount = bandVal.length;
DynamicsProcessing.Eq mEq = new DynamicsProcessing.Eq(true, true, maxBandCount);
mEq.setEnabled(true);
for (int i = 0; i < maxBandCount; i++) {
mEq.getBand(i).setCutoffFrequency(bandVal[i]);//设置此频段将处理的最高频率数(以 Hz 为单位)
}
//设置压缩前的均衡器给全频道
mDynamicsProcessing.setPreEqAllChannelsTo(mEq);
//设置压缩前的均衡器给指定频道
//public static final int CHANNEL_1 = 0;
//public static final int CHANNEL_2 = 1;
//mDynamicsProcessing.setPreEqByChannelIndex(CHANNEL_1, mEq);
//设置压缩后的均衡器给全频道
//mDynamicsProcessing.setPostEqAllChannelsTo(mEq);
//设置压缩后的均衡器给指定频道
//public static final int CHANNEL_1 = 0;
//public static final int CHANNEL_2 = 1;
//mDynamicsProcessing.setPostEqByChannelIndex(CHANNEL_1, mEq);
//创建压缩器对象
DynamicsProcessing.Mbc mDynamicsProcessingMbc = new DynamicsProcessing.Mbc(true, true, maxBandCount);
mDynamicsProcessingMbc.setEnabled(true);
for (int i = 0; i < maxBandCount; i++) {
mDynamicsProcessingMbc.getBand(i).setCutoffFrequency(bandVal[i]);//设置此频段将处理的最高频率数(以 Hz 为单位)
}
//设置多频段压缩器给全频道
mDynamicsProcessing.setMbcAllChannelsTo(mDynamicsProcessingMbc);
//设置多频段压缩器给指定频道
//mDynamicsProcessing.getMbcBandByChannelIndex(CHANNEL_1, mDynamicsProcessingMbc);
//创建限制器对象
//Limiter构造参数
private static final boolean LIMITER_DEFAULT_IN_USE = true;//如果将使用 MBC 阶段,则为 true,否则为 false。
private static final boolean LIMITER_DEFAULT_ENABLED = true;//如果启用/禁用 MBC 阶段,则为 true。这可以在效果运行时更改
private static final int LIMITER_DEFAULT_LINK_GROUP = 0;//分配给此限制器的组的索引。只有共享相同 linkGroup 索引的限制器才会一起做出反应。
private static final float LIMITER_DEFAULT_ATTACK_TIME = 1; // 限制器压缩器的启动时间,以毫秒 (ms) 为单位
private static final float LIMITER_DEFAULT_RELEASE_TIME = 60; //限制器压缩器的释放时间,以毫秒 (ms) 为单位
private static final float LIMITER_DEFAULT_RATIO = 10; // 限制器压缩比 (N:1)(输入:输出)
private static final float LIMITER_DEFAULT_THRESHOLD = -2; // 限幅压缩器阈值以分贝 (dB) 为单位,从 0 dB 满量程 (dBFS) 开始测量。
private static final float LIMITER_DEFAULT_POST_GAIN = 0; // 压缩后应用于信号的增益。
DynamicsProcessing.Limiter mDynamicsProcessingLimiter = new DynamicsProcessing.Limiter(LIMITER_DEFAULT_IN_USE, LIMITER_DEFAULT_ENABLED, LIMITER_DEFAULT_LINK_GROUP, LIMITER_DEFAULT_ATTACK_TIME, LIMITER_DEFAULT_RELEASE_TIME, LIMITER_DEFAULT_RATIO, LIMITER_DEFAULT_THRESHOLD, LIMITER_DEFAULT_POST_GAIN);
mDynamicsProcessingLimiter.setEnabled(true);
//设置限制器给全频道
mDynamicsProcessing.setLimiterAllChannelsTo(mDynamicsProcessingLimiter);
//设置限制器给指定频道
//mDynamicsProcessing.setLimiterByChannelIndex(CHANNEL_1, mDynamicsProcessingLimiter);
//调节输入增益
mDynamicsProcessing.setInputGainAllChannelsTo(value);
//调节均衡器
//根据调节的频段在bandVal数组中的索引bandIndex和调整后的值gain来调节均衡器
mEq.getBand(bandIndex).setGain(gain);
//设置压缩前的均衡器频段增益给全频道
mDynamicsProcessing.setPreEqBandAllChannelsTo(bandIndex, mEq.getBand(bandIndex));
//设置压缩前的均衡器频段增益给指定频道
//mDynamicsProcessing.setPreEqBandByChannelIndex(CHANNEL_1, bandIndex, mEq.getBand(bandIndex));
//设置压缩后的均衡器频段增益给全频道
//mDynamicsProcessing.setPostEqBandAllChannelsTo(bandIndex, mEq.getBand(bandIndex));
//设置压缩后的均衡器频段增益给指定频道
//mDynamicsProcessing.setPostEqBandByChannelIndex(CHANNEL_1, bandIndex, mEq.getBand(bandIndex));
//调节压缩器
//设置在压缩之前应用于信号的增益,以分贝 (dB) 为单位测量,其中 0 dB 表示没有电平变化。
mDynamicsProcessingMbc.getBand(bandIndex).setPreGain(gain);
//设置给全频道
mDynamicsProcessing.setMbcBandAllChannelsTo(bandIndex, mDynamicsProcessingMbc.getBand(bandIndex));
//设置给指定频道
//mDynamicsProcessing.setMbcBandByChannelIndex(CHANNEL_1, bandIndex, mDynamicsProcessingMbc.getBand(bandIndex));
//设置在压缩之后应用于信号的增益,以分贝 (dB) 为单位测量,其中 0 dB 表示没有电平变化。
//mDynamicsProcessingMbc.getBand(bandIndex).setPostGain(gain);
//设置给全频道
//mDynamicsProcessing.setMbcBandAllChannelsTo(bandIndex, mDynamicsProcessingMbc.getBand(bandIndex));
//设置给指定频道
//mDynamicsProcessing.setMbcBandByChannelIndex(CHANNEL_1, bandIndex, mDynamicsProcessingMbc.getBand(bandIndex));
//销毁
mDynamicsProcessing.setEnabled(false);
mDynamicsProcessing.release();
mDynamicsProcessing = null;
@TypeConverters
用于数据类型转换,在不同地方作用域不同,主要处理非基本数据类型在数据库中的映射类型 参考该文章class Converters {
@TypeConverter
fun fromDate(date: Date): Long {
return date.time
}
@TypeConverter
fun toDate(timestamp: Long): Date {
return Date(timestamp)
}
@TypeConverter
fun fromList(list: List<String>?): String? {
return list?.joinToString(",")
}
@TypeConverter
fun toList(string: String?): List<String>? {
return string?.split(",")
}
}
@Entity(tableName = "user")
@TypeConverters(Converters::class)
data class User(
@PrimaryKey val id: Int,
val name: String,
val birthday: Date
@TypeConverters(HobbiesConverter::class) val hobbies: List<String>
)
@Database(entities = [User::class], version = 1)
@TypeConverters(Converters::class)
abstract class AppDatabase : RoomDatabase() {
// ...
}
@Dao
@TypeConverters(Converters::class)
interface UserDao {
@Query("SELECT * FROM user")
fun getAll(): List<User>
}
@Relation
用于声明两个实体间关系,这样在搜索时会根据设定的关系返回关联对象,用于多表间数据结构的嵌套返回@Entity(tableName = "users")
data class User(
@PrimaryKey val id: Int,
val name: String,
val email: String
)
@Entity(tableName = "books")
data class Book(
@PrimaryKey val id: Int,
val title: String,
val author: String,
val userId: Int
)
data class UserWithBooks(
@Embedded val user: User,
@Relation(
parentColumn = "id",
entityColumn = "userId"
)
val books: List<Book>
)
//---------------查询
@Query("SELECT * FROM users WHERE id = :id")
fun getUserWithBooks(id: Int): UserWithBooks
@Embedded
指定嵌入式对象,可以简化对象构成,构成对象可添加prefix属性对字段添加前缀@Entity(tableName = "users")
@Entity(tableName = "users")
data class User(
@PrimaryKey val id: Int,
val name: String,
@Embedded(prefix = "home_") val homeAddress: Address,
@Embedded(prefix = "work_") val workAddress: Address
)
data class Address(
val street: String,
val city: String,
val state: String,
val zip: String
)
目前官方api主要分三类camera,camera2,cameraX,用法和兼容性稍有不同
CameraApi 介绍与使用
Gradle资料
访问github时经常访问速度过慢而导致加载失败,为解决这一问题,可以先找到github.com所对应的IP,将域名与IP的映射添加到本地
C:\Windows\System32\drivers\etc\host
文件中,空格分割:
20.205.243.166 github.com
185.199.108.154 github.githubassets.com
185.199.110.154 github.githubassets.com
185.199.109.154 github.githubassets.com
185.199.111.154 github.githubassets.com
锁,OKhttp,list,Glide 源码分析