Search code examples
androidandroid-activityandroid-viewandroid-tv

Focus is Getting Lost on adapter.notifyArrayItemRangeChanged


In my Android TV app, the action button in the ActionsRow loses focus on

adapter.notifyArrayItemRangeChanged(0, 1);

call. I am using:

View focusedView = getActivity().getCurrentFocus();

to get the focused view, but cannot set the focus back on after notifyArrayItemRangeChanged. The button with the focus before notifyArrayItemRangeChanged loses focus, and I can't make that button requestFocus in (or after) onBindViewHolder of the ActionPresenter or in onBindRowViewHolder of ActionsRowPresenter... The focus is set to the first button every time after notifyArrayItemRangeChanged.

Any ideas how to retain focus or how to set it back to the original view?

ActionPresenter:

@Override
public void onBindViewHolder(Presenter.ViewHolder viewHolder, Object item) {
    Log.i(TAG, "onBindViewHolder called, item:" + item.toString());
    Action action = (Action) item;
    ActionViewHolder vh = (ActionViewHolder) viewHolder;
    vh.mAction = action;
    vh.mButton.setText(action.getLabel1());
    vh.mButton.setTag(action.getId());

    vh.mButton.requestFocus();
}

ActionsRowPresenter:

protected void onBindRowViewHolder(ActionsRowPresenter.ViewHolder holder, Object item) {
    super.onBindRowViewHolder(holder, item);
    Log.i(TAG, "onBindRowViewHolder called");

    ViewHolder vh = holder;
    ActionsRow row = (ActionsRow) vh.getRow();

    ArrayObjectAdapter aoa = new ArrayObjectAdapter(mActionPresenter);
    aoa.addAll(0, (Collection)row.getActions());
    vh.bind(aoa);
}

NowPlayingChannelRowPresenter:

public NowPlayingChannelRowPresenter(Channel c) {
    setHeaderPresenter(null);
    setSelectEffectEnabled(false);

    mSelectedChannel = c;

    npcdrPresenter = new NowPlayingChannelDetailsRowPresenter(new DetailsDescriptionPresenter());
    actionsRowPresenter = new ActionsRowPresenter();

    ClassPresenterSelector ps = new ClassPresenterSelector();

    ps.addClassPresenter(NowPlayingChannelDetailsRow.class, npcdrPresenter);
    ps.addClassPresenter(ActionsRow.class, actionsRowPresenter);

    npcdRow = new NowPlayingChannelDetailsRow(mSelectedChannel);

    actionsRow = new ActionsRow(mSelectedChannel);

    actionsRow.addAction(new Action(ACTION_START_STOP, "Stop"));
    actionsRow.addAction(new Action(ACTION_ADD_REMOVE_FAVORITE, "Add to Favorites"));

}


@Override
protected RowPresenter.ViewHolder createRowViewHolder(ViewGroup parent) {
    View v = LayoutInflater.from(parent.getContext())
            .inflate(R.layout.now_playing_channel_row, parent, false);
    ViewHolder vh = new ViewHolder(v);

    vh.mNpcdVh = (NowPlayingChannelDetailsRowPresenter.ViewHolder) npcdrPresenter.onCreateViewHolder(vh.llNpcd);
    vh.llNpcd.addView(vh.mNpcdVh.view);

    vh.mActionsVh = (ActionsRowPresenter.ViewHolder) actionsRowPresenter.onCreateViewHolder(vh.llActions);
    vh.llActions.addView(vh.mActionsVh.view);

    return vh;
}


@Override
protected void onBindRowViewHolder(RowPresenter.ViewHolder holder, Object item) {
    super.onBindRowViewHolder(holder, item);

    ViewHolder vh = (ViewHolder) holder;
    npcdrPresenter.onBindRowViewHolder(vh.mNpcdVh, npcdRow);
    actionsRowPresenter.onBindRowViewHolder(vh.mActionsVh, actionsRow);

}

Edit 1: There's no ListView, I am using an ArrayObjectAdapter instance with custom presenters

Edit 2: I attached the layout view (Hiearchy View).

enter image description here


Solution

  • This should get called only for the item that needs to be focussed

    vh.mButton.requestFocus();

    If you notify the adapter just for the first item in the ActionPresenter, onBindViewHolder will be called just for the first item and it will get the focus.

    If it is the second item that needs to be focussed, ActionPresenter's onBindViewHolder should get called for that item and you should request focus only for the second item and not all items.