片段活动捕获 onKeyDown 并在片段中使用
Posted
技术标签:
【中文标题】片段活动捕获 onKeyDown 并在片段中使用【英文标题】:Fragment activity catch onKeyDown and use in fragment 【发布时间】:2012-08-26 00:13:48 【问题描述】:我有寻呼机的片段活动:
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 类中引发按键事件时调用此方法。例如:
@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);
【讨论】:
@JonWillis 随时提供更好的解决方案 其实你可以使用接口、LocalBroadcast 或者只使用 EventBus 并使用它发送 KeyEvent 给任何想要它的人。fragments
是什么意思,你在哪里声明的?
@JonWillis,他们为什么不应该通过紧耦合?任何活动都只能使用它设计的那些片段。并且只有父活动知道显示哪些片段并且应该接收事件此外,我会将其移至 BaseFragment 和 BaseActivity 作为整个项目的默认行为。还应该使myOnKeyDown
具有相同的签名,尤其是返回布尔值以判断是否处理了事件
@JonWillis,Activity 也应该知道是否处理了事件。当您可以触发并忘记并且不在乎谁将获得事件时,EventBus 和仪器都很好,但事实并非如此【参考方案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();
;
你的 keyevent - 放入活动的代码
@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):
广播
使用 android 的 LocalBroadcastManager:Documentation
创建一个广播接收器:
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
创建一个事件类:
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】:按照@hsu.tw 的回答以避免紧密耦合,我发现了这个gist。
避免紧密耦合是有代价的:你需要一个可聚焦的视图(幸运的是,我的情况就是这样,因为我已经在前台有一个可以监听其他触摸事件的视图,所以我只是在其中添加了View.OnKeyListener
)。
将View.OnKeyListener
附加到独立于活动的片段中的视图所需的步骤是(检查gist):
view.setFocusableInTouchMode(true);
view.requestFocus();
view.setOnKeyListener(pressKeyListener);
我在 Fragment 的 onViewCreated
回调中实现了这一点
【讨论】:
onViewCreated?这似乎更有意义。【参考方案5】:我对 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();
要点:https://gist.github.com/0neel/7d1ed5d26f2148b4168b6616337159ed
【讨论】:
【参考方案6】:我在开发 Android TV 应用时遇到了同样的问题。
我这样解决这个问题:
在 onCreateView 方法中,我通过某个 View 调用“requestFocus”。 (我将其标记为 ViewA。) 然后我将 KeyEventListener 设置为 ViewA。
在您的情况下,您应该在 Adapter 和 PagerChangeListener 中执行 (set-KeyEventListener)。
【讨论】:
以上是关于片段活动捕获 onKeyDown 并在片段中使用的主要内容,如果未能解决你的问题,请参考以下文章
Android 从片段中检索 Json 并在另一个活动中使用