Вызвать метод класса Activity из ViewHolder

223
12 октября 2017, 10:03

Имеем ReciclerView, на экране отображается список. Список обновляется каждые 5 сек. При нажатии на элемент списка, элемент расширяется (чтобы отобразить больше информации) или сужается обратно.

Проблема в том, что открытый элемент сужается из-за того, что таймер работает.

Мне нужно при расширении элемента остановить таймер(handler или runnable или как он там правильно называется), а при сужении снова запустить. Для этого я написал 2 метода в MainActivity - startRepeatingTask() и stopRepeatingTask(), но не знаю как получить к ним доступ из класса ViewHolder.

MainActivity.java

public class MainActivity  extends AppCompatActivity {
    RecyclerView recyclerView;
    RecyclerView.LayoutManager layoutManager;
    ConnectionItemAdapter adapter;
    List<ConnectionItem> connectionItems;
    Handler timerHandler;
    Runnable timerRunnable;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        InitRecyclerView();
        timerHandler = new Handler();
        timerRunnable = new Runnable() {
            @Override
            public void run() {
                //тут обновляется адаптер
                adapter.notifyDataSetChanged();
                timerHandler.postDelayed(this, 5000); //каждые 5 секунд
            }
        };
        timerHandler.postDelayed(timerRunnable, 5000);
    }
    void startRepeatingTask()
    {
        timerRunnable.run();
    }
    void stopRepeatingTask()
    {
        timerHandler.removeCallbacks(timerRunnable);
    }
}

ViewHolder.java

public class ConnectionItemsAdapterViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
    private boolean isViewExpanded = false;
    private int originalHeight = 0;
    public ConnectionItemsAdapterViewHolder(View itemView) {
        super(itemView);
        itemView.setOnClickListener(this);
        fcuName = (TextView)itemView.findViewById(R.id.FcuName);
        branchName = (TextView) itemView.findViewById(R.id.FcuBranchName);
        result = (TextView) itemView.findViewById(R.id.ResultText);
        versionIcon = (ImageView) itemView.findViewById(R.id.versionIcon);
        // If isViewExpanded == false then set the visibility
        // of whatever will be in the expanded to GONE
        if (isViewExpanded == false) {
            // Set Views to View.GONE and .setEnabled(false)
            branchName.setVisibility(View.GONE);
            branchName.setEnabled(false);
        }
    }
    public TextView fcuName;
    public TextView branchName;
    public ImageView versionIcon;
    public TextView result;
    @Override
    public void onClick(final View view) {
        // If the originalHeight is 0 then find the height of the View being used
        // This would be the height of the cardview
        if (originalHeight == 0) {
            originalHeight = view.getHeight();
        }
        // Declare a ValueAnimator object
        ValueAnimator valueAnimator;
        if (!isViewExpanded) {
            branchName.setVisibility(View.VISIBLE);
            branchName.setEnabled(true);
            isViewExpanded = true;
            // Вот где-то тут надо остановить таймер
            valueAnimator = ValueAnimator.ofInt(originalHeight, originalHeight + (int) (originalHeight * 2.0)); // These values in this method can be changed to expand however much you like
        } else {
            isViewExpanded = false;
            valueAnimator = ValueAnimator.ofInt(originalHeight + (int) (originalHeight * 2.0), originalHeight);
            Animation a = new AlphaAnimation(1.00f, 0.00f); // Fade out
            a.setDuration(200);
            // Set a listener to the animation and configure onAnimationEnd
            a.setAnimationListener(new Animation.AnimationListener() {
                @Override
                public void onAnimationStart(Animation animation) {
                }
                @Override
                public void onAnimationEnd(Animation animation) {
                    branchName.setVisibility(View.INVISIBLE);
                    branchName.setEnabled(false);
                }
                @Override
                public void onAnimationRepeat(Animation animation) {
                }
            });
            // Set the animation on the custom view
            branchName.startAnimation(a);
        }
        valueAnimator.setDuration(200);
        valueAnimator.setInterpolator(new AccelerateDecelerateInterpolator());
        valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            public void onAnimationUpdate(ValueAnimator animation) {
                Integer value = (Integer) animation.getAnimatedValue();
                view.getLayoutParams().height = value.intValue();
                view.requestLayout();
            }
        });
        valueAnimator.start();
    }
}

Только начал изучать android и java, возможно кто-то подскажет более правильный подход.

Answer 1

Правильный способ - прокинуть интерфейс через адаптер во ViewHolder.

  1. Создаём интерфейс
public interface MyInterface {
    void onClick();
}
  1. Передайте его в конструктор адаптера и инициализируйте им ссылку на него в адаптере:
public class MyAdapter extends .... {
    private MyInterface mMyInterface;
    public MyAdapter(MyInterface myInterface) {
        mMyInterface = myInterface;
    }
}
  1. Передавайте его также во ViewHolder при создании оного
public class ConnectionItemsAdapterViewHolder extends RecyclerView.ViewHolder {
    private MyInterface mMyInterface;
    public ConnectionItemsAdapterViewHolder(View itemView, MyInterface mMyInterface) {
        super(itemView);
        mMyInterface = myInterface;
    }
}
  1. В нужный момент вызовите его метод:
@Override
public void onClick(final View view) {
    mMyInterface.onClick();
}
  1. При создании адаптера в активити передайте реализацию интерфейса:
MyAdapter adapter = new MyAdapter(new MyInterface(){
    @Override
    public void onClick(){
        startRepeatingTask();
    }
})

А самый простой способ - кастануть контекст к активити как-то так:

//в классе ViewHolder
((MainActivity)itemView.getContext()).startRepeatingTask();
Answer 2

Все очень скучно и муторно:

  1. При создании адаптера RecyclerView в конструктор адаптера засылаем ссылку на ваш Activity
  2. При создании ViewHolder также в конструкторе засылаем из адаптера ссылку на Activity
  3. Bingo, теперь в холдере имеем Activity - в нужном месте вызываем методы Activity

Можно конечно реализовать идеологически выдержанный и православный паттерн через интерфейсы, но овчинка вряд ли стоит выделки.

READ ALSO
Найти совпадения в полях объектов

Найти совпадения в полях объектов

У меня есть List<Document> listOfDocuments = new ArrayList<>() объектов

182
Поиск по подстроке Hibernate

Поиск по подстроке Hibernate

Есть таблица c полем descriptionКак мне сделать поиск в таблице по этому полю так, чтоб выводились не только записи в которых description полностью совпадает...

278
Элемент вывода javafx

Элемент вывода javafx

Какой элемент нужно использовать для вывода информации пользователю? TextField использую в настоящее время, но он не подходит, так как позволяет...

207