Skip to content

Instantly share code, notes, and snippets.

@csshuai
Last active September 30, 2018 09:28
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save csshuai/9ccab646e35194eddafca9929cd9ad01 to your computer and use it in GitHub Desktop.
Save csshuai/9ccab646e35194eddafca9929cd9ad01 to your computer and use it in GitHub Desktop.
Use glide 4 to load apk file icon
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.support.annotation.Nullable;
import com.bumptech.glide.load.Options;
import com.bumptech.glide.load.ResourceDecoder;
import com.bumptech.glide.load.engine.Resource;
import com.bumptech.glide.load.resource.drawable.DrawableResource;
import com.bumptech.glide.util.Util;
import java.io.IOException;
class ApplicationIconDecoder implements ResourceDecoder<ApplicationInfo, Drawable> {
private final Context context;
public ApplicationIconDecoder(Context context) {
this.context = context;
}
@Nullable @Override
public Resource<Drawable> decode(ApplicationInfo source, int width, int height, Options options)
throws IOException {
Drawable icon = source.loadIcon(context.getPackageManager());
return new DrawableResource<Drawable>(icon) {
@Override public Class<Drawable> getResourceClass() {
return Drawable.class;
}
@Override public int getSize() { // best effort
if (drawable instanceof BitmapDrawable) {
return Util.getBitmapByteSize(((BitmapDrawable) drawable).getBitmap());
} else {
return 1;
}
}
@Override public void recycle() { /* not from our pool */ }
};
}
@Override public boolean handles(ApplicationInfo source, Options options) throws IOException {
return true;
}
}
import android.content.pm.ApplicationInfo;
import android.support.annotation.Nullable;
import com.bumptech.glide.Priority;
import com.bumptech.glide.load.DataSource;
import com.bumptech.glide.load.Options;
import com.bumptech.glide.load.data.DataFetcher;
import com.bumptech.glide.load.model.ModelLoader;
import com.bumptech.glide.signature.ObjectKey;
class ApplicationIconModelLoader implements ModelLoader<ApplicationInfo, ApplicationInfo> {
@Nullable @Override
public LoadData<ApplicationInfo> buildLoadData(final ApplicationInfo applicationInfo, int width,
int height, Options options) {
return new LoadData<>(new ObjectKey(applicationInfo), new DataFetcher<ApplicationInfo>() {
@Override
public void loadData(Priority priority, DataCallback<? super ApplicationInfo> callback) {
callback.onDataReady(applicationInfo);
}
@Override public void cleanup() {
}
@Override public void cancel() {
}
@Override public Class<ApplicationInfo> getDataClass() {
return ApplicationInfo.class;
}
@Override public DataSource getDataSource() {
return DataSource.LOCAL;
}
});
}
@Override public boolean handles(ApplicationInfo applicationInfo) {
return true;
}
}
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.graphics.drawable.Drawable;
import com.bumptech.glide.GlideBuilder;
import com.bumptech.glide.Registry;
import com.bumptech.glide.load.model.ModelLoader;
import com.bumptech.glide.load.model.ModelLoaderFactory;
import com.bumptech.glide.load.model.MultiModelLoaderFactory;
import com.bumptech.glide.module.GlideModule;
public class ApplicationIconModule implements GlideModule {
@Override public void applyOptions(Context context, GlideBuilder builder) {
// Do nothing.
}
@Override public void registerComponents(Context context, Registry registry) {
registry.append(ApplicationInfo.class, ApplicationInfo.class,
new ModelLoaderFactory<ApplicationInfo, ApplicationInfo>() {
@Override public ModelLoader<ApplicationInfo, ApplicationInfo> build(
MultiModelLoaderFactory multiFactory) {
return new ApplicationIconModelLoader();
}
@Override public void teardown() {
}
}).append(ApplicationInfo.class, Drawable.class, new ApplicationIconDecoder(context));
}
}
Glide.with(mActivity)
.load(getApplicationInfo(mActivity, pd.getInstalledPath()))
.apply(placeholderOf(R.drawable.ic_default_image).transform(mActivity,
new MultiTransformation<>(new CenterCrop(mActivity),
new RoundedCorners(mActivity, mImageCorner))))
.into(((DataHolder) holder).mIcon);
public static ApplicationInfo getApplicationInfo(Context context, String path) {
PackageManager pm = context.getPackageManager();
PackageInfo info = pm.getPackageArchiveInfo(path, PackageManager.GET_ACTIVITIES);
ApplicationInfo appInfo = null;
if (info != null) {
appInfo = info.applicationInfo;
appInfo.sourceDir = path;
appInfo.publicSourceDir = path;
}
return appInfo;
}
@asanChina
Copy link

Hi, your code seems still doing disk io in UI thread:

PackageInfo info = pm.getPackageArchiveInfo(path, PackageManager.GET_ACTIVITIES);

If you call function "getApplicationInfo(Context context, String path)" in main thread, then above line will definitely doing either disk io in main thread or doing some IPC in main thread. So, you need to rewrite your ModelLoader, make your ModelLoader accept a custom-scheme String (apkFIlePath), then in DataFecther, get the ApplicationInfo because DataFetcher.loadData(...) is guaranteed to be run in background thread, then use your ResourceDecoder to decode, return a Drawable.

@asanChina
Copy link

the example here bumptech/glide#1803 and here https://groups.google.com/forum/#!topic/glidelibrary/MAqPfuHpjr4 are doing the right thing.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment