How to check if Fragment implements an interface - android

In my main Activity I've set up a interface CentreKeyPress, and I have 4 Fragments in a ViewPager, and a few of them implement this, a few don't. The interface has an onBack method, for when the back button is pressed. Here's my current code
#Override
public boolean onKeyUp(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK) {
ViewPager pager = (ViewPager)findViewById(R.id.contact_view_pager);
List<Fragment> frags = adapter.getFragments();
try {
((CentreKeyPress) frags.get(pager.getCurrentItem())).onBack();
return true;
} catch (Exception e) {
e.printStackTrace();
}
}
return super.onKeyUp(keyCode, event);
}
Is a try/catch loop the best way to check if a Fragment implements the interface, or is there some kind of method that I can use to check if it implements it? Or, alternatively, could my Fragment handle onKeyUp themselves?

Try to use keyword INSTANCEOF and check if fragments are instance of interface
you can check this to: use of "Instance of" in java

Check whether fragment is a instanceof the given fragment
if(frags.get(pager.getCurrentItem()) instanceof CentreKeyPress){
//fragment implements CentreKeyPress
}

Related

Can I override/handle keyDown in fragment without put into Activity?

I have a fragment that's in an AAR, and the main activity that holds this fragment is in another APK depending on this AAR.
I could override the handleKeyDown() in the activity, but is there any way that I can directly override/handle the keyDown in the fragment since there're multiple fragments for this activity.
p.s. I need to capture all sorts of keyevent e.g. up, down, left & right, not only back button.
Also I tried to implement KeyEvent.Callback but it's not catching any keyevent when I navigate thru UI.
Step1: Create a custom interface, let's say KeyEventListener
public interface MyKeyEventListener {
boolean onKeyDown(int keyCode, KeyEvent event);
}
Step2: Add field currentFragment in Activity, which will be updated whenever you switch fragment. Basically it will hold the currently visible fragment
Fragment currentFragment;
currentFragment = here getCurrentFragment() etc;
Step3: Implement MyKeyEventListener in your fragments. You can skip interface implementation in any fragment
public class Fragment1 implements MyKeyEventListener {
#Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
//do whatever you want in onKeyDown
}
}
Step4: Override onKeyDown in your Activity
#Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if(currentFragment != null && currentFragment instanceof MyKeyEventListener) {
((MyKeyEventListener) currentFragment).onKeyDown(keyCode, event);
return true;
}
return super.onKeyDown(keyCode, event);
}

Fragment hardware back button event called twice

