【问题标题】:Recycling views shows same item multiple times回收视图多次显示同一项目
【发布时间】:2013-07-30 04:59:57
【问题描述】:

我有一个显示设备上安装的所有应用程序的网格视图。

每当我尝试回收项目(使用 convertView == null 等)时,相同的图标和文本会在我的网格中多次显示。

这是我的代码:

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

    ImageView imageView;
    TextView txtName;
    FrameLayout layout;
//        if (convertView == null) {
        imageView = new ImageView(myContext);
        imageView.setLayoutParams(new GridView.LayoutParams(230, 230));
        imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
        imageView.setPadding(4, 4, 4, 4);

        txtName = new TextView(myContext);
        RelativeLayout.LayoutParams relativeParams = new RelativeLayout.LayoutParams(LayoutParams.FILL_PARENT,
                LayoutParams.FILL_PARENT);
        relativeParams.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM);
        txtName.setLayoutParams(relativeParams);
        txtName.setGravity(Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL);
        // txtName.setPadding(8, 8, 8, 8);

        layout = new FrameLayout(myContext);
        // FrameLayout.LayoutParams layoutparams = new
        // FrameLayout.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT,
        // ViewGroup.LayoutParams.FILL_PARENT, Gravity.CENTER_HORIZONTAL |
        // Gravity.CENTER_VERTICAL);
        // layout.setLayoutParams(layoutparams);

        RelativeLayout layout2 = new RelativeLayout(myContext);

        layout.addView(imageView);
        layout.addView(layout2);
        layout2.addView(txtName);

        ResolveInfo resolveInfo = MyAppList.get(position);
        imageView.setImageDrawable(resolveInfo.loadIcon(myPackageManager));
        txtName.setText(resolveInfo.loadLabel(myPackageManager));

//        } else {
//            layout = (FrameLayout) convertView;
//        }

    return layout;

}

如果我不回收它们,它们会正确显示,但 gridview 很慢。

我的第二个问题是:如何将文本放在网格视图内的图标下?就像在原生 Android 启动器中一样?

这是我的 GridActivity:

public class AppListActivity extends Activity {

PackageManager myPackageManager;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    myPackageManager = getPackageManager();

    Intent intent = new Intent(Intent.ACTION_MAIN, null);
    intent.addCategory(Intent.CATEGORY_LAUNCHER);
    List<ResolveInfo> appIntentList = getPackageManager()
            .queryIntentActivities(intent, 0);

    GridView gridview = new GridView(this);
    gridview.setStretchMode(GridView.STRETCH_COLUMN_WIDTH);
    gridview.setNumColumns(4);
    gridview.setHorizontalSpacing(30);
    gridview.setVerticalSpacing(30);
    gridview.setBackgroundColor(getResources().getColor(android.R.color.black));
    gridview.setGravity(Gravity.CENTER);
    gridview.setColumnWidth(60);
    gridview.setPadding(10, 10, 10, 10);

    gridview.setAdapter(new MyAdapter(this, appIntentList));

    gridview.setOnItemClickListener(new OnItemClickListener() {

        @Override
        public void onItemClick(AdapterView<?> parent, View view,
                int position, long id) {
            ResolveInfo cleckedResolveInfo = (ResolveInfo) parent
                    .getItemAtPosition(position);
            ActivityInfo clickedActivityInfo = cleckedResolveInfo.activityInfo;

            Intent intent = new Intent(Intent.ACTION_MAIN);
            intent.addCategory(Intent.CATEGORY_LAUNCHER);
            intent.setClassName(
                    clickedActivityInfo.applicationInfo.packageName,
                    clickedActivityInfo.name);
            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
                    | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
            startActivity(intent);
        }

    });

    setContentView(gridview);
}
}

【问题讨论】:

    标签: android android-view android-gridview android-launcher recycle


    【解决方案1】:

    好吧,您需要将列表项的数据填充移到列表项设置之外。比如:

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
    
        ImageView imageView;
        TextView txtName;
        RelativeLayout layout;
        if (convertView == null) {
            imageView = new ImageView(myContext);
            imageView.setLayoutParams(new GridView.LayoutParams(230, 230));
            imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
            imageView.setPadding(4, 4, 4, 4);
            generateAndSetViewId(imageView);
    
            txtName = new TextView(myContext);
            RelativeLayout.LayoutParams relativeParams = new RelativeLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
            relativeParams.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM);
            relativeParams.addRule(RelativeLayout.BELOW, imageView.getId());
            txtName.setLayoutParams(relativeParams);
            txtName.setGravity(Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL);
            // txtName.setPadding(8, 8, 8, 8);
    
            layout = new RelativeLayout(myContext);
            // FrameLayout.LayoutParams layoutparams = new
            // FrameLayout.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT,
            // ViewGroup.LayoutParams.FILL_PARENT, Gravity.CENTER_HORIZONTAL |
            // Gravity.CENTER_VERTICAL);
            // layout.setLayoutParams(layoutparams);
    
            layout.addView(imageView);
            layout.addView(txtName);
    
        } else {
            layout = (RelativeLayout) convertView;
            imageView = (ImageView) layout.getChildAt(0);
            txtName = (TextView) layout.getChildAt(1);
        }
    
        ResolveInfo resolveInfo = MyAppList.get(position);
        imageView.setImageDrawable(resolveInfo.loadIcon(myPackageManager));
        txtName.setText(resolveInfo.loadLabel(myPackageManager));
    
        return layout;
    
    }
    
    private static final AtomicInteger sNextGeneratedId = new AtomicInteger(1);
    
    @SuppressLint("NewApi")
    public static int generateAndSetViewId(View view) {
        int viewID = -1;
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
            viewID = View.generateViewId();
        } else {
            while (true) {
                final int result = sNextGeneratedId.get();
                // aapt-generated IDs have the high byte nonzero; clamp to the range under that.
                int newValue = result + 1;
                if (newValue > 0x00FFFFFF) {
                    newValue = 1; // Roll over to 1, not 0.
                }
                if (sNextGeneratedId.compareAndSet(result, newValue)) {
                    viewID = result;
                    break;
                }
            }
        }
        view.setId(viewID);
        return viewID;
    }
    

    如果您从 XML 中扩展视图而不是动态创建视图,则可以大大简化上述代码。

    【讨论】:

    • 非常感谢。不幸的是,我目前无法在 xml 中创建它们。你也有文本问题的解决方案吗?
    • 你能贴出这句话的截图吗? Text shows up multiple times in my grid。可能有助于解决问题......文本应该每个项目显示一次。那是根据你的代码。
    • 不,这实际上与您的解决方案非常吻合。剩下的问题是:如何将文本放在网格视图内的图标下?就像在原生 Android 启动器中一样?非常感谢:)
    • 好吧,你需要稍微改变你的布局,因为FrameLayout 把它的子元素放在另一个上面。我已经编辑了我的答案,以便将根布局更改为RelativeLayout。或者您可以将其更改为具有垂直方向的LinearLayout。实际上LinearLayout 会更合适,因为您不需要我添加的代码来生成imageView id。我总是倾向于使用 RelativeLayouts ...
    • 非常感谢!这比我的解决方案好得多:)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-09-11
    • 2016-08-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多