You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android SDK从28升级到32后GridView首次加载不显示问题

Android SDK 28升级至32后GridView首次加载不显示问题

代码已稳定运行十余年,将Android SDK从28升级至32后,应用首屏的GridView首次加载时无法显示。Item数量为预期的4个,代码已进入getView方法,但视图仍不显示;切换至其他页面后返回,GridView即可正常显示。SDK30及以上版本中GridView是否有变更?应用其余功能均正常。


相关代码

MainActivity 核心代码

public class MainActivity extends BaseActivity implements Constants {
    public GridView gridView;
    MainActivityAdapter adapter;

    private ArrayList<String> topicNames;
    private ArrayList<Integer> topicIconIds;
    private ArrayList<OnTouchListener> onClickListeners;

    @Override
    protected void onCreation(Bundle savedInstanceState) {
        setLayout(new MainLayout());
        try {
            configureUI();
        } catch (MyException exception) {
            exception.handleMe(this);
        }
        UIUtils.handleLastCrashIfAny(this);
    }


    private void configureUI() throws MyException {
        ((MainLayout) getBaseLayout()).configureUI();
        prepareList();
        Log.d("MainActivity", " creating mainlayout with topics=" + topicNames.stream().count());
        adapter = new MainActivityAdapter(this, topicNames, topicIconIds);
        gridView.setAdapter(adapter);
    }

    class MainActivityAdapter extends BaseAdapter {
        private final ArrayList<String> adapterTopicNames;
        private final ArrayList<Integer> adapterTopicIcondIds;

        public MainActivityAdapter(Activity activity, ArrayList<String> listTopic, ArrayList<Integer> listImage) {
            super();
            this.adapterTopicNames = listTopic;
            this.adapterTopicIcondIds = listImage;
        }

        @Override
        public int getCount() {
            return adapterTopicNames.size();
        }

        @Override
        public String getItem(int position) {
            return adapterTopicNames.get(position);
        }

        @Override
        public long getItemId(int position) {
            return 0;
        }

        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            ViewHolder view = null;
            if (convertView == null) {
                convertView = ((MainLayout) getBaseLayout()).getView();
            }
            view = (ViewHolder) convertView.getTag();

            // set image view parameters
            ((MainLayout) getBaseLayout()).setTopicImageParameters(view);

            view.textView.setText(adapterTopicNames.get(position).replace(" and ", " & "));
            view.imageView.setId(position);

            view.imageView.setImageResource(adapterTopicIcondIds.get(position));
            view.position = position;

            convertView.setId(position);
            view.imageView.setOnTouchListener(onClickListeners.get(position));
            return convertView;
        }
    }

    public ArrayList<String> getTopicNames() {
        return topicNames;
    }

    @Override
    protected void onRestart() {
        super.onRestart();
        adapter.notifyDataSetChanged();
        getBaseLayout().hideBuyFullVersionButtonIfNeeded();
        Log.d("MainActivity", "onRestart");

    }
}

MainLayout.configureUI 方法

public void configureUI() throws MyException {

    int landscapeRowsPortraitColumns = ApplicationDetails.getLandscapeRowCountPortraitColumnCount();
    int landscapeColumsPortraitRows = ApplicationDetails.getLandscapeColumnCountPortraitRowCount();

    if (activity.getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) {
        numberOfRows = landscapeColumsPortraitRows;
        numberOfColumns = landscapeRowsPortraitColumns;

    } else if (activity.getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE) {
        numberOfRows = landscapeRowsPortraitColumns;
        numberOfColumns = landscapeColumsPortraitRows;
    }

    gridView = new GridView(activity) {
        @Override
        protected void onLayout(boolean changed, int l, int t, int r, int b) {
            super.onLayout(changed, l, t, r, b);
            if (!areCellDimensionsCalculated) {
                getCellDimensions();
            }
        }
    };

    gridView.setVerticalSpacing(1);
    gridView.setHorizontalSpacing(1);
    gridView.setOverScrollMode(GridView.OVER_SCROLL_NEVER);
    gridView.setStretchMode(GridView.NO_STRETCH);
    gridView.setSelector(android.R.color.transparent);
    gridView.setBackgroundColor(ApplicationDetails.getMainScreenDividerColor());
    RelativeLayout.LayoutParams gridViewParams = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT,
            RelativeLayout.LayoutParams.MATCH_PARENT);
    gridViewParams.addRule(RelativeLayout.BELOW, navigationBar.getId());
    gridViewParams.addRule(RelativeLayout.ABOVE, footerBar.getId());
    contentView.addView(gridView, gridViewParams);

    ((MainActivity) activity).gridView = gridView;

}

问题分析与解决方案

1. 视图布局计算时机不匹配(SDK30+绘制逻辑调整)

从Android 11(SDK30)开始,系统对视图布局调度做了优化,你重写的GridView.onLayout中计算单元格尺寸的逻辑,可能在首次加载时未及时完成,导致Item因尺寸未确定而无法显示。

解决:
在getCellDimensions方法执行完毕后,立即调用gridView.requestLayout()或adapter.notifyDataSetChanged(),强制触发GridView重新测量和绘制。

2. Adapter的View复用逻辑存在漏洞

当前getView方法中,首次创建convertView时未绑定ViewHolder到Tag,导致view = (ViewHolder) convertView.getTag()可能返回null,后续控件赋值操作无效(虽然代码进入了getView,但实际视图未正确渲染)。

解决:
修正getView中的ViewHolder绑定逻辑:

@Override
public View getView(int position, View convertView, ViewGroup parent) {
    ViewHolder view;
    if (convertView == null) {
        convertView = ((MainLayout) getBaseLayout()).getView();
        view = new ViewHolder();
        // 这里必须初始化view.textView、view.imageView等控件,比如:
        // view.textView = convertView.findViewById(R.id.topic_text);
        // view.imageView = convertView.findViewById(R.id.topic_icon);
        convertView.setTag(view);
    } else {
        view = (ViewHolder) convertView.getTag();
    }

    // 后续设置数据的逻辑不变
    ((MainLayout) getBaseLayout()).setTopicImageParameters(view);
    view.textView.setText(adapterTopicNames.get(position).replace(" and ", " & "));
    view.imageView.setId(position);
    view.imageView.setImageResource(adapterTopicIcondIds.get(position));
    view.position = position;
    convertView.setId(position);
    view.imageView.setOnTouchListener(onClickListeners.get(position));
    
    return convertView;
}

3. 首次加载时数据通知时机过早

设置Adapter的操作可能在GridView完成布局前执行,导致系统未触发绘制。

解决:
在configureUI中设置Adapter后,通过post延迟通知数据变更:

private void configureUI() throws MyException {
    ((MainLayout) getBaseLayout()).configureUI();
    prepareList();
    Log.d("MainActivity", " creating mainlayout with topics=" + topicNames.stream().count());
    adapter = new MainActivityAdapter(this, topicNames, topicIconIds);
    gridView.setAdapter(adapter);
    // 延迟触发绘制
    gridView.post(() -> adapter.notifyDataSetChanged());
}

4. StretchMode设置导致尺寸计算异常

你设置了GridView.NO_STRETCH,在SDK30+中,这种模式下如果未明确指定列宽,GridView可能无法正确计算Item的显示空间。

解决:
尝试修改StretchMode为GridView.STRETCH_COLUMN_WIDTH,或者主动设置列宽:

gridView.setStretchMode(GridView.STRETCH_COLUMN_WIDTH);
// 或者根据计算的单元格尺寸设置列宽
gridView.setColumnWidth(calculatedCellWidth);

内容的提问来源于stack exchange,提问作者nirav dinmali

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.16 22:05:40