小知识点3

1.Android中fragment切换报错:Can not perform this action after onSaveInstanceState

参考网址:Android can not perform this action after onSaveInstanceState 问题解决_colorfulshark-CSDN博客

解决方法:commit()替换成commitAllowingStateLoss()

old

FragmentTransaction trx = getSupportFragmentManager().beginTransaction();
if (!fragments[0].isAdded()) {
    // 隐藏当前的fragment,add下一个到Activity中
    trx.remove(fragments[choose]).add(R.id.activity_main_new, fragments[0]).commit();
} else {
    // 隐藏当前的fragment,显示下一个
    trx.hide(fragments[choose]).show(fragments[0]).commit();
}

new

FragmentTransaction trx = getSupportFragmentManager().beginTransaction();
if (!fragments[0].isAdded()) {
    // 隐藏当前的fragment,add下一个到Activity中
    trx.remove(fragments[choose]).add(R.id.activity_main_new, fragments[0]).commitAllowingStateLoss();
} else {
    // 隐藏当前的fragment,显示下一个
    trx.hide(fragments[choose]).show(fragments[0]).commitAllowingStateLoss();
}

2.Android中多个Fragment和对应的onResume与onPause

参考网址:​​​​​​Android 再次探究Fragment在各种情况下的onResume与onPause_fan7983377的博客-CSDN博客_fragment onresume

说明:如果fragment的切换使用的是show/hide切换方式则需要使用以下方法
因为当show/hide切换时onResume和onPause只会调用一次,后边则会调用onHiddenChanged,通过记录当前Fragment是否显示的状态来模拟onResume和onPause,而当打开/关闭新的Activity时则会走onResume和onPause方法,通过isShowFragment可以判断当前是从哪个fragment中打开的新的Activity。

ManiActivity中:
public static boolean isShowFragment;
public static String nowFragment;//当前显示的哪个fragment

以下三个方法是在每个Fragment中重写的
@Override
public void onResume() {
    super.onResume();
    if (ManiActivity.isShowFragment){
        ManiActivity.nowFragment = "Fragment01";
    }
}
@Override
public void onHiddenChanged(boolean hidden) {
    super.onHiddenChanged(hidden);
    ManiActivity.isShowFragment = hidden;
    if (hidden) {// 不在最前端显示 相当于调用了onPause();
        ManiActivity.nowFragment = "";
    } else {// 在最前端显示 相当于调用了onResume();
        ManiActivity.nowFragment = "Fragment01";
    }
}
@Override
public void onPause() {
    super.onPause();
    if (ManiActivity.isShowFragment){
		ManiActivity.nowFragment = "";
    }
}

3.Android中android:appComponentFactory导致APP安装失败:'INSTALL_PARSE_FAILED_MANIFEST_MALFORME

参考网址:androidx遇到的坑INSTALL_PARSE_FAILED_MANIFEST_MALFORMED

错误信息:

Installation did not succeed.
The application could not be installed.
Installation failed due to: 'INSTALL_PARSE_FAILED_MANIFEST_MALFORMED'

解决方法:

在Manifest.xml里面的application加上下面的内容:

 tools:replace="android:appComponentFactory"
  android:appComponentFactory="任意字符" //任意字符,一定要有字符,不要是""

4.Android 中java.io.IOException: Cleartext traffic not permitted: http://192.168.1.2:8001

参考网址:【Android问题解决】java.io.IOException: Cleartext HTTP traffic to ....... not permitted完美解决_菜鸟的后花园-CSDN博客

错误说明:网址的请求不被允许

解决方法:

1.查看网络是否正常连接,网络权限是否添加

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

2.Android 9.0是默认禁止所有http请求的,需要在代码中设置如以下代码才可以正常进行网络请求

需在AndroidManifest.xml的Application中添加属性:android:usesCleartextTraffic="true"

3.如果是更高的版本,以上方法不能解决,就要通过网络配置文件解决

network_security_config.xml

<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
    <base-config cleartextTrafficPermitted="true"/>
</network-security-config>

需在AndroidManifest.xml的Application中添加属性:android:networkSecurityConfig="@xml/network_security_config"

5.Android中打开其他APP

