开发过程中,解决问题集锦~
happen
W/ContextImpl: Failed to ensure directory
不要使用 context.getExternalFilesDir( String type) Api ,顺源码查看,发现此API,存在多个挂载区但不可用时,会打印警告信息。使用 Environment.getExternalStorageDirectory() 则不会
I follow the getExternalFilesDir() source
/**
* Ensure that given directories exist, trying to create them if missing. If
* unable to create, they are filtered by replacing with {@code null}.
*/
private File[] ensureExternalDirsExistOrFilter(File[] dirs) {
File[] result = new File[dirs.length];
for (int i = 0; i < dirs.length; i++) {
File dir = dirs[i];
if (!dir.exists()) {
if (!dir.mkdirs()) {
// recheck existence in case of cross-process race
if (!dir.exists()) {
// Failing to mkdir() may be okay, since we might not have
// enough permissions; ask vold to create on our behalf.
final IMountService mount = IMountService.Stub.asInterface(
ServiceManager.getService("mount"));
try {
final int res = mount.mkdirs(getPackageName(), dir.getAbsolutePath());
if (res != 0) {
Log.w(TAG, "Failed to ensure " + dir + ": " + res);
dir = null;
}
} catch (Exception e) {
Log.w(TAG, "Failed to ensure " + dir + ": " + e);
dir = null;
}
}
}
}
result[i] = dir;
}
return result;
how to get ExternalFilesDir
public final class StorageUtil {
public static final String DIR_ANDROID = "Android";
private static final String DIR_DATA = "data";
private static final String DIR_FILES = "files";
private static final String DIR_CACHE = "cache";
@Nullable
public static synchronized File getExternalStorageAppFilesFile(Context context, String fileName) {
if (context == null) return null;
if (fileName == null) return null;
if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
File dirs = buildExternalStorageAppFilesDirs(Environment.getExternalStorageDirectory().getAbsolutePath(), context.getPackageName());
return new File(dirs, fileName);
}
return null;
}
public synchronized static File buildExternalStorageAppFilesDirs(String externalStoragePath, String packageName) {
return buildPath(externalStoragePath, DIR_ANDROID, DIR_DATA, packageName, DIR_FILES);
}
public synchronized static File buildPath(String base, String... segments) {
File cur = new File(base);
for (String segment : segments) {
cur = new File(cur, segment);
}
return cur;
}
Glide
- happen
Caused by: java.lang.IllegalArgumentException: You cannot start a load for a destroyed activity
加上
Glide.with(context).isPaused()
去调用Glide.with(context).pauseRequests();
即可
public static void resumeRequests(@NonNull final Context context) {
if (!isContextDestroyed(context) && isPaused(context)) {
Glide.with(context).resumeRequests();
}
}
public static void pauseRequests(@NonNull final Context context) {
if (!isContextDestroyed(context) && !isPaused(context)) {
Glide.with(context).pauseRequests();
}
}
public static boolean isPaused(@NonNull final Context context) {
return isContextDestroyed(context) || Glide.with(context).isPaused();
}
private static boolean isContextDestroyed(@NonNull final Context context) {
if (context instanceof Activity) {
Activity activity = (Activity) context;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1 && activity.isDestroyed()) {
return true;
}
}
return false;
}
在复杂的Fragment 交互中,popBackStack 偶尔抛出java.lang.IllegalStateException Fragment already added
popBackStackImmediate 则偶尔抛出java.lang.IllegalStateException Can not perform this action after onSaveInstanceState
。
跟踪它们源码发现,popBackStack 是Handler异步出栈,popBackStackImmediate 是马上出栈的。我推荐用
popBackStackImmediate,问题来了如何解决上面问题呢
package android.support.v4.app;
/**
* Created by lazy on 2017/8/23.
*/
public class VendingFragmentManager {
/**
* make sure no throws java.lang.IllegalStateException: Can not perform this action after onSaveInstanceState ,HA HA
*
* @param fragmentManager
*/
public static void allowStateLoss(FragmentManager fragmentManager) {
((FragmentManagerImpl) fragmentManager).noteStateNotSaved();
}
}
FragmentManager fragmentManager = getSupportFragmentManager();
VendingFragmentManager.allowStateLoss(fragmentManager);
fragmentManager.popBackStackImmediate();
addMainFragment();
FragmentManagerImpl 类是用默认访问修饰符修饰的,新建android.support.v4.app
包就可以投机取巧访问了。
File->Invalidate and Restart
* What went wrong:
A problem occurred evaluating project ':app'.
> java.lang.UnsupportedClassVersionError: com/android/build/gradle/AppPlugin : Unsupported major.minor version 52.0
在gradle.properties 使用jdk1.8 即可
org.gradle.java.home=/Applications/devtools/Android Studio.app/Contents/jre/jdk/Contents/Home
java.lang.NoSuchMethodError: No static method getFont(Landroid/content/Context;ILandroid/util/TypedValue;ILandroid/widget/TextView;)Landroid/graphics/Typeface; in class Landroid/support/v4/content/res/ResourcesCompat; or its super classes (declaration of 'android.support.v4.content.res.ResourcesCompat'
at android.support.v7.widget.TintTypedArray.getFont(TintTypedArray.java:119)
at android.support.v7.widget.AppCompatTextHelper.updateTypefaceAndStyle(AppCompatTextHelper.java:208)
at android.support.v7.widget.AppCompatTextHelper.loadFromAttributes(AppCompatTextHelper.java:110)
at android.support.v7.widget.AppCompatTextHelperV17.loadFromAttributes(AppCompatTextHelperV17.java:38)
at android.support.v7.widget.AppCompatTextView.(AppCompatTextView.java:81)
at android.support.v7.widget.AppCompatTextView.(AppCompatTextView.java:71)
at android.support.v7.app.AppCompatViewInflater.createView(AppCompatViewInflater.java:103)
at android.support.v7.app.AppCompatDelegateImplV9.createView(AppCompatDelegateImplV9.java:1024)
at android.support.v7.app.AppCompatDelegateImplV9.onCreateView(AppCompatDelegateImplV9.java:1081)
at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:729)
更新 appcompat 版本就OK