Фрагментная активность catch onKeyDown и использование в фрагменте
У меня есть функция фрагментации с пейджером:
List<Fragment> fragments = new Vector<Fragment>();
fragments.add(Fragment.instantiate(this, PastEventListFragment.class.getName(),bundle));
fragments.add(Fragment.instantiate(this, EventListFragment.class.getName(),bundle));
this.mPagerAdapter = new EventPagerAdapter(super.getSupportFragmentManager(), fragments);
//
ViewPager pager = (ViewPager)super.findViewById(R.id.viewpager1);
pager.setAdapter(this.mPagerAdapter);
pager.setCurrentItem(1);
Я поймаю событие onKeyDown:
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_MENU) {
}
return super.onKeyDown(keyCode, event);
}
Вопрос:
Как использовать событие во всех фрагментах, которые я создал в этой операции. Благодаря
Ответы
Ответ 1
Что вы можете сделать, так это определить собственный метод в классе (-ах). Например:
public void myOnKeyDown(int key_code){
//do whatever you want here
}
и вызывать этот метод всякий раз, когда в вашем классе Activity поднимается событие "key-down". Например:
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_MENU) {
((PastEventListFragment)fragments.get(0)).myOnKeyDown(keyCode);
((EventListFragment)fragments.get(1)).myOnKeyDown(keyCode);
//and so on...
}
return super.onKeyDown(keyCode, event);
}
Ответ 2
Если кто-то поинтересовался, как это сделать с помощью Boradcast:
В вашем фрагменте в onViewCreated
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
// Register to receive messages.
// We are registering an observer (mMessageReceiver) to receive Intents
// with actions named "custom-event-name".
LocalBroadcastManager.getInstance(this).registerReceiver(mMessageReceiver,
new IntentFilter("activity-says-hi"));
...}
// Our handler for received Intents. This will be called whenever an Intent
// with an action named "custom-event-name" is broadcasted.
private BroadcastReceiver mMessageReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
// Get extra data included in the Intent
doSomethingCauseVolumeKeyPressed();
}
};
ваш ключ - код для ввода в действие
@Override
public boolean dispatchKeyEvent(KeyEvent event) {
int action = event.getAction();
int keyCode = event.getKeyCode();
switch (keyCode) {
case KeyEvent.KEYCODE_VOLUME_UP:
if (action == KeyEvent.ACTION_DOWN) {
sendBroadcast();
}
return true;
case KeyEvent.KEYCODE_VOLUME_DOWN:
if (action == KeyEvent.ACTION_DOWN) {
sendBroadcast();
}
return true;
default:
return super.dispatchKeyEvent(event);
}
}
ваш отправитель трансляции:
private void sendVolumeBroadcast(){
Intent intent = new Intent("activity-says-hi");
LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
}
Ответ 3
Как упоминалось другими, принятый ответ приводит к плотной связи между активностью и ее фрагментами.
Вместо этого я бы предложил использовать какую-то реализацию на основе событий. Это гораздо более многоразовое и приводит к лучшей архитектуре программного обеспечения. В предыдущих проектах я использовал одно из следующих решений (Kotlin):
Трансляции
Использование LocalBroadcastManager для Android: документация
Создайте BroadcastReceiver:
class SomeBroadcastReceiver : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) {
val keyCode = intent?.getIntExtra("KEY_CODE", 0)
// Do something with the event
}
}
В вашей деятельности:
class SomeActivity : AppCompatActivity() {
override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean {
val intent = Intent("SOME_TAG").apply { putExtra("KEY_CODE", keyCode) }
LocalBroadcastManager.getInstance(this).sendBroadcast(intent)
return super.onKeyDown(keyCode, event)
}
}
Затем в любом фрагменте (или услугах и т.д.):
class SomeFragment : Fragment() {
val receiver = SomeBroadcastReceiver()
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
val filter = IntentFilter().apply { addAction("SOME_TAG") }
LocalBroadcastManager.getInstance(context!!).registerReceiver(receiver, filter)
return super.onCreateView(inflater, container, savedInstanceState)
}
}
EventBus
Использование EventBus
Создать класс события:
data class Event(val keyCode: Int)
В вашей деятельности:
class SomeActivity : AppCompatActivity() {
override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean {
EventBus.getDefault().post(Event(keyCode))
return super.onKeyDown(keyCode, event)
}
}
Затем в вашем фрагменте:
class SomeFragment : Fragment() {
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
// Register for events
EventBus.getDefault().register(this)
return super.onCreateView(inflater, container, savedInstanceState)
}
@Subscribe
public fun onKeyEvent(event : Event) {
// Called by eventBus when an event occurs
}
override fun onDestroyView() {
super.onDestroyView()
EventBus.getDefault().unregister(this)
}
}
Ответ 4
Я выполняю подклассы классов Activity и Fragment для выполнения передачи KeyEvents. Для меня это выглядит яснее, чем отправка локальных трансляций. Но это решение может быть не столь гибким. Выберите предпочтительный вариант самостоятельно.
Вот активность:
public abstract class KeyEventPassingActivity extends Activity {
public interface KeyEventListener extends View.OnKeyListener {
boolean isVisible();
View getView();
}
private final List<KeyEventListener> keyEventHandlerList = new ArrayList<>();
@Override
public boolean dispatchKeyEvent(KeyEvent event) {
for (KeyEventListener handler : keyEventHandlerList) {
if (handleKeyEvent(handler, event)) {
return true;
}
}
return super.dispatchKeyEvent(event);
}
void addKeyEventHandler(@NonNull KeyEventListener handler) {
keyEventHandlerList.add(handler);
}
void removeKeyEventHandler(@NonNull KeyEventListener handler) {
keyEventHandlerList.remove(handler);
}
/**
* @return <tt>true</tt> if the event was handled, <tt>false</tt> otherwise
*/
private boolean handleKeyEvent(@Nullable KeyEventListener listener, KeyEvent event) {
return listener != null
&& listener.isVisible()
&& listener.onKey(listener.getView(), event.getKeyCode(), event);
}
}
И фрагмент:
public abstract class KeyEventHandlingFragment extends Fragment
implements KeyEventPassingActivity.KeyEventListener {
@SuppressWarnings("deprecation")
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
if (activity instanceof KeyEventPassingActivity) {
((KeyEventPassingActivity) activity).addKeyEventHandler(this);
}
}
@Override
public void onDetach() {
Activity activity = getActivity();
if (activity instanceof KeyEventPassingActivity) {
((KeyEventPassingActivity) activity).removeKeyEventHandler(this);
}
super.onDetach();
}
}
Gist: https://gist.github.com/0neel/7d1ed5d26f2148b4168b6616337159ed
Ответ 5
У меня та же проблема при разработке приложения для Android TV.
И я решаю эту проблему следующим образом:
В методе onCreateView я вызываю "requestFocus" некоторыми View. (Я отмечаю его как ViewA.) Затем я устанавливаю KeyEventListener в ViewA.
В вашем случае вы должны сделать это (set-KeyEventListener) в Adapter и PagerChangeListener.