【android每日一问,复习指南

截取部分源码:

@NonNull
Glide build(@NonNull Context context) {

if (memoryCache == null) {
  memoryCache = new LruResourceCache(memorySizeCalculator.getMemoryCacheSize());
}

if (engine == null) {
  engine =
      new Engine(
          memoryCache,
          diskCacheFactory,
          diskCacheExecutor,
          sourceExecutor,
          GlideExecutor.newUnlimitedSourceExecutor(),
          GlideExecutor.newAnimationExecutor(),
          isActiveResourceRetentionAllowed);
} 

*   memoryCache就是Glide使用的内存缓存,LruResourceCache类继承了LruCache,这部分可以自行查看一下源码。

通过上面可以看到,GLide#build()方法中实例化memoryCache作为Glide的内存缓存,并将其传给Engine作为构造器的入参。

*   Engine.class 截取部分源码

{
//生成缓存key
EngineKey key = keyFactory.buildKey(model, signature, width, height, transformations,
resourceClass, transcodeClass, options);
//从弱应用中读取缓存
EngineResource<?> active = loadFromActiveResources(key, isMemoryCacheable);
if (active != null) {
cb.onResourceReady(active, DataSource.MEMORY_CACHE);
if (VERBOSE_IS_LOGGABLE) {
logWithTimeAndKey(“Loaded resource from active resources”, startTime, key);
}
return null;
}
//从LruCache中读取缓存
EngineResource<?> cached = loadFromCache(key, isMemoryCacheable);
if (cached != null) {
cb.onResourceReady(cached, DataSource.MEMORY_CACHE);
if (VERBOSE_IS_LOGGABLE) {
logWithTimeAndKey(“Loaded resource from cache”, startTime, key);
}
return null;
}
EngineJob engineJob =
engineJobFactory.build(
key,
isMemoryCacheable,
useUnlimitedSourceExecutorPool,
useAnimationPool,
onlyRetrieveFromCache);
jobs.put(key, engineJob);

engineJob.addCallback(cb);
//开启线程池,加载图片
engineJob.start(decodeJob);

}


从上可知,Glide加载过程中使用loadFromActiveResources方法和loadFromCache方法来获取内存缓存的。

大致总结一下: 首先从弱引用读取缓存,没有的话通过Lru读取,有则取,并且加到弱引用中,如果没有会开启EngineJob进行后面的图片加载逻辑。

下面直接看之后的缓存部分代码:

*   Engine#onEngineJobComplete()

public void onEngineJobComplete(EngineJob<?> engineJob, Key key, EngineResource<?> resource) {
Util.assertMainThread();
// A null resource indicates that the load failed, usually due to an exception.
if (resource != null) {
resource.setResourceListener(key, this);

  if (resource.isCacheable()) {
    activeResources.activate(key, resource);
  }
}

jobs.removeIfCurrent(key, engineJob);

}
void activate(Key key, EngineResource<?> resource) {
ResourceWeakReference toPut =
new ResourceWeakReference(
key,
resource,
getReferenceQueue(),
isActiveResourceRetentionAllowed);

ResourceWeakReference removed = activeEngineResources.put(key, toPut);
if (removed != null) {
  removed.reset();
}

}


这里可以看到`activeResources.activate(key, resource)`把EngineResource放到了弱引用中,至于lru的放置逻辑如下:

*   EngineResource#release()

void release() {
if (acquired <= 0) {
throw new IllegalStateException(“Cannot release a recycled or not yet acquired resource”);
}
if (!Looper.getMainLooper().equals(Looper.myLooper())) {
throw new IllegalThreadStateException(“Must call release on the main thread”);
}
if (–acquired == 0) {
listener.onResourceReleased(key, this);
}
}


当acquired变量大于0的时候,说明图片正在使用中,也就应该放到activeResources弱引用缓存当中。而经过release()之后,如果acquired变量等于0了,说明图片已经不再被使用了,那么此时会调用listener的onResourceReleased()方法来释放资源。

*   Engine#onResourceReleased()

@Override
public void onResourceReleased(Key cacheKey, EngineResource<?> resource) {
Util.assertMainThread();
activeResources.deactivate(cacheKey);
if (resource.isCacheable()) {
cache.put(cacheKey, resource);
} else {
resourceRecycler.recycle(resource);
}
}


这里首先会将缓存图片从activeResources中移除,然后再将它put到LruResourceCache当中。这样也就实现了正在使用中的图片使用弱引用来进行缓存,不在使用中的图片使用LruCache来进行缓存的功能。

接下来就是Glide的磁盘缓存,磁盘缓存简单来说就是根据Key去DiskCache中取缓存,有兴趣可以自行看一下源码。

### 为什么选择Glide不选择其他的图片加载框架?

*   Glide和Picasso

前者要更加省内存,可以按需加载图片,默认为ARGB\_565,后者为ARGB\_8888。

前者支持Gif,后者并不支持。

*   Glide和Fresco

Fresco低版本有优势,占用部分native内存,但是高版本一样是java内存。

Fresco加载对图片大小有限制,Glide基本没有。

Fresco推荐使用SimpleDraweeView,涉及到布局文件,这就不得不考虑迁移的成本。

Fresco有很多native的实现,想改源码成本要大的多。

Glide提供对中TransFormation帮助处理图片,Fresco并没有。

Glide版本迭代相对较快。

### Glide的几个显著的优点:

*   生命周期的管理

GLide#with

@NonNull
public static RequestManager with(@NonNull Context context) {
return getRetriever(context).get(context);
}

@NonNull
public static RequestManager with(@NonNull Activity activity) {
return getRetriever(activity).get(activity);
}

@NonNull
public static RequestManager with(@NonNull FragmentActivity activity) {
return getRetriever(activity).get(activity);
}

@NonNull
public static RequestManager with(@NonNull Fragment fragment) {
return getRetriever(fragment.getActivity()).get(fragment);
}

@Deprecated
@NonNull
public static RequestManager with(@NonNull android.app.Fragment fragment) {
return getRetriever(fragment.getActivity()).get(fragment);
}


可以看到有多个重载方法,主要对两类不同的Context进行不同的处理

*   Application Context 图片加载的生命周期和应用程序一样,肯定是我们不推荐的写法。
*   其余Context,会像当前Activity创建一个隐藏的Fragment,绑定生命周期。

以Activity为例:

@NonNull
public RequestManager get(@NonNull Activity activity) {
if (Util.isOnBackgroundThread()) {
return get(activity.getApplicationContext());
} else {
//判断是否是销毁状态
assertNotDestroyed(activity);
android.app.FragmentManager fm = activity.getFragmentManager();
//绑定生命周期

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,以下是一个简单的指南针App的制作过程: 1. 首先,打开Android Studio并创建一个新项目。 2. 在MainActivity中创建一个CompassView类,用于绘制指南针。 3. 在CompassView类中,我们需要实现onDraw方法,用于绘制指南针。在这个方法中,我们需要使用Canvas和Path对象来绘制指南针的各个部分。 4. 在MainActivity中,我们需要获取传感器数据并更新指南针的方向。我们可以使用SensorManager和SensorEventListener来实现这一点。 5. 在onCreate方法中,我们需要注册SensorEventListener并启动传感器。 6. 在onResume方法中,我们需要重新注册SensorEventListener并恢复传感器。 7. 在onPause方法中,我们需要注销SensorEventListener并暂停传感器。 8. 最后,在AndroidManifest.xml文件中添加必要的权限。 下面是一个简单的示例代码: MainActivity.java: ``` public class MainActivity extends AppCompatActivity implements SensorEventListener { private CompassView compassView; private SensorManager sensorManager; private Sensor accelerometer; private Sensor magnetometer; private float[] gravity; private float[] geomagnetic; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); compassView = findViewById(R.id.compass); sensorManager = (SensorManager) getSystemService(SENSOR_SERVICE); accelerometer = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER); magnetometer = sensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD); gravity = new float[3]; geomagnetic = new float[3]; } @Override protected void onResume() { super.onResume(); sensorManager.registerListener(this, accelerometer, SensorManager.SENSOR_DELAY_UI); sensorManager.registerListener(this, magnetometer, SensorManager.SENSOR_DELAY_UI); } @Override protected void onPause() { super.onPause(); sensorManager.unregisterListener(this); } @Override public void onSensorChanged(SensorEvent event) { if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) { System.arraycopy(event.values, 0, gravity, 0, 3); } if (event.sensor.getType() == Sensor.TYPE_MAGNETIC_FIELD) { System.arraycopy(event.values, 0, geomagnetic, 0, 3); } float[] R = new float[9]; float[] I = new float[9]; boolean success = SensorManager.getRotationMatrix(R, I, gravity, geomagnetic); if (success) { float[] orientation = new float[3]; SensorManager.getOrientation(R, orientation); float azimuth = (float) Math.toDegrees(orientation[0]); compassView.setAzimuth(azimuth); } } @Override public void onAccuracyChanged(Sensor sensor, int accuracy) { } } ``` CompassView.java: ``` public class CompassView extends View { private static final float MAX_ROSE_ARC_DEGREE = 360f; private static final float MIN_ROSE_ARC_DEGREE = 10f; private static final float MAX_ROSE_ARC_DEGREE_HALF = MAX_ROSE_ARC_DEGREE / 2f; private static final float MIN_ROSE_ARC_DEGREE_HALF = MIN_ROSE_ARC_DEGREE / 2f; private float azimuth = 0f; public CompassView(Context context) { super(context); } public CompassView(Context context, @Nullable AttributeSet attrs) { super(context, attrs); } public CompassView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); float w = getWidth(); float h = getHeight(); float r = Math.min(w, h) / 2f; Paint paint = new Paint(); paint.setAntiAlias(true); paint.setTextSize(30f); paint.setTextAlign(Paint.Align.CENTER); //绘制方位线 float cx = w / 2f; float cy = h / 2f; paint.setColor(Color.parseColor("#FF0000")); canvas.drawLine(cx, 0f, cx, h, paint); canvas.drawLine(0f, cy, w, cy, paint); //绘制指南针 paint.setColor(Color.parseColor("#000000")); Path rosePath = new Path(); RectF rectF = new RectF(cx - r, cy - r, cx + r, cy + r); rosePath.addArc(rectF, MAX_ROSE_ARC_DEGREE_HALF + azimuth - MIN_ROSE_ARC_DEGREE_HALF, MIN_ROSE_ARC_DEGREE); rosePath.addArc(rectF, MAX_ROSE_ARC_DEGREE_HALF + azimuth + MIN_ROSE_ARC_DEGREE_HALF, MIN_ROSE_ARC_DEGREE); rosePath.addArc(rectF, MAX_ROSE_ARC_DEGREE_HALF + azimuth + MIN_ROSE_ARC_DEGREE_HALF * 3f, MIN_ROSE_ARC_DEGREE); rosePath.addArc(rectF, MAX_ROSE_ARC_DEGREE_HALF + azimuth + MIN_ROSE_ARC_DEGREE_HALF * 5f, MIN_ROSE_ARC_DEGREE); canvas.drawPath(rosePath, paint); //绘制方位文字 paint.setColor(Color.parseColor("#000000")); canvas.drawText("N", cx, cy - r + 30f, paint); canvas.drawText("S", cx, cy + r - 10f, paint); canvas.drawText("E", cx + r - 30f, cy, paint); canvas.drawText("W", cx - r + 30f, cy, paint); } public void setAzimuth(float azimuth) { this.azimuth = azimuth; invalidate(); } } ``` 在AndroidManifest.xml文件中添加必要的权限: ``` <uses-permission android:name="android.permission.INTERNET" /> ``` 最后,在activity_main.xml中添加CompassView组件: ``` <?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent"> <com.example.compass.CompassView android:id="@+id/compass" android:layout_width="match_parent" android:layout_height="match_parent" /> </RelativeLayout> ``` 这样就完成了一个简单的指南针App的制作。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值