Android Fresco 框架工具与测试模块源码深度剖析(五)

news/2025/3/19 9:41:10/

一、引言

在 Android 开发中,Fresco 是一个强大的图片加载和显示框架,由 Facebook 开源。它不仅提供了高效的图片加载和缓存机制,还配备了丰富的工具与测试模块,这些模块对于开发者在调试、优化以及确保框架的正确性方面起着至关重要的作用。本文将深入剖析 Fresco 框架的工具与测试模块,从源码级别进行详细分析,帮助开发者更好地理解和运用这些功能。

二、工具模块概述

Fresco 的工具模块主要包含了一系列用于辅助开发、调试和性能分析的工具类和接口。这些工具可以帮助开发者更好地理解框架的运行机制,优化图片加载性能,以及快速定位和解决问题。

2.1 主要工具类和接口

2.1.1 ImagePerfMonitor

ImagePerfMonitor 是一个用于监控图片加载性能的工具类。它可以记录图片加载过程中的各个阶段的时间,如网络请求时间、解码时间等,并提供相应的回调接口,让开发者可以根据这些信息进行性能分析和优化。

java

// ImagePerfMonitor 接口定义
public interface ImagePerfMonitor {// 记录图片加载开始事件void onImageLoadStart(ImageRequest imageRequest);// 记录图片网络请求开始事件void onNetworkFetchStart(ImageRequest imageRequest);// 记录图片网络请求完成事件void onNetworkFetchFinish(ImageRequest imageRequest, long fetchTimeMs);// 记录图片解码开始事件void onDecodeStart(ImageRequest imageRequest);// 记录图片解码完成事件void onDecodeFinish(ImageRequest imageRequest, long decodeTimeMs);// 记录图片加载完成事件void onImageLoadFinish(ImageRequest imageRequest, long totalTimeMs);// 记录图片加载失败事件void onImageLoadFailure(ImageRequest imageRequest, Throwable throwable);
}
2.1.2 ImagePerfData

ImagePerfData 是一个用于存储图片加载性能数据的类。它包含了图片加载过程中的各个阶段的时间信息,以及图片的相关信息,如 URL、尺寸等。

java

// ImagePerfData 类定义
public class ImagePerfData {private final ImageRequest imageRequest;private long loadStartTimeMs;private long networkFetchStartTimeMs;private long networkFetchFinishTimeMs;private long decodeStartTimeMs;private long decodeFinishTimeMs;private long loadFinishTimeMs;private Throwable loadFailureThrowable;public ImagePerfData(ImageRequest imageRequest) {this.imageRequest = imageRequest;}// 获取图片请求public ImageRequest getImageRequest() {return imageRequest;}// 设置图片加载开始时间public void setLoadStartTimeMs(long loadStartTimeMs) {this.loadStartTimeMs = loadStartTimeMs;}// 获取图片加载开始时间public long getLoadStartTimeMs() {return loadStartTimeMs;}// 设置网络请求开始时间public void setNetworkFetchStartTimeMs(long networkFetchStartTimeMs) {this.networkFetchStartTimeMs = networkFetchStartTimeMs;}// 获取网络请求开始时间public long getNetworkFetchStartTimeMs() {return networkFetchStartTimeMs;}// 设置网络请求完成时间public void setNetworkFetchFinishTimeMs(long networkFetchFinishTimeMs) {this.networkFetchFinishTimeMs = networkFetchFinishTimeMs;}// 获取网络请求完成时间public long getNetworkFetchFinishTimeMs() {return networkFetchFinishTimeMs;}// 设置解码开始时间public void setDecodeStartTimeMs(long decodeStartTimeMs) {this.decodeStartTimeMs = decodeStartTimeMs;}// 获取解码开始时间public long getDecodeStartTimeMs() {return decodeStartTimeMs;}// 设置解码完成时间public void setDecodeFinishTimeMs(long decodeFinishTimeMs) {this.decodeFinishTimeMs = decodeFinishTimeMs;}// 获取解码完成时间public long getDecodeFinishTimeMs() {return decodeFinishTimeMs;}// 设置图片加载完成时间public void setLoadFinishTimeMs(long loadFinishTimeMs) {this.loadFinishTimeMs = loadFinishTimeMs;}// 获取图片加载完成时间public long getLoadFinishTimeMs() {return loadFinishTimeMs;}// 设置图片加载失败的异常信息public void setLoadFailureThrowable(Throwable loadFailureThrowable) {this.loadFailureThrowable = loadFailureThrowable;}// 获取图片加载失败的异常信息public Throwable getLoadFailureThrowable() {return loadFailureThrowable;}// 计算网络请求时间public long getNetworkFetchTimeMs() {return networkFetchFinishTimeMs - networkFetchStartTimeMs;}// 计算解码时间public long getDecodeTimeMs() {return decodeFinishTimeMs - decodeStartTimeMs;}// 计算图片加载总时间public long getTotalLoadTimeMs() {return loadFinishTimeMs - loadStartTimeMs;}
}
2.1.3 ImagePerfDataListener

ImagePerfDataListener 是一个回调接口,用于监听图片加载性能数据的变化。当图片加载过程中的某个阶段完成时,会触发相应的回调方法,开发者可以在这些方法中获取性能数据并进行处理。

java

// ImagePerfDataListener 接口定义
public interface ImagePerfDataListener {// 当图片加载性能数据更新时调用void onImagePerfDataUpdated(ImagePerfData imagePerfData);
}

2.2 工具模块的使用场景

  • 性能分析:通过 ImagePerfMonitor 记录图片加载过程中的各个阶段的时间,开发者可以分析出哪些环节是性能瓶颈,从而进行针对性的优化。
  • 问题定位:当图片加载出现问题时,通过查看 ImagePerfData 中的信息,开发者可以快速定位问题所在,如网络请求失败、解码错误等。
  • 调试和监控:在开发和测试阶段,开发者可以使用 ImagePerfDataListener 实时监控图片加载性能,确保框架的稳定性和性能。

三、工具模块源码分析

3.1 ImagePerfMonitor 的实现

ImagePerfMonitor 有多个实现类,其中一个常见的实现类是 DefaultImagePerfMonitor。下面是 DefaultImagePerfMonitor 的源码分析:

java