参考网址:​​​​​​Android 在一个APP里打开另一个APP_晨曦-CSDN博客_从一个app打开另一个app

//打开指定APP,并可传参
public static void openAPP(Activity activity,String str){
	PackageManager packageManager = activity.getPackageManager();
	Intent intent = packageManager.getLaunchIntentForPackage("要打开的APP包名");
	intent.putExtra("data",str);
	activity.startActivity(intent);
}
//打开指定APP,并打开指定界面,并可传参
public static void openAPP2(Activity activity,String str){
	Intent intent = new Intent(Intent.ACTION_MAIN);
	ComponentName componentName = new ComponentName("要打开的APP包名","要打开的APP包名+指定的Activity");
	intent.setComponent(componentName);
	intent.putExtra("str",str);
	activity.startActivity(intent);
}

6.Android中TabLayout设置tab的时候默认居中,占不满屏幕问题解决

参考网址 :

android TabLayout设置tab的时候默认居中,占不满屏幕问题解决 - 爱码网

说明:TabLayout设置的标头默认是居中的,如果想要占满屏幕并平分需要使用以及代码

<android.support.design.widget.TabLayout
    app:tabMaxWidth="0dp"
    app:tabGravity="fill"
    app:tabMode="fixed"
    android:layout_width="match_parent"
    android:background="@color/mywhite"
    app:tabTextAppearance="@style/TabLayoutTextStyle"
    app:tabIndicatorColor="@android:color/holo_blue_light"
    app:tabTextColor="@android:color/darker_gray"
    app:tabSelectedTextColor="@android:color/black"
    android:layout_height="wrap_content" />

重点:

    app:tabMaxWidth="0dp"
    app:tabGravity="fill"
    app:tabMode="fixed"

7.Android中DecimalFormat("#.00")保留两位小数时丢失个位数0,例如0.98就成了.98

参考网址:https://blog.csdn.net/shareye1992/article/details/103119423

//正确写法:
DecimalFormat df = new DecimalFormat("#0.00");
String str = df.format(v);//0.52-->0.52
//含有bug写法:(只有个位并且是0的情况下)
DecimalFormat df2 = new DecimalFormat("#.00");
String str2 = df2.format(v);//0.52-->.52

说明:在整数部分没有值的时候,会把个位置为0,而不是处理成空串;这个原理类似小数位的使用"#.00"与"#.##"的区别,前者必然有2位小数,后者最多有2位小数,也可能没有

8.Android中网络请求HTTP改为HTTPS异常:javax.net.ssl.SSLHandshakeException: java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.

参考网址:

javax.net.ssl.SSLHandshakeException: java.security.cert.CertPathValidatorException:_MoonLoong的博客-CSDN博客

说明:因为Https的安全性,保证信息安全,对于我们程序员而言就是随之而来的适配问题。现在比较火的网络请求框架RxJava + Retrofit + OkHttp ,在我们进行网络请求时,需要区分链接是http还是https,便于进行https的校验。(小记目前为止自己写的post请求方法使用以下方案2是可以调通接口,利用xutils库调接口无法调通

异常说明:由于项目的https.bks证书不是正规的CA签发的证书,而是二级代理商等签发的证书,验证不通过造成的!!!

解决方案:

1.获取正规合法的https证书,让后台上传或者存在assets中,进行应用验证,这是最根本的解决办法!

2.忽略https的证书校验;具体做法:需要在获取sslParams时,修改并自定义TrustManager为trustAllCerts

//在继承的Application类里面onCreat()方法中调用该方法忽略https的证书校验
public static void handleSSLHandshake() {
    try {
        TrustManager[] trustAllCerts = new TrustManager[]{new X509TrustManager() {
            public X509Certificate[] getAcceptedIssuers() {
                return new X509Certificate[0];
            }
 
            @Override
            public void checkClientTrusted(X509Certificate[] certs, String authType) {
            }
 
            @Override
            public void checkServerTrusted(X509Certificate[] certs, String authType) {
            }
        }};
 
        SSLContext sc = SSLContext.getInstance("TLS");
        // trustAllCerts信任所有的证书
     sc.init(null, trustAllCerts, new SecureRandom());
        HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
        HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() {
            @Override
            public boolean verify(String hostname, SSLSession session) {
                return true;
            }
        });
    } catch (Exception ignored) {
    }
 }
 

