从 ListView 中的 apk 文件加载许多图标

Posted

技术标签:

【中文标题】从 ListView 中的 apk 文件加载许多图标【英文标题】:Load many icon from apk files in ListView 【发布时间】:2018-05-15 19:06:44 【问题描述】:

我正在尝试将许多 apk 文件中的图标加载到列表视图中。

这是我的适配器类

public class Apk_Adapter extends BaseAdapter 
    private ArrayList<File> apk;
    private my_activity activity;
    public static ArrayList<Integer> selection=new ArrayList<>();
    public Adapter (my_activity  activity, ArrayList<File> list) 
        super();
        this.apk = list;
        this.activity = activity;
        selection.clear();
    

    @Override
    public int getCount() 
        return apk.size();
    

    @Override
    public String getItem(int position) 
        return String.valueOf(apk.get(position));
    

    @Override
    public long getItemId(int position) 

        return 0;
    

    public class ViewHolder 
        public ImageView apk_img;
        public TextView name;
        public TextView size;
        public CheckBox tick;
    

    @Override
    public View getView(final int position, View convertView, ViewGroup parent) 


        final ViewHolder view;


        LayoutInflater inflator = activity.getLayoutInflater();

        if (convertView == null) 


            view = new ViewHolder();

            convertView = inflator.inflate(R.layout.apk_adapter, null);

            view.apk_img = (ImageView) convertView.findViewById(R.id.img);
            view.size = (TextView) convertView.findViewById(R.id.size);
            view.name= (TextView) convertView.findViewById(R.id.name);
            view.tick= (CheckBox) convertView.findViewById(R.id.checkBox);

            convertView.setTag(view);
         else 
            view = (ViewHolder) convertView.getTag();
        
        view.tick.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() 
            @Override
            public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) 
               //DO SOMETHING
            
        );

        view.name.setText(apk.get(position).getName());
        view.size.setText(get_size(apk.get(position).length()));
        ByteArrayOutputStream stream = new ByteArrayOutputStream();
        get_apk_image(apk.get(position),activity.getApplication()).compress(Bitmap.CompressFormat.PNG, 100, stream);
        Glide.with(activity.getApplicationContext())
                .load(stream.toByteArray())
                .placeholder(R.drawable.apk)
                .centerCrop()
                .diskCacheStrategy(DiskCacheStrategy.RESULT)
                .thumbnail(0.5f)
                .into(view.apk_img);
        if (selection.contains(new Integer(position))) 
            view.tick.setChecked(true);
         else 

            view.tick.setChecked(false);
        
           return convertView;
    


    public Bitmap get_apk_image(File file,Context context)
    
        String filePath = file.getPath();
        PackageInfo packageInfo = context.getPackageManager().getPackageArchiveInfo(filePath, PackageManager.GET_ACTIVITIES);
        if(packageInfo != null) 
            ApplicationInfo appInfo = packageInfo.applicationInfo;
            if (Build.VERSION.SDK_INT >= 8) 
                appInfo.sourceDir = filePath;
                appInfo.publicSourceDir = filePath;
            
          final  Drawable icon = appInfo.loadIcon(context.getPackageManager());
            return ((BitmapDrawable) icon).getBitmap();

        
        return null;
    
    public double round(double value, int places) 
        if (places < 0) throw new IllegalArgumentException();
        BigDecimal bd = new BigDecimal(value);
        bd = bd.setScale(places, RoundingMode.HALF_UP);
        return bd.doubleValue();
    


    public String get_size(double bytes)
    
        if(bytes>(1024*1024*1024))
        
            return String.valueOf(round((bytes/(1024*1024*1024)),2)+"GB");
        
        else  if(bytes>(1024*1024))
        
            return String.valueOf(round((bytes/(1024*1024)),2)+"MB");
        
        else
        
            return String.valueOf(round((bytes/(1024)),2)+"KB");
        
    


但主要问题是,一旦我设置了适配器,所有图标图像都需要一些时间才能加载,然后手机就会挂起。

我尝试过使用 AsyncTask 但是 这是我得到的错误

Fatal Exception: java.util.concurrent.RejectedExecutionException
Task android.os.AsyncTask$3@16ffd1b rejected from java.util.concurrent.ThreadPoolExecutor@9af2eb8[Running, pool size = 9, active threads = 9, queued tasks = 128, completed tasks = 246]

我知道发生此错误是因为我同时在排队许多 AsyncTask。

我的应用程序有一个/两个以上的 AsyncTask(用于无法避免的不同目的)同时运行,因此我无法等待它们结束然后加载图标。

所以我必须使用下面的代码调用 AsyncTask 来执行。

task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR,path_to_icon);

任何人都可以帮助我顺利加载图标图像,而不会影响性能并且不会出现错误。

【问题讨论】:

【参考方案1】:

您可能需要使用Loader 类。

Loader API 可让您从内容提供商或其他 在 FragmentActivity 或 Fragment 中显示的数据源。如果你 不明白为什么你需要 Loader API 来执行这个看似 琐碎的操作,那么首先考虑一些你可能会遇到的问题 遇到没有装载机:

如果您直接在 Activity 或 Fragment 中获取数据,您的用户将因执行而缺乏响应 来自 UI 线程的查询可能会很慢。 如果您从另一个线程获取数据,可能使用 AsyncTask,那么您负责管理线程和 UI 线程 通过各种活动或片段生命周期事件,例如 onDestroy() 和配置更改。

装载机解决了这些问题并带来了其他好处。例如:

加载程序在单独的线程上运行,以防止 UI 出现卡顿或无响应。 加载程序通过在事件发生时提供回调方法来简化线程管理。 加载程序会在配置更改时保持并缓存结果,以防止重复查询。 加载器可以实现一个观察者来监控底层数据源的变化。例如,CursorLoader 自动 注册一个 ContentObserver 以在数据更改时触发重新加载。

还有一篇博文,您可能也会觉得有用:http://www.technotalkative.com/android-asynchronous-image-loading-in-listview/

【讨论】:

非常感谢您的回答。将尽快尝试更新您。 非常感谢您的出色解决方案。有什么我必须记住的,这样我才能防止任何错误。也很抱歉,由于我的声誉较低,我无法投票给答案。 该解决方案运行良好,但在设置适配器时提供了大约 1 秒的粗略体验。你能帮我解决这个问题吗?

以上是关于从 ListView 中的 apk 文件加载许多图标的主要内容,如果未能解决你的问题,请参考以下文章

如何从QML中的GridView或ListView获取实例化的委托组件

listview前几个item怎么不停加载

38.Android之ListView简单学习

使用matrixcursor加载带有缩略图的自定义ListView?但如何?

如何在 Blackberry 10 级联中为 ListView 加载 GroupDataModel 中的源数据?

主界面绘制加载轮播图减少apk体积( 简易音乐 五)