From 6e378001482d3f57cd62c60b5e99dc11c1593f82 Mon Sep 17 00:00:00 2001 From: TongTongStudio Date: Mon, 27 Jul 2026 08:10:58 +0800 Subject: [PATCH] =?UTF-8?q?refactor:=20=E4=BC=98=E5=8C=96=E7=9B=B8?= =?UTF-8?q?=E6=9C=BA=E5=B7=A5=E5=85=B7=E5=8F=8A=E8=BF=81=E7=A7=BBFileUtils?= =?UTF-8?q?=E8=87=B3iconloader=E6=A8=A1=E5=9D=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../settings/utils/SettingsUtilsActivity.java | 22 +- .../ttstd/dialer/network/OkHttpManager.java | 2 +- .../com/ttstd/dialer/push/PushExecutor.java | 3 +- .../ttstd/dialer/utils/AvatarCacheUtil.java | 4 +- .../com/ttstd/dialer/utils/CameraUtil.java | 207 +++++++++++------- .../com/ttstd/dialer/utils/FileUtils.java | 24 -- .../ttstd/iconloader/IconCacheManager.java | 3 +- .../com/ttstd/iconloader/utils/FileUtils.java | 23 ++ 8 files changed, 163 insertions(+), 125 deletions(-) delete mode 100644 app/src/main/java/com/ttstd/dialer/utils/FileUtils.java create mode 100644 iconloader/src/main/java/com/ttstd/iconloader/utils/FileUtils.java diff --git a/app/src/main/java/com/ttstd/dialer/activity/settings/utils/SettingsUtilsActivity.java b/app/src/main/java/com/ttstd/dialer/activity/settings/utils/SettingsUtilsActivity.java index bf59937..d632e12 100644 --- a/app/src/main/java/com/ttstd/dialer/activity/settings/utils/SettingsUtilsActivity.java +++ b/app/src/main/java/com/ttstd/dialer/activity/settings/utils/SettingsUtilsActivity.java @@ -15,6 +15,7 @@ import com.ttstd.dialer.databinding.ActivitySettingsUtilsBinding; import com.ttstd.dialer.mdm.DeviceManagerService; import com.ttstd.dialer.service.main.MainService; import com.ttstd.dialer.utils.CameraUtil; +import com.ttstd.iconloader.utils.FileUtils; import com.ttstd.dialer.utils.Logger; import com.ttstd.dialer.utils.SystemUtils; @@ -147,7 +148,7 @@ public class SettingsUtilsActivity extends BaseMvvmActivity() { @Override public void onNext(@NonNull Integer integer) { @@ -186,27 +187,10 @@ public class SettingsUtilsActivity extends BaseMvvmActivity params = new HashMap<>(); params.put("sn", DeviceManagerService.getInstance().getSerial()); params.put("createtime", String.valueOf(createTime)); -// Call call = NetInterfaceManager.getInstance().getScreenshotCall().sendScreenshot(params, body); -// call.enqueue(new RetryCallback(call, 10, 30 * 1000) { -// @Override -// public void onRequestResponse(Call call, Response response) { -// Logger.e(TAG, "onRequestResponse: " + response.body().toString()); -// } -// -// @Override -// public void onRequestFail(Call call, Throwable t) { -// Logger.e(TAG, "onRequestFail: "); -// } -// -// @Override -// public void onStartRetry() { -// Logger.e(TAG, "onStartRetry: "); -// } -// }); } }); - cameraUtil.startTakePicture(getExternalCacheDir().getAbsolutePath() + "cameracapture_" + File.separator + createTime + ".jpg"); + cameraUtil.startTakePicture(FileUtils.getCacheDir(SettingsUtilsActivity.this) + File.separator + "cameracapture_" + File.separator + createTime + ".jpg"); } } diff --git a/app/src/main/java/com/ttstd/dialer/network/OkHttpManager.java b/app/src/main/java/com/ttstd/dialer/network/OkHttpManager.java index c044493..6da1e8f 100644 --- a/app/src/main/java/com/ttstd/dialer/network/OkHttpManager.java +++ b/app/src/main/java/com/ttstd/dialer/network/OkHttpManager.java @@ -18,7 +18,7 @@ import com.ttstd.dialer.mdm.DeviceManagerService; import com.ttstd.dialer.network.api.ContactApi; import com.ttstd.dialer.network.api.SnApi; import com.ttstd.dialer.network.interceptor.AuthInterceptor; -import com.ttstd.dialer.utils.FileUtils; +import com.ttstd.iconloader.utils.FileUtils; import com.ttstd.dialer.utils.Logger; import org.jetbrains.annotations.NotNull; diff --git a/app/src/main/java/com/ttstd/dialer/push/PushExecutor.java b/app/src/main/java/com/ttstd/dialer/push/PushExecutor.java index 0b2490f..3af55b3 100644 --- a/app/src/main/java/com/ttstd/dialer/push/PushExecutor.java +++ b/app/src/main/java/com/ttstd/dialer/push/PushExecutor.java @@ -20,6 +20,7 @@ import com.ttstd.dialer.mdm.DeviceManagerService; import com.ttstd.dialer.network.BaseObserver; import com.ttstd.dialer.network.OkHttpManager; import com.ttstd.dialer.utils.CmdUtil; +import com.ttstd.iconloader.utils.FileUtils; import com.ttstd.dialer.utils.Logger; import com.ttstd.dialer.utils.RebootUtils; @@ -238,7 +239,7 @@ public class PushExecutor { } private void screenSnapshot() { - String filepath = mContext.getExternalCacheDir().getAbsolutePath() + File.separator + "screenshot_" + System.currentTimeMillis() + ".png"; + String filepath = FileUtils.getCacheDir(mContext) + File.separator + "screenshot_" + System.currentTimeMillis() + ".png"; Observable.fromCallable(new Callable() { @Override diff --git a/app/src/main/java/com/ttstd/dialer/utils/AvatarCacheUtil.java b/app/src/main/java/com/ttstd/dialer/utils/AvatarCacheUtil.java index 74e355f..324fa1d 100644 --- a/app/src/main/java/com/ttstd/dialer/utils/AvatarCacheUtil.java +++ b/app/src/main/java/com/ttstd/dialer/utils/AvatarCacheUtil.java @@ -9,6 +9,8 @@ import android.graphics.Paint; import android.graphics.Rect; import android.util.LruCache; +import com.ttstd.iconloader.utils.FileUtils; + import java.io.File; import java.io.FileOutputStream; import java.io.IOException; @@ -113,7 +115,7 @@ public class AvatarCacheUtil { // ========== 本地磁盘缓存操作 ========== private static File getCacheDir(Context context) { - File cacheDir = new File(context.getExternalCacheDir(), CACHE_DIR_NAME); + File cacheDir = new File(FileUtils.getCacheDir(context), CACHE_DIR_NAME); if (!cacheDir.exists()) { cacheDir.mkdirs(); } diff --git a/app/src/main/java/com/ttstd/dialer/utils/CameraUtil.java b/app/src/main/java/com/ttstd/dialer/utils/CameraUtil.java index a6824c9..b4aac89 100644 --- a/app/src/main/java/com/ttstd/dialer/utils/CameraUtil.java +++ b/app/src/main/java/com/ttstd/dialer/utils/CameraUtil.java @@ -17,11 +17,15 @@ import android.hardware.camera2.params.StreamConfigurationMap; import android.media.Image; import android.media.ImageReader; import android.media.MediaRecorder; +import android.os.Build; import android.os.Handler; +import android.os.HandlerThread; import android.os.Looper; import android.os.Message; import android.util.DisplayMetrics; import android.util.Size; +import android.view.Display; +import android.view.WindowManager; import androidx.annotation.NonNull; import androidx.core.app.ActivityCompat; @@ -38,19 +42,14 @@ import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.stream.Collectors; -/** - * @作者 Liushihua - * @创建时间 2021-2-3 10:54 - * @描述 - */ public class CameraUtil { private static final String TAG = "CameraUtil"; private Context context; private CameraCallBack cameraCallBack; private CameraManager cameraManager; - // 默认相机id是0 LENS_FACING_FRONT,LENS_FACING_BACK - private int cameraId = CameraCharacteristics.LENS_FACING_FRONT; + // 默认相机id + private String mCameraId; private CameraDevice mCameraDevice; private String savePath; @@ -58,7 +57,10 @@ public class CameraUtil { private CameraCaptureSession mCameraCaptureSession; private CaptureRequest request; private ExecutorService service; + private HandlerThread mBackgroundThread; + private Handler mBackgroundHandler; private boolean isTakedPicture = false;//是否已经拍照 + private volatile boolean mIsCapturing = false; // 是否正在捕获图片数据 private int needSetOrientation = 0;// 设置默认的拍照方向 private boolean isInitOk = false;// 是否初始化成功 @@ -132,12 +134,9 @@ public class CameraUtil { @Override public void onDisconnected(@NonNull CameraDevice cameraDevice) { Logger.e(TAG, "onDisconnected"); - cameraDevice.close(); mCameraDevice = null; - Message message = new Message(); - message.what = HANDLER_ERR; - message.obj = "后台相机断开连接"; - handler.sendMessage(message); + sendErrorMessage("后台相机断开连接"); + onStop(); } /** @@ -150,12 +149,9 @@ public class CameraUtil { @Override public void onError(@NonNull CameraDevice cameraDevice, int error) { Logger.e(TAG, "onError 相机设备异常,请重启!"); - cameraDevice.close(); mCameraDevice = null; - Message messagef = new Message(); - messagef.what = HANDLER_ERR; - messagef.obj = "相机设备异常,请重启!"; - handler.sendMessage(messagef); + sendErrorMessage("相机设备异常,请重启!"); + onStop(); } /** @@ -198,75 +194,117 @@ public class CameraUtil { this.context = activity; this.cameraCallBack = cameraCallBack; cameraManager = (CameraManager) activity.getSystemService(Context.CAMERA_SERVICE); + startBackgroundThread(); // 对于静态图片,使用可用的最大值来拍摄。 if (cameraManager != null) { isInitOk = true; - cameraManager.registerAvailabilityCallback(callback, null); + cameraManager.registerAvailabilityCallback(callback, mBackgroundHandler); + findFrontCamera(); getCameraInfo(); setupImageReader(); service = Executors.newSingleThreadExecutor(); } } + private void startBackgroundThread() { + mBackgroundThread = new HandlerThread("CameraBackground"); + mBackgroundThread.start(); + mBackgroundHandler = new Handler(mBackgroundThread.getLooper()); + } + + private void stopBackgroundThread() { + if (mBackgroundThread != null) { + mBackgroundThread.quitSafely(); + try { + mBackgroundThread.join(); + mBackgroundThread = null; + mBackgroundHandler = null; + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + } + + private void findFrontCamera() { + try { + for (String id : cameraManager.getCameraIdList()) { + CameraCharacteristics characteristics = cameraManager.getCameraCharacteristics(id); + Integer facing = characteristics.get(CameraCharacteristics.LENS_FACING); + if (facing != null && facing == CameraCharacteristics.LENS_FACING_FRONT) { + mCameraId = id; + return; + } + } + // 如果没找到前置,就用第一个 + String[] ids = cameraManager.getCameraIdList(); + if (ids.length > 0) { + mCameraId = ids[0]; + } + } catch (CameraAccessException e) { + e.printStackTrace(); + } + } + private void setupImageReader() { -// Size size = getOutputSize(imgOutputSizes); - //前三个参数分别是需要的尺寸和格式,最后一个参数代表每次最多获取几帧数据,本例的3代表ImageReader中最多可以获取2帧图像流 - imageReader = ImageReader.newInstance(1600, 1200, ImageFormat.JPEG, 1); - //监听ImageReader的事件,当有图像流数据可用时会回调onImageAvailable方法,它的参数就是预览帧数据,可以对这帧数据进行处理 + if (imageReader != null) { + imageReader.close(); + } + Size size = getOutputSize(imgOutputSizes); + //前三个参数分别是需要的尺寸和格式,最后一个参数代表每次最多获取几帧数据,本例的1代表ImageReader中最多可以获取1帧图像流 + imageReader = ImageReader.newInstance(size.getWidth(), size.getHeight(), ImageFormat.JPEG, 1); + //监听ImageReader的事件,当有图像流数据可用时会回调onImageAvailable方法 imageReader.setOnImageAvailableListener(new ImageReader.OnImageAvailableListener() { @Override public void onImageAvailable(ImageReader reader) { + if (!mIsCapturing) { + // 如果不在捕获状态,直接丢弃帧数据,避免预览流占满内存 + Image image = reader.acquireLatestImage(); + if (image != null) image.close(); + return; + } + mIsCapturing = false; // 标记捕获完成 Image image = reader.acquireLatestImage(); - //我们可以将这帧数据转成字节数组,类似于Camera1的PreviewCallback回调的预览帧数据 + if (image == null) return; ByteBuffer buffer = image.getPlanes()[0].getBuffer(); byte[] data = new byte[buffer.remaining()]; buffer.get(data); image.close(); saveFile(data, savePath); } - }, null); + }, mBackgroundHandler); } /** * 打开相机 */ private void openCamera() { - cameraId = getFrontCameraId(); - Logger.e(TAG, "openCamera: getFrontCameraId = " + getFrontCameraId()); - Logger.e(TAG, "openCamera:" + cameraId); + if (mCameraId == null) { + findFrontCamera(); + } + Logger.e(TAG, "openCamera: cameraId = " + mCameraId); isCameraDoing = true; - // 设置TextureView的缓冲区大小 - // 获取Surface显示预览数据 if (ActivityCompat.checkSelfPermission(context, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) { - Message message = new Message(); - message.what = HANDLER_ERR; - message.obj = "权限不足"; - handler.sendMessage(message); + sendErrorMessage("权限不足"); return; } try { - cameraManager.openCamera(Integer.toString(cameraId), stateCallback, null); - Logger.e(TAG, "打开相机成功!"); + if (imageReader == null) { + setupImageReader(); + } + cameraManager.openCamera(mCameraId, stateCallback, mBackgroundHandler); + Logger.e(TAG, "正在打开相机..."); } catch (Exception e) { Logger.e(TAG, "打开相机失败-Exception:" + e.getMessage()); e.printStackTrace(); - Message messagef = new Message(); - messagef.what = HANDLER_ERR; - messagef.obj = "打开相机失败"; - handler.sendMessage(messagef); + sendErrorMessage("打开相机失败"); } } - private int getFrontCameraId() { - int numberOfCameras = Camera.getNumberOfCameras(); - for (int i = 0; i < numberOfCameras; i++) { - Camera.CameraInfo cameraInfo = new Camera.CameraInfo(); - Camera.getCameraInfo(i, cameraInfo); - if (cameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) { - return i; - } - } - return 0; + private void sendErrorMessage(String msg) { + Message message = new Message(); + message.what = HANDLER_ERR; + message.obj = msg; + handler.sendMessage(message); } /** @@ -274,21 +312,16 @@ public class CameraUtil { */ private void startPreview() { Logger.e(TAG, "startPreview"); - // CaptureRequest添加imageReaderSurface,不加的话就会导致ImageReader的onImageAvailable()方法不会回调 - // 创建CaptureSession时加上imageReaderSurface,如下,这样预览数据就会同时输出到previewSurface和imageReaderSurface了 + if (mCameraDevice == null || imageReader == null) return; try { - // 创建CaptureRequestBuilder,TEMPLATE_PREVIEW比表示预览请求 - mPreviewRequestBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_RECORD); - mPreviewRequestBuilder.addTarget(imageReader.getSurface());// 设置Surface作为预览数据的显示界面 - // 创建相机捕获会话,第一个参数是捕获数据的输出Surface列表,第二个参数是CameraCaptureSession的状态回调接口,当它创建好后会回调onConfigured方法,第三个参数用来确定Callback在哪个线程执行,为null的话就在当前线程执行 - mCameraDevice.createCaptureSession(Arrays.asList(imageReader.getSurface()), captureSessionStateCallBack, null); + // 创建CaptureRequestBuilder,TEMPLATE_PREVIEW表示预览请求 + mPreviewRequestBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW); + mPreviewRequestBuilder.addTarget(imageReader.getSurface()); + mCameraDevice.createCaptureSession(Arrays.asList(imageReader.getSurface()), captureSessionStateCallBack, mBackgroundHandler); } catch (CameraAccessException e) { e.printStackTrace(); - Message messagef = new Message(); - messagef.what = HANDLER_ERR; - messagef.obj = "捕获帧失败"; - handler.sendMessage(messagef); - Logger.e(TAG, "Camera获取成功,创建录制请求或捕获Session失败" + e.getMessage()); + sendErrorMessage("捕获帧失败"); + Logger.e(TAG, "创建预览Session失败: " + e.getMessage()); } } @@ -320,6 +353,7 @@ public class CameraUtil { @Override public void onConfigureFailed(CameraCaptureSession session) { Logger.e(TAG, "onConfigureFailed"); + sendErrorMessage("开启预览失败"); } }; @@ -341,27 +375,26 @@ public class CameraUtil { private void takePicture() { Logger.e(TAG, "takePicture"); try { - if (mCameraDevice == null || mPreviewRequestBuilder == null) return; - mPreviewRequestBuilder.addTarget(imageReader.getSurface()); + if (mCameraDevice == null || mCameraCaptureSession == null) return; + CaptureRequest.Builder captureBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE); + captureBuilder.addTarget(imageReader.getSurface()); //设置拍照方向 - mPreviewRequestBuilder.set(CaptureRequest.JPEG_ORIENTATION, this.needSetOrientation); - //这个回调接口用于拍照结束时重启预览,因为拍照会导致预览停止 - CameraCaptureSession.CaptureCallback mImageSavedCallback = new CameraCaptureSession.CaptureCallback() { + captureBuilder.set(CaptureRequest.JPEG_ORIENTATION, this.needSetOrientation); + // 自动对焦和自动曝光模式 + captureBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE); + captureBuilder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH); + + mIsCapturing = true; // 准备接收ImageReader的数据 + mCameraCaptureSession.capture(captureBuilder.build(), new CameraCaptureSession.CaptureCallback() { @Override - public void onCaptureCompleted(CameraCaptureSession session, CaptureRequest request, TotalCaptureResult result) { - Logger.e(TAG, "拍照完成"); - onStop(); + public void onCaptureCompleted(@NonNull CameraCaptureSession session, @NonNull CaptureRequest request, @NonNull TotalCaptureResult result) { + Logger.e(TAG, "拍照指令完成"); } - }; - //开始拍照,然后回调上面的接口重启预览,因为mCaptureBuilder设置ImageReader作为target,所以会自动回调ImageReader的onImageAvailable()方法保存图片 - mCameraCaptureSession.capture(mPreviewRequestBuilder.build(), mImageSavedCallback, null); + }, mBackgroundHandler); } catch (CameraAccessException e) { Logger.e(TAG, "takePhoto CameraAccessException:" + e.getMessage()); e.printStackTrace(); - Message messagef = new Message(); - messagef.what = HANDLER_ERR; - messagef.obj = "拍照失败"; - handler.sendMessage(messagef); + sendErrorMessage("拍照失败"); } } @@ -409,8 +442,10 @@ public class CameraUtil { */ public void onDestroy() { this.cameraCallBack = null; + stopBackgroundThread(); if (cameraManager != null) cameraManager.unregisterAvailabilityCallback(callback); + this.context = null; } /** @@ -463,8 +498,9 @@ public class CameraUtil { if (enableCameraList == null) { getCameras(); } + if (mCameraId == null) findFrontCamera(); try { - CameraCharacteristics mCameraCharacteristics = cameraManager.getCameraCharacteristics(String.valueOf(cameraId)); + CameraCharacteristics mCameraCharacteristics = cameraManager.getCameraCharacteristics(mCameraId); // 设置是否支持闪光灯 Boolean available = mCameraCharacteristics.get(CameraCharacteristics.FLASH_INFO_AVAILABLE); mFlashSupported = available == null ? false : available; @@ -474,7 +510,20 @@ public class CameraUtil { return; } int mSensorOrientation = mCameraCharacteristics.get(CameraCharacteristics.SENSOR_ORIENTATION);//这个方法来获取CameraSensor的方向。 - Logger.e(TAG, "camera sensor orientation:" + mSensorOrientation + ",display rotation=" + context.getDisplay().getRotation()); + + int rotation; + WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { + try { + rotation = context.getDisplay().getRotation(); + } catch (Exception e) { + rotation = wm != null ? wm.getDefaultDisplay().getRotation() : 0; + } + } else { + rotation = wm != null ? wm.getDefaultDisplay().getRotation() : 0; + } + + Logger.e(TAG, "camera sensor orientation:" + mSensorOrientation + ",display rotation=" + rotation); int[] formats = map.getOutputFormats();//获得手机支持的输出格式,其中jpeg是一定会支持的,yuv_420_888是api21才开始支持的 for (int format : formats) { @@ -553,6 +602,8 @@ public class CameraUtil { message.what = HANDLER_TAKE_PHOTO_SUCCESS; message.obj = savePath; handler.sendMessage(message); + // 保存成功后关闭相机,解决竞态问题 + handler.post(() -> onStop()); } catch (IOException e) { e.printStackTrace(); Logger.e(TAG, "图片保存-IOException:" + e.getMessage()); diff --git a/app/src/main/java/com/ttstd/dialer/utils/FileUtils.java b/app/src/main/java/com/ttstd/dialer/utils/FileUtils.java deleted file mode 100644 index ce475ac..0000000 --- a/app/src/main/java/com/ttstd/dialer/utils/FileUtils.java +++ /dev/null @@ -1,24 +0,0 @@ -package com.ttstd.dialer.utils; - -import android.content.Context; -import android.os.Environment; - -public class FileUtils { - public static String getCacheDir(Context context) { - String cachePath; - if (Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState()) - || !Environment.isExternalStorageRemovable()) { - if (context.getExternalCacheDir() != null) { - cachePath = context.getExternalCacheDir().getPath(); - } else if (context.getExternalFilesDir("cache") != null) { - cachePath = context.getExternalFilesDir("cache").getPath(); - } else { - cachePath = context.getCacheDir().getPath(); - } - } else { - cachePath = context.getCacheDir().getPath(); - } - return cachePath; - } - -} diff --git a/iconloader/src/main/java/com/ttstd/iconloader/IconCacheManager.java b/iconloader/src/main/java/com/ttstd/iconloader/IconCacheManager.java index e56b973..653b83c 100644 --- a/iconloader/src/main/java/com/ttstd/iconloader/IconCacheManager.java +++ b/iconloader/src/main/java/com/ttstd/iconloader/IconCacheManager.java @@ -17,6 +17,7 @@ import android.util.Log; import androidx.collection.LruCache; import com.jakewharton.disklrucache.DiskLruCache; +import com.ttstd.iconloader.utils.FileUtils; import java.io.File; import java.io.IOException; @@ -63,7 +64,7 @@ public class IconCacheManager { }; // 磁盘缓存(50MB) - File cacheDir = new File(context.getExternalCacheDir(), "icon_cache"); + File cacheDir = new File(FileUtils.getCacheDir(context), "icon_cache"); try { mDiskCache = DiskLruCache.open(cacheDir, 1, 1, 50 * 1024 * 1024); } catch (Exception e) { diff --git a/iconloader/src/main/java/com/ttstd/iconloader/utils/FileUtils.java b/iconloader/src/main/java/com/ttstd/iconloader/utils/FileUtils.java new file mode 100644 index 0000000..dbb3ffc --- /dev/null +++ b/iconloader/src/main/java/com/ttstd/iconloader/utils/FileUtils.java @@ -0,0 +1,23 @@ +package com.ttstd.iconloader.utils; + +import android.content.Context; +import android.os.Environment; +import java.io.File; + +public class FileUtils { + /** + * 获取缓存目录 + * 优先返回外部缓存目录,如果不可用则返回内部缓存目录 + */ + public static String getCacheDir(Context context) { + File cacheDir = null; + if (Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState()) + || !Environment.isExternalStorageRemovable()) { + cacheDir = context.getExternalCacheDir(); + } + if (cacheDir == null) { + cacheDir = context.getCacheDir(); + } + return cacheDir.getPath(); + } +}