异常:javax.net.ssl.SSLException: hostname in certificate didn't match

参考网址:Android:javax.net.ssl.SSLException: hostname in certificate didn't match_yeliang23的博客-CSDN博客

 原因: 网站使用https服务器,请求的时候遇到证书验证错误。
解决:添加 SSLSocketFactory.getSocketFactory().setHostnameVerifier(new AllowAllHostnameVerifier());

SSLSocketFactory.getSocketFactory().setHostnameVerifier(new AllowAllHostnameVerifier());
httpResponse = new DefaultHttpClient().execute(httpPost);

9.Android中webSocket使用wss

参考网址:安卓websocket支持wss - 爱码网

异常:Trust anchor for certification path not found.

说明:webSocket中的ws://改为wss://说明是有证书验证的,so

//忽略https的证书校验
    private void webSocketWSS(){
        try {
            SSLContext sslContext = SSLContext.getInstance("TLS");
            sslContext.init(null, new TrustManager[]{new X509TrustManager() {
                        @Override
                        public void checkClientTrusted(X509Certificate[] chain, String authType) {}
                        @Override
                        public void checkServerTrusted(X509Certificate[] chain, String authType) {}
                        @Override
                        public X509Certificate[] getAcceptedIssuers() {
                            return new X509Certificate[0];
                        }
                    }
            }, new SecureRandom());
            SSLSocketFactory factory = sslContext.getSocketFactory();
            webSocketClient.setSocket(factory.createSocket());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

此方法需要在WebSocketClient.connect();之前调用,webSocketClient初始化之后调用即可

10.Android中65535放法数超限问题解决方案(分包)

参考网址:Android 的65535放法数超限问题解决方案-AS方式、apk解析合并多dex、smali文件问题_林慈桥的博客-CSDN博客_安卓65535

1. 在build.gradle中配置支持多dex参数

android {
    ...
    defaultConfig {    
        ...
        multiDexEnabled true//解决方法数超65536限制问题
    }
}

2.再自己的Application里重写attachBaseContext(),加入MultiDex.install(context)即可


import androidx.multidex.MultiDex;
 
public class MyApplication extends Application {
 
    @Override
    protected void attachBaseContext(Context context) {
        MultiDex.install(context);
        super.attachBaseContext(context);
    }

3.然后将自己的MyApplication注册到AndroidManifest.xml中

OR

2.在build.gradle中配置

dependencies {
    ...
    implementation 'com.android.support:multidex:1.0.0'
}

11.Android中调用摄像头录视频点击取消,提示相机停止运行

参考网址:IllegalArgumentException:Unknown URL content 错误的原因_拥抱月光的博客-CSDN博客

 错误信息:IllegalArgumentException: Unknown URL file://xx/xx/x.mp4

 错误信息:exposed beyond app through ClipData.Item.getUri()

<provider
    android:name=".DatabaseProvider"
    android:authorities="com.example.databasetest.provider"
    android:exported="false"
    android:enabled="true"//加这句
    android:grantUriPermissions="true">
</provider>

如果下载我的资源

录音、录像等功能Demo-Android其他资源-CSDN下载

 可以配合上边AndroidManifest.xml的配置使用

说明:通过测试发现个别手机会有这种情况,调取手机系统自带视频录制,录制完成后部分手机会显示两个按钮:取消(X)和确认(√),当点击取消的时候会提示相机停止运行,虽然不会影响自己的APP运行,但体感不太好

补充方案:(仅用上边的未能成功解决问题)

参考网址:Android7.0下调用相机闪退的解决方案_峰沙同行的博客-CSDN博客

 说明:Android升级到7.0后对权限又做了一个更新即不允许出现以file://的形式调用隐式APP,需要用共享文件的形式:content:// URI

private void startVideo(){
	String filePath = FileUtil.getName(FileUtil.videoFilePath,".mp4");
	videoPath = filePath;
	File imageFile = new File(filePath);
	Uri uri = null;
	Intent intent = new Intent(MediaStore.ACTION_VIDEO_CAPTURE);
	intent.putExtra(MediaStore.EXTRA_VIDEO_QUALITY, 1);//1.高质量视频
	intent.putExtra(MediaStore.EXTRA_SIZE_LIMIT, 1);
	//指定最大视频录制时间(单位秒)
	intent.putExtra(MediaStore.EXTRA_DURATION_LIMIT, 10);
	intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
	intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
	intent.addCategory(Intent.CATEGORY_DEFAULT);
	intent.putExtra(MediaStore.EXTRA_FINISH_ON_COMPLETION, true);
	if (android.os.Build.VERSION.SDK_INT < 24) {
		uri = Uri.fromFile(imageFile);
	}else{//系统版本>=Android7.0使用
        //方式一
		ContentValues contentValues = new ContentValues(1);
		contentValues.put(MediaStore.Images.Media.DATA, imageFile.getAbsolutePath());
		uri = getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, contentValues);
		intent.putExtra(MediaStore.EXTRA_OUTPUT, uri);
        //方式二:第二个参数:"app的包名.fileProvider"
        uri=FileProvider.getUriForFile(this,
            BuildConfig.APPLICATION_ID.concat(".fileprovider"), imageFile);
	}
	// 自定义输出位置,这样可以将视频存在我们指定的位置
	intent.putExtra(MediaStore.EXTRA_OUTPUT, uri);
	startActivityForResult(intent, 1);
}

调用系统相机拍照如果有这种情况写法一样,根据系统版本选取不同的uri获取方式

12.Android中自定义View中初始化子控件

 说明:当一个Activity中需要使用大量控件时,可通过自定义View减少Activity中的代码量,将自定义View作为父级控件,向其中添加所需布局控件;并将子级控件的初始化代码放入自定义View中来实现,但需要注意的是需要等父级自定义View初始化完成后才可以初始化子级控件;所以需要用到以下方法(重写onFinishInflate

public MainView(Context context) {
	super(context);
	this.context = context;
}
public MainView(Context context, @Nullable AttributeSet attrs) {
	super(context, attrs);
	this.context = context;
}

public MainView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
	super(context, attrs, defStyleAttr);
	this.context = context;
}

@SuppressLint("NewApi")
public MainView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
	super(context, attrs, defStyleAttr, defStyleRes);
	this.context = context;
}
//在所有子视图都被添加之后,此时可以通过findView获取该控件下的子控件
@Override
protected void onFinishInflate() {
	super.onFinishInflate();
	if(isInEditMode()) {
		return;
	}
	init();//自定义view下的控件初始化放在这个方法中
}

13.Android中代码设置TextView添加图片

 xml设置TextView添加图片

<TextView
	android:id="@+id/tv_new_main_weather"
	android:layout_width="wrap_content"
	android:layout_height="wrap_content"
	android:drawableLeft="@mipmap/weather"左侧添加图片
	android:drawablePadding="5dp"
	android:textColor="@color/white"
	android:textSize="15dp"
	android:text="晴转阴 20℃~26℃"/>

代码添加图片

TextView weather = findViewByid(R.id.weather);
Drawable drawable = getResources().getDrawable(R.drawable.weather);
BitmapDrawable bitmapDrawable = (BitmapDrawable) drawable;
//获取图片的宽高适应图片,指定宽高影响图片展示
int width = bitmapDrawable.getBitmap().getWidth();
int height = bitmapDrawable.getBitmap().getHeight();
drawable.setBounds(0,0,width,height);//没有这个不显示图片
weather.setCompoundDrawables(drawable,null,null,null);

14.解决fragment中onActivityResult失效的问题

 方法一:(耦合性低)

//在Activity的onActivityResult中添加以下代码,在fragment中重写onActivityResult
//就可以监听到
//遍历Activity中所有fragment,并调用onActivityResult方法
for (Fragment fragment : getSupportFragmentManager().getFragments()) {
	fragment.onActivityResult(requestCode, resultCode, data);
}

方法二:(耦合性中)
在Activity中添加监听事件,在fragment中通过监听Activity的onActivityResult进行操作
方法三:(耦合性高)
在Activity中通过fragment.方法(需要进行的操作放到fragment创建的方法并公有化)
 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值