I am trying to implement back navigation through my fragments which are called in specific order: A->B->C and by going back with hardware button I would like them to remain order.
I am using fragmenttransaction.replace in order to switch fragment with no addToBackStack because it made my ActionBarMenu to misbehave.
Problem is that when I am on fragment C back button is going back directly to A. I found out that it is because click event is executed twice I am going to B and directly to A.
#Override
public void onViewCreated(View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
setOnBackButtonPresed();
}
private void setOnBackButtonPresed() {
getView().setFocusableInTouchMode(true);
getView().requestFocus();
getView().setOnKeyListener( new View.OnKeyListener()
{
#Override
public boolean onKey( View v, int keyCode, KeyEvent event )
{
if( keyCode == KeyEvent.KEYCODE_BACK )
{
goBackToDays();
return false;
}
return false;
}
} );
}
private void goBackToDays() {
Log.e("fragmentC", "executing on back action")
}
logcat result:
03-15 08:37:17.353 21245-21245/com.test E/fragmentC: executing on back action
03-15 08:37:17.390 21245-21245/com.test E/fragmentC: executing on back action
Can anyone give me a hint how I can avoide twice button events?
I think "click event is executed twice" because you call both event ACTION_DOWN and ACTION_UP. Try this
#Override
public boolean onKey( View v, int keyCode, KeyEvent event )
{
if( keyCode == KeyEvent.KEYCODE_BACK && event.getAction()== KeyEvent.ACTION_DOWN)
{
goBackToDays();
return false;
}
return false;
}
2 things:
Even though you're replacing fragments, the old OnKeyListener stays there (and get's fired up later on). Try removing the old OnKeyListener on switching fragments.
Just as S-lightning pointed out, you need to bare in mind that there are two actions associated with a key event (KeyEvent.ACTION_DOWN and KeyEvent.ACTION_UP).
You can do two things
"it made my ActionBarMenu to misbehave." FIX this issue.
Override onBackPressed() on your Activity and find find out your current loaded fragment and replace with whichever you want.
Fragment fragment = getSupportFragmentManager().findFragmentById(R.id.your_view_container);
if (fragment instanceof FragmentThree) {
//replace with your fragment ie. FragmentTwo
} else if (fragment instanceof FragmentTwo) {
//replace with your fragment ie. FragmentOne
}
Return true if you want to "absorb" the key event and stop it from propagating up to the Activity, which has its own onBackPressed() implementation.
if( keyCode == KeyEvent.KEYCODE_BACK )
{
goBackToDays();
return true; // <-- should be TRUE, not FALSE
}
return false;
Override the onBackPressed() method in hosting activity.
do like this.
private void replaceFragment (Fragment fragment){
String backStateName = fragment.getClass().getName();
FragmentManager manager = getSupportFragmentManager();
boolean fragmentPopped = manager.popBackStackImmediate(backStateName, 0);
if (!fragmentPopped){ //fragment not in back stack, create it.
FragmentTransaction ft = manager.beginTransaction();
ft.replace(R.id.content_frame, fragment);
ft.addToBackStack(backStateName);
ft.commit();
}
}
.
.
#Override
public void onBackPressed(){
if (getSupportFragmentManager().getBackStackEntryCount() == 1){
finish();
}
else {
super.onBackPressed();
}
}
Here is the well explained answer. link

Execute method in fragment before ad it to backstack

I have multiple fragments and I can switch between them, my problem is on how can I execute a method in a fragment before it goes to backstack.
If I execute some method in fragment's OnPause() or OnStop() my activity is closing with all fragments instantly. The code to switch from one fragment to another is:
public void switchFrgFromFrg(Fragment fragment, String tag, boolean isAddedToBackStack, int idContainer) {
FragmentTransaction fragmentTransaction = getFragmentManager().beginTransaction();
fragmentTransaction.replace(idContainer, fragment, tag);
if (isAddedToBackStack) {
fragmentTransaction.addToBackStack(tag);
}
fragmentTransaction.commit();
}
Any help is apreciated.
Your fragment onResume() and onPause() will be called only when the Activity onResume() or onPause() that holds it is called. They are tightly coupled to the Activity, that's why your fragment is closing. I sugest you ti implement a back key listener as:
private void doBackActionListener(View view){
view.setFocusableInTouchMode(true);
view.requestFocus();
view.setOnKeyListener(new View.OnKeyListener() {
#Override
public boolean onKey(View v, int keyCode, KeyEvent event) {
if (event.getAction() == KeyEvent.ACTION_DOWN) {
if (keyCode == KeyEvent.KEYCODE_BACK) {
//execute code
//then do standart go back action
getActivity().onBackPressed();
return true;
}
}
return false;
}
});
}
You will cal this in your onCreateView() and pass inflated view as parameter.
how can I execute a method in a fragment before it goes to backstack
When you fragment is visible you can execute as many methods as you want
If I execute some method in fragment's OnPause() or OnStop() my activity is closing with all fragments instantly.
That's because some Exception is arising in your code. It is better to show your console (Log messages) in your question.

Controlling Back Button in a non Activity class?

