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.
参考网址:
说明:因为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
异常: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创建的方法并公有化)