// 默认的图片性能监控器实现类
public class DefaultImagePerfMonitor implements ImagePerfMonitor {private final ImagePerfDataListener imagePerfDataListener;private final Map<ImageRequest, ImagePerfData> imagePerfDataMap = new HashMap<>();public DefaultImagePerfMonitor(ImagePerfDataListener imagePerfDataListener) {this.imagePerfDataListener = imagePerfDataListener;}@Overridepublic void onImageLoadStart(ImageRequest imageRequest) {// 创建一个新的 ImagePerfData 对象来存储图片加载性能数据ImagePerfData imagePerfData = new ImagePerfData(imageRequest);// 记录图片加载开始时间imagePerfData.setLoadStartTimeMs(System.currentTimeMillis());// 将 ImagePerfData 对象存入 map 中imagePerfDataMap.put(imageRequest, imagePerfData);// 通知监听器图片加载性能数据更新notifyImagePerfDataUpdated(imagePerfData);}@Overridepublic void onNetworkFetchStart(ImageRequest imageRequest) {// 从 map 中获取对应的 ImagePerfData 对象ImagePerfData imagePerfData = imagePerfDataMap.get(imageRequest);if (imagePerfData != null) {// 记录网络请求开始时间imagePerfData.setNetworkFetchStartTimeMs(System.currentTimeMillis());// 通知监听器图片加载性能数据更新notifyImagePerfDataUpdated(imagePerfData);}}@Overridepublic void onNetworkFetchFinish(ImageRequest imageRequest, long fetchTimeMs) {// 从 map 中获取对应的 ImagePerfData 对象ImagePerfData imagePerfData = imagePerfDataMap.get(imageRequest);if (imagePerfData != null) {// 记录网络请求完成时间imagePerfData.setNetworkFetchFinishTimeMs(System.currentTimeMillis());// 通知监听器图片加载性能数据更新notifyImagePerfDataUpdated(imagePerfData);}}@Overridepublic void onDecodeStart(ImageRequest imageRequest) {// 从 map 中获取对应的 ImagePerfData 对象ImagePerfData imagePerfData = imagePerfDataMap.get(imageRequest);if (imagePerfData != null) {// 记录解码开始时间imagePerfData.setDecodeStartTimeMs(System.currentTimeMillis());// 通知监听器图片加载性能数据更新notifyImagePerfDataUpdated(imagePerfData);}}@Overridepublic void onDecodeFinish(ImageRequest imageRequest, long decodeTimeMs) {// 从 map 中获取对应的 ImagePerfData 对象ImagePerfData imagePerfData = imagePerfDataMap.get(imageRequest);if (imagePerfData != null) {// 记录解码完成时间imagePerfData.setDecodeFinishTimeMs(System.currentTimeMillis());// 通知监听器图片加载性能数据更新notifyImagePerfDataUpdated(imagePerfData);}}@Overridepublic void onImageLoadFinish(ImageRequest imageRequest, long totalTimeMs) {// 从 map 中获取对应的 ImagePerfData 对象ImagePerfData imagePerfData = imagePerfDataMap.get(imageRequest);if (imagePerfData != null) {// 记录图片加载完成时间imagePerfData.setLoadFinishTimeMs(System.currentTimeMillis());// 通知监听器图片加载性能数据更新notifyImagePerfDataUpdated(imagePerfData);// 从 map 中移除该 ImagePerfData 对象imagePerfDataMap.remove(imageRequest);}}@Overridepublic void onImageLoadFailure(ImageRequest imageRequest, Throwable throwable) {// 从 map 中获取对应的 ImagePerfData 对象ImagePerfData imagePerfData = imagePerfDataMap.get(imageRequest);if (imagePerfData != null) {// 记录图片加载失败的异常信息imagePerfData.setLoadFailureThrowable(throwable);// 记录图片加载完成时间imagePerfData.setLoadFinishTimeMs(System.currentTimeMillis());// 通知监听器图片加载性能数据更新notifyImagePerfDataUpdated(imagePerfData);// 从 map 中移除该 ImagePerfData 对象imagePerfDataMap.remove(imageRequest);}}// 通知监听器图片加载性能数据更新private void notifyImagePerfDataUpdated(ImagePerfData imagePerfData) {if (imagePerfDataListener != null) {imagePerfDataListener.onImagePerfDataUpdated(imagePerfData);}}
}

3.2 ImagePerfData 的使用

ImagePerfData 主要用于存储图片加载性能数据,在 DefaultImagePerfMonitor 中被广泛使用。下面是一个使用 ImagePerfData 的示例:

java

// 创建一个 ImagePerfDataListener 实现类
ImagePerfDataListener listener = new ImagePerfDataListener() {@Overridepublic void onImagePerfDataUpdated(ImagePerfData imagePerfData) {// 获取图片请求的 URLString url = imagePerfData.getImageRequest().getSourceUri().toString();// 获取网络请求时间long networkFetchTimeMs = imagePerfData.getNetworkFetchTimeMs();// 获取解码时间long decodeTimeMs = imagePerfData.getDecodeTimeMs();// 获取图片加载总时间long totalLoadTimeMs = imagePerfData.getTotalLoadTimeMs();// 打印性能数据Log.d("ImagePerf", "URL: " + url);Log.d("ImagePerf", "Network Fetch Time: " + networkFetchTimeMs + " ms");Log.d("ImagePerf", "Decode Time: " + decodeTimeMs + " ms");Log.d("ImagePerf", "Total Load Time: " + totalLoadTimeMs + " ms");// 检查是否加载失败Throwable loadFailureThrowable = imagePerfData.getLoadFailureThrowable();if (loadFailureThrowable != null) {Log.e("ImagePerf", "Image load failed: " + loadFailureThrowable.getMessage());}}
};// 创建一个 DefaultImagePerfMonitor 实例
DefaultImagePerfMonitor monitor = new DefaultImagePerfMonitor(listener);// 创建一个 ImageRequest
ImageRequest imageRequest = ImageRequestBuilder.newBuilderWithSource(Uri.parse("http://example.com/image.jpg")).build();// 模拟图片加载开始
monitor.onImageLoadStart(imageRequest);
// 模拟网络请求开始
monitor.onNetworkFetchStart(imageRequest);
// 模拟网络请求完成
monitor.onNetworkFetchFinish(imageRequest, 500);
// 模拟解码开始
monitor.onDecodeStart(imageRequest);
// 模拟解码完成
monitor.onDecodeFinish(imageRequest, 300);
// 模拟图片加载完成
monitor.onImageLoadFinish(imageRequest, 800);

3.3 ImagePerfDataListener 的作用

ImagePerfDataListener 作为一个回调接口,允许开发者在图片加载性能数据更新时进行相应的处理。开发者可以根据自己的需求实现该接口,例如将性能数据上传到服务器进行分析,或者在界面上显示性能数据等。

java

// 实现 ImagePerfDataListener 接口
public class MyImagePerfDataListener implements ImagePerfDataListener {@Overridepublic void onImagePerfDataUpdated(ImagePerfData imagePerfData) {// 将性能数据上传到服务器uploadPerformanceDataToServer(imagePerfData);}// 上传性能数据到服务器的方法private void uploadPerformanceDataToServer(ImagePerfData imagePerfData) {// 实现上传逻辑// 示例代码,使用 OkHttp 发送请求OkHttpClient client = new OkHttpClient();RequestBody body = new FormBody.Builder().add("url", imagePerfData.getImageRequest().getSourceUri().toString()).add("networkFetchTime", String.valueOf(imagePerfData.getNetworkFetchTimeMs())).add("decodeTime", String.valueOf(imagePerfData.getDecodeTimeMs())).add("totalLoadTime", String.valueOf(imagePerfData.getTotalLoadTimeMs())).build();Request request = new Request.Builder().url("http://example.com/uploadPerformanceData").post(body).build();try {Response response = client.newCall(request).execute();if (response.isSuccessful()) {Log.d("ImagePerf", "Performance data uploaded successfully");} else {Log.e("ImagePerf", "Failed to upload performance data: " + response.message());}} catch (IOException e) {Log.e("ImagePerf", "Error uploading performance data: " + e.getMessage());}}
}

四、测试模块概述

Fresco 的测试模块主要用于对框架的各个组件进行单元测试和集成测试,确保框架的正确性和稳定性。测试模块使用了 JUnit 和 Mockito 等测试框架,通过模拟各种场景来验证框架的功能。

4.1 主要测试类和接口

4.1.1 ImagePipelineTestUtils

ImagePipelineTestUtils 是一个工具类,提供了一些用于测试的静态方法,如创建 ImageRequestEncodedImage 等对象,方便在测试中使用。

java

// 图片管道测试工具类
public class ImagePipelineTestUtils {// 创建一个 ImageRequest 对象public static ImageRequest createImageRequest(Uri uri) {return ImageRequestBuilder.newBuilderWithSource(uri).build();}// 创建一个 EncodedImage 对象public static EncodedImage createEncodedImage(InputStream inputStream) {return new EncodedImage(ByteStreams.toByteArray(inputStream));}// 创建一个 CloseableReference<CloseableImage> 对象public static CloseableReference<CloseableImage> createCloseableImageReference(Bitmap bitmap) {CloseableStaticBitmap closeableStaticBitmap = new CloseableStaticBitmap(bitmap,SimpleBitmapReleaser.getInstance());return CloseableReference.of(closeableStaticBitmap);}
}
4.1.2 MockImageDecoder

MockImageDecoder 是一个模拟的图片解码器,用于在测试中替代真实的解码器。它可以返回预设的 CloseableImage 对象,方便测试图片解码功能。

java

// 模拟图片解码器
public class MockImageDecoder implements ImageDecoder {private final CloseableImage mockCloseableImage;public MockImageDecoder(CloseableImage mockCloseableImage) {this.mockCloseableImage = mockCloseableImage;}@Overridepublic CloseableImage decodeImage(EncodedImage encodedImage, int length, ImageDecodeOptions options) {// 返回预设的 CloseableImage 对象return mockCloseableImage;}
}
4.1.3 MockNetworkFetcher

MockNetworkFetcher 是一个模拟的网络请求器,用于在测试中替代真实的网络请求器。它可以返回预设的 EncodedImage 对象,方便测试图片网络加载功能。

java

// 模拟网络请求器
public class MockNetworkFetcher implements NetworkFetcher<MockNetworkFetchState> {private final EncodedImage mockEncodedImage;public MockNetworkFetcher(EncodedImage mockEncodedImage) {this.mockEncodedImage = mockEncodedImage;}@Overridepublic MockNetworkFetchState createFetchState(ImageRequest request, Object callerContext) {return new MockNetworkFetchState(request, callerContext);}@Overridepublic void fetch(final MockNetworkFetchState fetchState, final Callback callback) {// 模拟网络请求完成,返回预设的 EncodedImage 对象callback.onResponse(fetchState, mockEncodedImage.getInputStream(), mockEncodedImage.getSize(), 0, 0);}
}// 模拟网络请求状态
class MockNetworkFetchState extends NetworkFetchState {public MockNetworkFetchState(ImageRequest request, Object callerContext) {super(request, callerContext);}
}

4.2 测试模块的使用场景

  • 单元测试:使用 ImagePipelineTestUtilsMockImageDecoderMockNetworkFetcher 等工具类和模拟对象,对框架的各个组件进行独立的单元测试,确保每个组件的功能正确性。
  • 集成测试:通过组合多个模拟对象和工具类,模拟框架的实际运行场景,进行集成测试,验证框架的整体功能和稳定性。

五、测试模块源码分析

5.1 ImagePipelineTestUtils 的使用

ImagePipelineTestUtils 提供了一些方便的静态方法,用于创建测试所需的对象。下面是一个使用 ImagePipelineTestUtils 的示例:

java

import org.junit.Test;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.net.URI;
import java.net.URISyntaxException;
import android.net.Uri;
import com.facebook.imagepipeline.image.CloseableStaticBitmap;
import com.facebook.imagepipeline.image.EncodedImage;
import com.facebook.imagepipeline.request.ImageRequest;
import com.facebook.common.references.CloseableReference;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;import static org.junit.Assert.*;public class ImagePipelineTestUtilsTest {@Testpublic void testCreateImageRequest() throws URISyntaxException {// 创建一个 URIURI uri = new URI("http://example.com/image.jpg");// 使用 ImagePipelineTestUtils 创建 ImageRequest 对象ImageRequest imageRequest = ImagePipelineTestUtils.createImageRequest(Uri.parse(uri.toString()));// 验证 ImageRequest 对象的 URI 是否正确assertEquals(uri.toString(), imageRequest.getSourceUri().toString());}@Testpublic void testCreateEncodedImage() {// 创建一个输入流byte[] data = new byte[]{1, 2, 3, 4, 5};InputStream inputStream = new ByteArrayInputStream(data);// 使用 ImagePipelineTestUtils 创建 EncodedImage 对象EncodedImage encodedImage = ImagePipelineTestUtils.createEncodedImage(inputStream);// 验证 EncodedImage 对象的数据长度是否正确assertEquals(data.length, encodedImage.getSize());}@Testpublic void testCreateCloseableImageReference() {// 创建一个 Bitmap 对象Bitmap bitmap = BitmapFactory.decodeResource(getClass().getResourceAsStream("/test_image.jpg"));// 使用 ImagePipelineTestUtils 创建 CloseableReference<CloseableImage> 对象CloseableReference<CloseableImage> closeableImageReference = ImagePipelineTestUtils.createCloseableImageReference(bitmap);// 验证 CloseableReference<CloseableImage> 对象是否正确创建assertNotNull(closeableImageReference);}
}

5.2 MockImageDecoder 的使用

MockImageDecoder 可以在测试中替代真实的解码器,返回预设的 CloseableImage 对象。下面是一个使用 MockImageDecoder 的示例:

java

import org.junit.Test;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import com.facebook.imagepipeline.image.CloseableStaticBitmap;
import com.facebook.imagepipeline.image.EncodedImage;
import com.facebook.imagepipeline.image.ImageDecoder;
import com.facebook.common.references.CloseableReference;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;import static org.junit.Assert.*;public class MockImageDecoderTest {@Testpublic void testDecodeImage() {// 创建一个 Bitmap 对象Bitmap bitmap = BitmapFactory.decodeResource(getClass().getResourceAsStream("/test_image.jpg"));// 创建一个 CloseableStaticBitmap 对象CloseableStaticBitmap closeableStaticBitmap = new CloseableStaticBitmap(bitmap,SimpleBitmapReleaser.getInstance());// 创建一个 MockImageDecoder 对象,传入预设的 CloseableStaticBitmap 对象MockImageDecoder mockImageDecoder = new MockImageDecoder(closeableStaticBitmap);// 创建一个 EncodedImage 对象byte[] data = new byte[]{1, 2, 3, 4, 5};InputStream inputStream = new ByteArrayInputStream(data);EncodedImage encodedImage = new EncodedImage(data);// 调用 MockImageDecoder 的 decodeImage 方法进行解码CloseableImage decodedImage = mockImageDecoder.decodeImage(encodedImage, data.length, null);// 验证解码结果是否为预设的 CloseableStaticBitmap 对象assertEquals(closeableStaticBitmap, decodedImage);}
}

5.3 MockNetworkFetcher 的使用

MockNetworkFetcher 可以在测试中替代真实的网络请求器,返回预设的 EncodedImage 对象。下面是一个使用 MockNetworkFetcher 的示例:

java

import org.junit.Test;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import com.facebook.imagepipeline.image.EncodedImage;
import com.facebook.imagepipeline.producers.NetworkFetcher;
import com.facebook.imagepipeline.producers.NetworkFetcher.Callback;
import com.facebook.imagepipeline.request.ImageRequest;
import com.facebook.imagepipeline.request.ImageRequestBuilder;import static org.mockito.Mockito.*;public class MockNetworkFetcherTest {@Testpublic void testFetch() {// 创建一个 EncodedImage 对象byte[] data = new byte[]{1, 2, 3, 4, 5};InputStream inputStream = new ByteArrayInputStream(data);EncodedImage encodedImage = new EncodedImage(data);// 创建一个 MockNetworkFetcher 对象,传入预设的 EncodedImage 对象MockNetworkFetcher mockNetworkFetcher = new MockNetworkFetcher(encodedImage);// 创建一个 ImageRequest 对象ImageRequest imageRequest = ImageRequestBuilder.newBuilderWithSource(Uri.parse("http://example.com/image.jpg")).build();// 创建一个 MockNetworkFetchState 对象MockNetworkFetchState fetchState = new MockNetworkFetchState(imageRequest, null);// 创建一个 Callback 模拟对象Callback callback = mock(Callback.class);// 调用 MockNetworkFetcher 的 fetch 方法进行网络请求mockNetworkFetcher.fetch(fetchState, callback);// 验证 Callback 的 onResponse 方法是否被调用verify(callback, times(1)).onResponse(fetchState, encodedImage.getInputStream(), encodedImage.getSize(), 0, 0);}
}

六、工具与测试模块的结合使用

在实际开发中,工具模块和测试模块可以结合使用,以提高开发效率和代码质量。下面是一个结合使用工具与测试模块的示例:

6.1 测试图片加载性能监控功能

java

import org.junit.Test;
import java.net.URI;
import java.net.URISyntaxException;
import android.net.Uri;
import com.facebook.imagepipeline.request.ImageRequest;
import com.facebook.imagepipeline.request.ImageRequestBuilder;
import com.facebook.imagepipeline.image.ImagePerfData;
import com.facebook.imagepipeline.image.ImagePerfDataListener;
import com.facebook.imagepipeline.image.DefaultImagePerfMonitor;import static org.mockito.Mockito.*;public class ImagePerfMonitorTest {@Testpublic void testImagePerfMonitor() throws URISyntaxException {// 创建一个 ImagePer

java

import org.junit.Test;
import java.net.URI;
import java.net.URISyntaxException;
import android.net.Uri;
import com.facebook.imagepipeline.request.ImageRequest;
import com.facebook.imagepipeline.request.ImageRequestBuilder;
import com.facebook.imagepipeline.image.ImagePerfData;
import com.facebook.imagepipeline.image.ImagePerfDataListener;
import com.facebook.imagepipeline.image.DefaultImagePerfMonitor;import static org.mockito.Mockito.*;public class ImagePerfMonitorTest {@Testpublic void testImagePerfMonitor() throws URISyntaxException {// 创建一个 ImagePerfDataListener 模拟对象ImagePerfDataListener mockListener = mock(ImagePerfDataListener.class);// 创建 DefaultImagePerfMonitor 实例,并传入模拟的监听器DefaultImagePerfMonitor monitor = new DefaultImagePerfMonitor(mockListener);// 创建一个 ImageRequestURI uri = new URI("http://example.com/image.jpg");ImageRequest imageRequest = ImageRequestBuilder.newBuilderWithSource(Uri.parse(uri.toString())).build();// 模拟图片加载开始monitor.onImageLoadStart(imageRequest);// 验证监听器的 onImagePerfDataUpdated 方法是否被调用verify(mockListener, times(1)).onImagePerfDataUpdated(any(ImagePerfData.class));// 模拟网络请求开始monitor.onNetworkFetchStart(imageRequest);// 验证监听器的 onImagePerfDataUpdated 方法是否再次被调用verify(mockListener, times(2)).onImagePerfDataUpdated(any(ImagePerfData.class));// 模拟网络请求完成monitor.onNetworkFetchFinish(imageRequest, 500);// 验证监听器的 onImagePerfDataUpdated 方法是否又被调用verify(mockListener, times(3)).onImagePerfDataUpdated(any(ImagePerfData.class));// 模拟解码开始monitor.onDecodeStart(imageRequest);// 验证监听器的 onImagePerfDataUpdated 方法是否再次被调用verify(mockListener, times(4)).onImagePerfDataUpdated(any(ImagePerfData.class));// 模拟解码完成monitor.onDecodeFinish(imageRequest, 300);// 验证监听器的 onImagePerfDataUpdated 方法是否又被调用verify(mockListener, times(5)).onImagePerfDataUpdated(any(ImagePerfData.class));// 模拟图片加载完成monitor.onImageLoadFinish(imageRequest, 800);// 验证监听器的 onImagePerfDataUpdated 方法是否再次被调用verify(mockListener, times(6)).onImagePerfDataUpdated(any(ImagePerfData.class));}
}

在这个测试中,我们创建了一个 DefaultImagePerfMonitor 实例,并传入一个模拟的 ImagePerfDataListener。然后模拟了图片加载的各个阶段,并验证监听器的 onImagePerfDataUpdated 方法是否按照预期被调用。

6.2 结合工具与测试进行图片加载流程测试

java

import org.junit.Test;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.net.URI;
import java.net.URISyntaxException;
import android.net.Uri;
import com.facebook.imagepipeline.request.ImageRequest;
import com.facebook.imagepipeline.request.ImageRequestBuilder;
import com.facebook.imagepipeline.image.CloseableStaticBitmap;
import com.facebook.imagepipeline.image.EncodedImage;
import com.facebook.imagepipeline.image.ImageDecoder;
import com.facebook.imagepipeline.producers.NetworkFetcher;
import com.facebook.imagepipeline.producers.NetworkFetcher.Callback;
import com.facebook.imagepipeline.producers.MockNetworkFetcher;
import com.facebook.imagepipeline.producers.MockNetworkFetchState;
import com.facebook.imagepipeline.image.MockImageDecoder;
import com.facebook.imagepipeline.image.ImagePerfData;
import com.facebook.imagepipeline.image.ImagePerfDataListener;
import com.facebook.imagepipeline.image.DefaultImagePerfMonitor;
import com.facebook.common.references.CloseableReference;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;import static org.mockito.Mockito.*;public class ImageLoadingFlowTest {@Testpublic void testImageLoadingFlow() throws URISyntaxException {// 创建一个 ImagePerfDataListener 模拟对象ImagePerfDataListener mockPerfListener = mock(ImagePerfDataListener.class);// 创建 DefaultImagePerfMonitor 实例,并传入模拟的监听器DefaultImagePerfMonitor perfMonitor = new DefaultImagePerfMonitor(mockPerfListener);// 创建一个 ImageRequestURI uri = new URI("http://example.com/image.jpg");ImageRequest imageRequest = ImageRequestBuilder.newBuilderWithSource(Uri.parse(uri.toString())).build();// 模拟网络请求返回的 EncodedImagebyte[] data = new byte[]{1, 2, 3, 4, 5};InputStream inputStream = new ByteArrayInputStream(data);EncodedImage mockEncodedImage = new EncodedImage(data);// 创建 MockNetworkFetcher 实例MockNetworkFetcher mockNetworkFetcher = new MockNetworkFetcher(mockEncodedImage);// 创建一个 Bitmap 对象Bitmap bitmap = BitmapFactory.decodeResource(getClass().getResourceAsStream("/test_image.jpg"));// 创建一个 CloseableStaticBitmap 对象CloseableStaticBitmap closeableStaticBitmap = new CloseableStaticBitmap(bitmap,SimpleBitmapReleaser.getInstance());// 创建 MockImageDecoder 实例MockImageDecoder mockImageDecoder = new MockImageDecoder(closeableStaticBitmap);// 模拟图片加载开始perfMonitor.onImageLoadStart(imageRequest);// 模拟网络请求开始perfMonitor.onNetworkFetchStart(imageRequest);MockNetworkFetchState fetchState = new MockNetworkFetchState(imageRequest, null);Callback mockCallback = mock(Callback.class);mockNetworkFetcher.fetch(fetchState, mockCallback);// 模拟网络请求完成perfMonitor.onNetworkFetchFinish(imageRequest, 500);// 模拟解码开始perfMonitor.onDecodeStart(imageRequest);ImageDecoder decoder = mockImageDecoder;CloseableReference<CloseableStaticBitmap> decodedImage = decoder.decodeImage(mockEncodedImage, data.length, null);// 模拟解码完成perfMonitor.onDecodeFinish(imageRequest, 300);// 模拟图片加载完成perfMonitor.onImageLoadFinish(imageRequest, 800);// 验证性能监听器的调用次数verify(mockPerfListener, times(6)).onImagePerfDataUpdated(any(ImagePerfData.class));}
}

在这个测试中,我们结合了工具模块的 DefaultImagePerfMonitor 和测试模块的 MockNetworkFetcherMockImageDecoder,模拟了一个完整的图片加载流程,并验证了性能监听器的调用次数是否符合预期。

6.3 工具与测试在异常处理测试中的应用

java

import org.junit.Test;
import java.net.URI;
import java.net.URISyntaxException;
import android.net.Uri;
import com.facebook.imagepipeline.request.ImageRequest;
import com.facebook.imagepipeline.request.ImageRequestBuilder;
import com.facebook.imagepipeline.image.ImagePerfData;
import com.facebook.imagepipeline.image.ImagePerfDataListener;
import com.facebook.imagepipeline.image.DefaultImagePerfMonitor;
import com.facebook.imagepipeline.producers.NetworkFetcher;
import com.facebook.imagepipeline.producers.NetworkFetcher.Callback;
import com.facebook.imagepipeline.producers.MockNetworkFetcher;
import com.facebook.imagepipeline.producers.MockNetworkFetchState;import static org.mockito.Mockito.*;public class ExceptionHandlingTest {@Testpublic void testNetworkFailure() throws URISyntaxException {// 创建一个 ImagePerfDataListener 模拟对象ImagePerfDataListener mockPerfListener = mock(ImagePerfDataListener.class);// 创建 DefaultImagePerfMonitor 实例,并传入模拟的监听器DefaultImagePerfMonitor perfMonitor = new DefaultImagePerfMonitor(mockPerfListener);// 创建一个 ImageRequestURI uri = new URI("http://example.com/image.jpg");ImageRequest imageRequest = ImageRequestBuilder.newBuilderWithSource(Uri.parse(uri.toString())).build();// 模拟图片加载开始perfMonitor.onImageLoadStart(imageRequest);// 模拟网络请求开始perfMonitor.onNetworkFetchStart(imageRequest);MockNetworkFetchState fetchState = new MockNetworkFetchState(imageRequest, null);Callback mockCallback = mock(Callback.class);// 模拟网络请求失败Exception networkException = new Exception("Network failure");doAnswer(invocation -> {perfMonitor.onImageLoadFailure(imageRequest, networkException);return null;}).when(mockCallback).onFailure(fetchState, networkException);// 模拟网络请求器调用失败回调mockCallback.onFailure(fetchState, networkException);// 验证性能监听器是否收到加载失败的通知verify(mockPerfListener, times(3)).onImagePerfDataUpdated(any(ImagePerfData.class));ImagePerfData capturedData = null;ArgumentCaptor<ImagePerfData> captor = ArgumentCaptor.forClass(ImagePerfData.class);verify(mockPerfListener, times(3)).onImagePerfDataUpdated(captor.capture());capturedData = captor.getValue();assertEquals(networkException, capturedData.getLoadFailureThrowable());}
}

在这个测试中,我们使用 DefaultImagePerfMonitor 监控图片加载过程,模拟了网络请求失败的情况,并验证了性能监听器是否正确记录了加载失败的异常信息。

七、工具与测试模块的性能优化

7.1 工具模块性能优化

7.1.1 减少性能监控的开销

ImagePerfMonitor 在记录性能数据时,会频繁调用系统时间函数(如 System.currentTimeMillis()),这可能会带来一定的性能开销。为了减少这种开销,可以采用批量记录的方式,例如在一段时间内记录多个事件的时间,然后一次性处理这些数据。

java

// 优化后的 ImagePerfMonitor 实现
public class OptimizedImagePerfMonitor implements ImagePerfMonitor {private final ImagePerfDataListener imagePerfDataListener;private final Map<ImageRequest, ImagePerfData> imagePerfDataMap = new HashMap<>();private final long batchIntervalMs = 1000; // 批量处理的时间间隔private long lastBatchTimeMs = System.currentTimeMillis();private List<ImagePerfData> batchData = new ArrayList<>();public OptimizedImagePerfMonitor(ImagePerfDataListener imagePerfDataListener) {this.imagePerfDataListener = imagePerfDataListener;}@Overridepublic void onImageLoadStart(ImageRequest imageRequest) {ImagePerfData imagePerfData = new ImagePerfData(imageRequest);imagePerfData.setLoadStartTimeMs(System.currentTimeMillis());imagePerfDataMap.put(imageRequest, imagePerfData);addToBatch(imagePerfData);}@Overridepublic void onNetworkFetchStart(ImageRequest imageRequest) {ImagePerfData imagePerfData = imagePerfDataMap.get(imageRequest);if (imagePerfData != null) {imagePerfData.setNetworkFetchStartTimeMs(System.currentTimeMillis());addToBatch(imagePerfData);}}@Overridepublic void onNetworkFetchFinish(ImageRequest imageRequest, long fetchTimeMs) {ImagePerfData imagePerfData = imagePerfDataMap.get(imageRequest);if (imagePerfData != null) {imagePerfData.setNetworkFetchFinishTimeMs(System.currentTimeMillis());addToBatch(imagePerfData);}}@Overridepublic void onDecodeStart(ImageRequest imageRequest) {ImagePerfData imagePerfData = imagePerfDataMap.get(imageRequest);if (imagePerfData != null) {imagePerfData.setDecodeStartTimeMs(System.currentTimeMillis());addToBatch(imagePerfData);}}@Overridepublic void onDecodeFinish(ImageRequest imageRequest, long decodeTimeMs) {ImagePerfData imagePerfData = imagePerfDataMap.get(imageRequest);if (imagePerfData != null) {imagePerfData.setDecodeFinishTimeMs(System.currentTimeMillis());addToBatch(imagePerfData);}}@Overridepublic void onImageLoadFinish(ImageRequest imageRequest, long totalTimeMs) {ImagePerfData imagePerfData = imagePerfDataMap.get(imageRequest);if (imagePerfData != null) {imagePerfData.setLoadFinishTimeMs(System.currentTimeMillis());addToBatch(imagePerfData);imagePerfDataMap.remove(imageRequest);}}@Overridepublic void onImageLoadFailure(ImageRequest imageRequest, Throwable throwable) {ImagePerfData imagePerfData = imagePerfDataMap.get(imageRequest);if (imagePerfData != null) {imagePerfData.setLoadFailureThrowable(throwable);imagePerfData.setLoadFinishTimeMs(System.currentTimeMillis());addToBatch(imagePerfData);imagePerfDataMap.remove(imageRequest);}}private void addToBatch(ImagePerfData imagePerfData) {batchData.add(imagePerfData);long currentTimeMs = System.currentTimeMillis();if (currentTimeMs - lastBatchTimeMs >= batchIntervalMs) {processBatch();lastBatchTimeMs = currentTimeMs;batchData.clear();}}private void processBatch() {if (imagePerfDataListener != null) {for (ImagePerfData data : batchData) {imagePerfDataListener.onImagePerfDataUpdated(data);}}}
}
7.1.2 优化数据存储和处理

ImagePerfData 中,可以考虑使用更高效的数据结构来存储性能数据,例如使用数组代替 Map 来存储时间戳,以减少内存开销和查找时间。

java

// 优化后的 ImagePerfData 实现
public class OptimizedImagePerfData {private final ImageRequest imageRequest;private final long[] timestamps = new long[6]; // 分别存储加载开始、网络请求开始、网络请求完成、解码开始、解码完成、加载完成的时间private Throwable loadFailureThrowable;public OptimizedImagePerfData(ImageRequest imageRequest) {this.imageRequest = imageRequest;for (int i = 0; i < timestamps.length; i++) {timestamps[i] = -1;}}public ImageRequest getImageRequest() {return imageRequest;}public void setLoadStartTimeMs(long loadStartTimeMs) {timestamps[0] = loadStartTimeMs;}public long getLoadStartTimeMs() {return timestamps[0];}public void setNetworkFetchStartTimeMs(long networkFetchStartTimeMs) {timestamps[1] = networkFetchStartTimeMs;}public long getNetworkFetchStartTimeMs() {return timestamps[1];}public void setNetworkFetchFinishTimeMs(long networkFetchFinishTimeMs) {timestamps[2] = networkFetchFinishTimeMs;}public long getNetworkFetchFinishTimeMs() {return timestamps[2];}public void setDecodeStartTimeMs(long decodeStartTimeMs) {timestamps[3] = decodeStartTimeMs;}public long getDecodeStartTimeMs() {return timestamps[3];}public void setDecodeFinishTimeMs(long decodeFinishTimeMs) {timestamps[4] = decodeFinishTimeMs;}public long getDecodeFinishTimeMs() {return timestamps[4];}public void setLoadFinishTimeMs(long loadFinishTimeMs) {timestamps[5] = loadFinishTimeMs;}public long getLoadFinishTimeMs() {return timestamps[5];}public void setLoadFailureThrowable(Throwable loadFailureThrowable) {this.loadFailureThrowable = loadFailureThrowable;}public Throwable getLoadFailureThrowable() {return loadFailureThrowable;}public long getNetworkFetchTimeMs() {if (timestamps[1] != -1 && timestamps[2] != -1) {return timestamps[2] - timestamps[1];}return 0;}public long getDecodeTimeMs() {if (timestamps[3] != -1 && timestamps[4] != -1) {return timestamps[4] - timestamps[3];}return 0;}public long getTotalLoadTimeMs() {if (timestamps[0] != -1 && timestamps[5] != -1) {return timestamps[5] - timestamps[0];}return 0;}
}

7.2 测试模块性能优化

7.2.1 减少模拟对象的创建开销

在测试中,频繁创建模拟对象(如 MockNetworkFetcherMockImageDecoder 等)可能会带来一定的性能开销。可以考虑使用对象池来复用这些模拟对象,减少创建和销毁的次数。

java

// 模拟对象池实现
public class MockObjectPool {private static final int POOL_SIZE = 10;private final Queue<MockNetworkFetcher> networkFetcherPool = new LinkedList<>();private final Queue<MockImageDecoder> imageDecoderPool = new LinkedList<>();public MockObjectPool() {for (int i = 0; i < POOL_SIZE; i++) {networkFetcherPool.add(createMockNetworkFetcher());imageDecoderPool.add(createMockImageDecoder());}}private MockNetworkFetcher createMockNetworkFetcher() {byte[] data = new byte[]{1, 2, 3, 4, 5};InputStream inputStream = new ByteArrayInputStream(data);EncodedImage mockEncodedImage = new EncodedImage(data);return new MockNetworkFetcher(mockEncodedImage);}private MockImageDecoder createMockImageDecoder() {Bitmap bitmap = BitmapFactory.decodeResource(getClass().getResourceAsStream("/test_image.jpg"));CloseableStaticBitmap closeableStaticBitmap = new CloseableStaticBitmap(bitmap,SimpleBitmapReleaser.getInstance());return new MockImageDecoder(closeableStaticBitmap);}public MockNetworkFetcher borrowNetworkFetcher() {if (networkFetcherPool.isEmpty()) {return createMockNetworkFetcher();}return networkFetcherPool.poll();}public void returnNetworkFetcher(MockNetworkFetcher fetcher) {if (networkFetcherPool.size() < POOL_SIZE) {networkFetcherPool.add(fetcher);}}public MockImageDecoder borrowImageDecoder() {if (imageDecoderPool.isEmpty()) {return createMockImageDecoder();}return imageDecoderPool.poll();}public void returnImageDecoder(MockImageDecoder decoder) {if (imageDecoderPool.size() < POOL_SIZE) {imageDecoderPool.add(decoder);}}
}
7.2.2 并行执行测试用例

对于一些相互独立的测试用例,可以使用 JUnit 的并行执行功能来提高测试效率。在 JUnit 5 中,可以通过配置 junit.jupiter.execution.parallel.enabled 属性来启用并行执行。

groovy

// 在 build.gradle 中配置 JUnit 5 并行执行
test {useJUnitPlatform {configurationParameter 'junit.jupiter.execution.parallel.enabled', 'true'configurationParameter 'junit.jupiter.execution.parallel.mode.default', 'concurrent'}
}

八、工具与测试模块在实际项目中的应用案例

8.1 性能监控在图片加载优化中的应用

在一个电商应用中,开发者发现部分图片加载速度较慢,影响了用户体验。通过使用 ImagePerfMonitor 监控图片加载性能,发现网络请求时间和解码时间较长是主要问题。

java

// 在应用中初始化 ImagePerfMonitor
ImagePerfDataListener listener = new ImagePerfDataListener() {@Overridepublic void onImagePerfDataUpdated(ImagePerfData imagePerfData) {long networkFetchTimeMs = imagePerfData.getNetworkFetchTimeMs();long decodeTimeMs = imagePerfData.getDecodeTimeMs();if (networkFetchTimeMs > 500 || decodeTimeMs > 300) {// 记录性能瓶颈的图片 URLString url = imagePerfData.getImageRequest().getSourceUri().toString();Log.w("ImagePerf", "Slow image loading: " + url +", Network Fetch Time: " + networkFetchTimeMs + " ms, Decode Time: " + decodeTimeMs + " ms");}}
};
DefaultImagePerfMonitor monitor = new DefaultImagePerfMonitor(listener);// 在图片加载处添加性能监控
ImageRequest imageRequest = ImageRequestBuilder.newBuilderWithSource(Uri.parse("http://example.com/image.jpg")).build();
monitor.onImageLoadStart(imageRequest);
// 后续网络请求、解码等操作,在相应位置调用 monitor 的方法记录时间

通过分析性能数据,开发者发现部分图片服务器响应较慢,于是更换了图片服务器;同时,对解码逻辑进行了优化,减少了解码时间。经过优化后,图片加载速度明显提升。

8.2 测试模块在功能迭代中的应用

在一个社交应用的开发过程中,需要对图片加载功能进行迭代,添加新的图片格式支持。为了确保新功能的正确性,开发者使用了测试模块进行单元测试和集成测试。

java

import org.junit.Test;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import com.facebook.imagepipeline.image.CloseableStaticBitmap;
import com.facebook.imagepipeline.image.EncodedImage;
import com.facebook.imagepipeline.image.ImageDecoder;
import com.facebook.imagepipeline.producers.NetworkFetcher;
import com.facebook.imagepipeline.producers.MockNetworkFetcher;
import com.facebook.imagepipeline.producers.MockNetworkFetchState;
import com.facebook.imagepipeline.image.MockImageDecoder;
import com.facebook.imagepipeline.request.ImageRequest;
import com.facebook.imagepipeline.request.ImageRequestBuilder;
import com.facebook.common.references.CloseableReference;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;import static org.junit.Assert.*;public class NewImageFormatSupportTest {@Testpublic void testNewImageFormatLoading() {// 模拟新图片格式的 EncodedImagebyte[] newFormatData = new byte[]{10, 20, 30, 40, 50};InputStream inputStream = new ByteArrayInputStream(newFormatData);EncodedImage newFormatEncodedImage = new EncodedImage(newFormatData);// 创建 MockNetworkFetcher 实例MockNetworkFetcher mockNetworkFetcher = new MockNetworkFetcher(newFormatEncodedImage);// 创建一个 Bitmap 对象Bitmap bitmap = BitmapFactory.decodeResource(getClass().getResourceAsStream("/test_image.jpg"));// 创建一个 CloseableStaticBitmap 对象CloseableStaticBitmap closeableStaticBitmap = new CloseableStaticBitmap(bitmap,SimpleBitmapReleaser.getInstance());// 创建 MockImageDecoder 实例,模拟支持新图片格式的解码MockImageDecoder mockImageDecoder = new MockImageDecoder(closeableStaticBitmap);// 创建 ImageRequestImageRequest imageRequest = ImageRequestBuilder.newBuilderWithSource(Uri.parse("http://example.com/new_format_image.jpg")).build();// 模拟网络请求MockNetworkFetchState fetchState = new MockNetworkFetchState(imageRequest, null);NetworkFetcher.Callback mockCallback = mock(NetworkFetcher.Callback.class);mockNetworkFetcher.fetch(fetchState, mockCallback);// 模拟解码CloseableReference<CloseableStaticBitmap> decodedImage = mockImageDecoder.decodeImage(newFormatEncodedImage, newFormatData.length, null);// 验证解码结果assertNotNull(decodedImage);}
}

通过这些测试用例,开发者可以在开发过程中及时发现新功能的问题,确保图片加载功能在添加新图片格式支持后仍然稳定可靠。

九、总结

Fresco 框架的工具与测试模块为开发者提供了强大的辅助功能,帮助开发者更好地理解和优化框架的性能,同时确保代码的正确性和稳定性。工具模块中的 ImagePerfMonitorImagePerfDataImagePerfDataListener 可以帮助开发者监控图片加载性能,定位性能瓶颈;测试模块中的 ImagePipelineTestUtilsMockImageDecoderMockNetworkFetcher 等工具类和模拟对象可以方便开发者进行单元测试和集成测试。

在实际应用中,工具与测试模块可以结合使用,提高开发效率和代码质量。同时,通过对工具与测试模块进行性能优化,可以进一步提升框架的整体性能。在未来的开发中,开发者可以充分利用这些模块的功能,不断优化和完善自己的应用。

以上就是对 Android Fresco 框架工具与测试模块的深入分析,希望能为开发者在使用和扩展 Fresco 框架时提供有价值的参考。在实际开发过程中,开发者可以根据具体需求灵活运用这些功能,不断探索和创新。


http://www.ppmy.cn/news/1580283.html

相关文章

网页制作17-Javascipt图像特效の鼠标经过图像震动

01、效果图 02、grammer用法 parseInt() 函数可解析一个字符串&#xff0c;并返回一个整数。 parseInt(string, radix) 如果 string 以 "0x" 开头&#xff0c;parseInt() 会把 string 的其余部分解析为十六进制的整数。如果 string 以 0 开头&#xff0c;那么 ECMASc…

学习Python如何高效处理CSV文件的技巧!

在Python中&#xff0c;处理CSV文件是一项非常常见的任务&#xff0c;特别是在数据分析和数据科学领域。CSV文件的全称是Comma-Separated Values&#xff0c;顾名思义&#xff0c;它以逗号为分隔符来存储表格数据。这种格式简单易读&#xff0c;也很方便进行数据的存储和交换。…

redis十大应用数据类型具体使用及其应用

Redis 提供了多种数据类型&#xff0c;每种数据类型都有其特定的应用场景。下面是 Redis 十大应用数据类型的具体使用及其应用场景&#xff1a; 1. 字符串 (String) 描述&#xff1a;Redis 中最基本的数据类型&#xff0c;用于存储简单的字符串数据。字符串可以是文本、数字&a…

JVAV面试-静态代理动态代理

前面已经更新了非常多的java基础知识和面试技巧&#xff0c;这一篇文章可以说是java面试中java基础最后的绝唱&#xff0c;也是基础知识的压轴戏&#xff0c;和前面反射内容息息相关。代理是一种设计模式&#xff0c;在每种语言上都有体现&#xff0c;但是能窥见一斑的人不多&a…

护网面试题

来看看下面蓝中的面试题你能答得上来不&#xff1f; 讲一下中国菜刀、蚁剑、冰蝎的流量特征详解及三者之间的区别&#xff1f; 1、中国菜刀&#xff08;Cknife&#xff09;流量特征 基础特征 静态特征&#xff1a;默认使用一句话木马&#xff0c;如PHP的<?php eval($_POS…

【java面向对象进阶】------继承

1. 继承概述 格式&#xff1a; 1.1 引例 假如我们要定义如下类: 学生类,老师类和工人类&#xff0c;分析如下。 学生类 属性:姓名,年龄 行为:吃饭,睡觉 老师类 属性:姓名,年龄,薪水 行为:吃饭,睡觉&#xff0c;教书 班主任 属性:姓名,年龄,薪水 行为:吃饭,睡觉&#xff0c…

llamafactory的参数详解 1:(量化等级和方法 RoPE插值方法 加速方式),会对照图片解释,适合小白

前言&#xff1a; 因为刚刚接触大模型&#xff0c;是新手小白&#xff0c;所以刚好学习一下参数是什么意思&#xff0c;在这里分享。 量化等级与量化方法 1. 量化等级&#xff08;Quantization Levels&#xff09; 定义&#xff1a; 量化等级是指将连续或高精度的数据&#x…

Android Zygote的进程机制

目录 ✅ Android Zygote 进程机制详解 &#x1f6a9; 一、Zygote 的作用 ⚙️ 二、Zygote 启动流程 ✅ 1. init 进程启动 Zygote ✅ 2. Zygote 初始化虚拟机与核心类库 ✅ 3. Zygote 监听 Socket ✅ 4. Zygote fork 创建应用进程 &#x1f525; 三、Zygote 与应用进程之…