I have an Actionbar app with fragments and a TabFragment extends Fragment class, where I customize the functionality of my fragments.
I want to be able to control what the back button does.
#Overriding onBackPressed()
won't work because I am not in an Activity,
nor will
#Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if ((keyCode == KeyEvent.KEYCODE_BACK)) {
//my code here
}
return super.onKeyDown(keyCode, event);
}
My goal is to hide some specific Views when I press back based on true/false value of a boolean variable. Any suggestions on how I might be able to manipulate this functionality? Thanks!
I had the same problem as you, but I realized that you had to deal with the back button in the activity where you are running your fragments from. You need to override the onBackPressed() in the activity code, not inside the fragment code. Then you can check to see which fragment is visible and do what you want accordingly.
This code is in my activity:
#Override
public void onBackPressed()
{
try
{
final LiveWorkFragment liveFragment = (LiveWorkFragment)getFragmentManager().findFragmentByTag("live_work");//LiveWorkFragment is a fragment
final NonLiveWorkFragment nonLiveFragment = (NonLiveWorkFragment)getFragmentManager().findFragmentByTag("non_live");//NonLiveWorkFragment is a fragment
final SignatureFragment signatureFragment = (SignatureFragment)getFragmentManager().findFragmentByTag("signature");//this is a Fragment too
if(liveFragment == null && nonLiveFragment == null && signatureFragment == null)
{
super.onBackPressed();
}
if(liveFragment != null)
{
if (liveFragment.isVisible())
{
//do what you want
}
}
}
}

How to handle back button using view pager?

I am having two fragments Frag A and Frag B which are rendered using view pager .
If user has swiped from A to B then presses back button(when in B) then user should go to A instead of coming out of view pager . How can we achieve this ?
Adding transaction to backstack does not seem to help .
Thanks
You have to override the onKeyDown() method in the Activity.
#Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK) {
myViewPager.setCurrentItem(0, true);
return true;
} else {
return super.onKeyDown(keyCode, event);
}
}
This will capture the "back" button press event and send the user to the first item in the ViewPager.
There is also ViewPager#getCurrentItem() which can be used to go back only if the user swiped. An implementation like this:
#Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK && myViewPager.getCurrentItem() == 1) {
myViewPager.setCurrentItem(0, true);
return true;
} else {
return super.onKeyDown(keyCode, event);
}
}
would send the user back to the previous page only if the user was on the next page. Else, it will register the "back" normally and the user will exit as expected.
You may want the case in which the user goes back to the previous page (assuming you have more than two pages). In which case, you want to implement the ViewPager.OnPageChangeListener() and save the position every time onPageSelected(int position) is called. If you implement them in a stack, then you can pop them off every time the user presses "back". Once the stack is empty, exit the app.
EDIT
As correctly stated in the comments by Jade Byfield, a slightly easier way to do this would be to use onBackPressed() in the Activity. This will only work in API levels 5+.
#Override
public void onBackPressed() {
if(i_dont_want_to_leave) {
myViewPager.setCurrentItem(0, true);
} else {
super.onBackPressed(); // This will pop the Activity from the stack.
}
}
On the Android Docs page
https://developer.android.com/training/animation/screen-slide.html#viewpager
I found an example of handling ViewPager sliding and there's a method
#Override
public void onBackPressed() {
if (mPager.getCurrentItem() == 0) {
super.onBackPressed();
}
else {
mPager.setCurrentItem(mPager.getCurrentItem() - 1);
}
}
This selects a previous page or exits the current activity.
I think a better approach would be to delegate the back key handling to the respective fragments. I have used a CustomFragment which supports a method to handle the back key. All the Fragments will be extending from this CustomFragment.
public abstract class BackKeyHandlingFragment extends Fragment {
public abstract boolean handleBackKey();
}
Activity can delegate the backKey processing to current Fragment. Fragments can perform required actions in their respective implementation of handleBackKey method. The method can return true to tell activity not to process the back key. To go ahead with default back key action at Activity level, the method can return false.
public void onBackPressed() {
BackKeyHandlingFragment fragment = (BackKeyHandlingFragment) mSectionsPagerAdapter.getItem(mViewPager.getCurrentItem());
// Fragment should return boolean according to app requirements after processing back key
if (!fragment.handleBackKey()) {
super.onBackPressed();
}
}

Categories

Resources