How to implement onBackPressed for Android Fragment? - android

I want to implement custom onBackPressed methods for all my fragments which are included in my Main activity. But I am not getting a hook when my device back is pressed. I tried to implement few stuffs available in SOF, but none of them work properly.
Please Help!
I tried this in onCreateView:
rootView.setFocusableInTouchMode(true);
rootView.requestFocus();
rootView.setOnKeyListener( new OnKeyListener()
{
#Override
public boolean onKey( View v, int keyCode, KeyEvent event )
{
if( keyCode == KeyEvent.KEYCODE_BACK)
{
return true;
}
return false;
}
} );

Use below code hopefully this code will help you.
rootView.setOnKeyListener(new View.OnKeyListener() {
#Override
public boolean onKey(View v, int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK) {
backFlag = backFlag++;
if (backFlag == 2) {
getActivity().finish();
}
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
backFlag = 0;
return true;
}
return false;
}
});

Same issue here. I solve this by setting actionbar title to fragment and then check onBackPressed which fragment is currently visible by checking the title of ActionBar. Its not proper solution but it works for me perfectly. if u have any question tell me. Hope it works for u. Thanx

public interface OnBackPressedListener {
boolean onBackPressed();
}
public interface OnBackPressedNotifier {
void registerOnBackPressedListener(OnBackPressedListener listener);
void unregisterOnBackPressedListener(OnBackPressedListener listener);
}
public class SampleActivity extends Activity implements OnBackPressedNotifier {
List<OnBackPressedListener> onBackPressedListeners = new ArrayList<>();
#Override
public void registerOnBackPressedListener(OnBackPressedListener listener) {
if (!onBackPressedListeners.contains(listener))
onBackPressedListeners.add(listener);
}
#Override
public void unregisterOnBackPressedListener(OnBackPressedListener listener) {
if(onBackPressedListeners.contains(listener))
onBackPressedListeners.remove(listener);
}
#Override
protected void onDestroy() {
onBackPressedListeners.clear();
super.onDestroy();
}
private boolean notifyOnBackPressed(){
boolean handledByFragment = false;
for (OnBackPressedListener listener : onBackPressedListeners){
handledByFragment = listener.onBackPressed();
if (handledByFragment)
break;
}
return handledByFragment;
}
#Override
public void onBackPressed() {
if (!notifyOnBackPressed())
super.onBackPressed();
}
}
public class SampleFragment extends android.support.v4.app.Fragment implements OnBackPressedListener {
#Override
public void onAttach(Context context) {
super.onAttach(context);
((OnBackPressedNotifier)getActivity()).registerOnBackPressedListener(this);
}
#Override
public void onDetach() {
((OnBackPressedNotifier)getActivity()).unregisterOnBackPressedListener(this);
super.onDetach();
}
#Override
public boolean onBackPressed() {
// Handle onBackPressed
return false;
}

You can use the new API.
activity?.onBackPressedDispatcher?.addCallback

Related

How to show AlertDialog as soon as Fragment created

I'd like to show an AlertDialog (with a couple of Radio Button buttons and an OK button) as soon as a fragment is created.
Where is the best place to call the dialog fragment? I have tried in onViewCreated() and on onResume() and both work, but I am not sure what's best practice.
Also, to ensure the dialog isn't shown every time the fragment is stopped/recreated due, for example, to screen rotation, I have created Boolean value called mShowDialog and set it to 'true' in onCreate() then used an 'If' statement to decide whether the dialog should be shown (see below for example).
onCreate(){
//....
mShowDialog = true;
}
onResume(){
if (mShowDialog){
//....show dialog code
// set mShowDialog to false to ensure code executed only once
mShowDialog = false;
}
}
Is the above code the best way of fulfilling both requirements?
Btw, I am fairly new to programming.
Thanks in advance for the help.
Best practice for this is to inflate dialog in onCreateView() method of fragment.
If you're trying to create it from the activity adding the fragment, I've had good luck with adding a FragmentListener to my fragments and setting it from the activity. This is my basic BaseFragment class that all my fragments extend:
public class BaseFragment extends Fragment {
public Context context;
public Activity activity;
public FragmentListener fragmentListener;
private boolean attached = false;
public BaseFragment() {
}
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
if (!isAttached()) {
this.context = activity;
this.activity = activity;
if (this.fragmentListener != null) {
this.fragmentListener.onAttached();
}
setAttached(true);
}
}
#Override
public void onAttach(Context context) {
super.onAttach(context);
if (!isAttached()) {
this.context = context;
this.activity = (Activity) context;
if (this.fragmentListener != null) {
this.fragmentListener.onAttached();
}
setAttached(true);
}
}
#Override
public void onDetach() {
super.onDetach();
setAttached(false);
if (this.fragmentListener != null){
this.fragmentListener.onDetached();
}
}
public void setFragmentListener(FragmentListener fragmentListener) {
this.fragmentListener = fragmentListener;
}
public View.OnClickListener onBackTapped = new View.OnClickListener() {
#Override
public void onClick(View v) {
getActivity().onBackPressed();
}
};
public boolean isAttached() {
return attached;
}
public void setAttached(boolean attached) {
this.attached = attached;
}
public boolean isPermissionGranted(String permission){
return ContextCompat.checkSelfPermission(context, permission) == PackageManager.PERMISSION_GRANTED;
}
public boolean ifShouldShowRationaleForPermission(String permission){
return ActivityCompat.shouldShowRequestPermissionRationale(activity, permission);
}
public void showPermissionRequest(Activity activity, int requestCode, String... permissions){
ActivityCompat.requestPermissions(activity, permissions, requestCode);
}
}
This way, I can do this in my activity:
MyFragment myFragment = new MyFragment();
myfragment.setFragmentListener(new FragmentListener() {
#Override
public void onAttached() {
// Stuff I want to do when it is attached
}
#Override
public void onDetached() {
// Stuff I want to do when it is detached
}
});
fragmentManager.beginTransaction()
.add(R.id.container, myFragment)
.commit();
And then I can add whatever code I want when the fragment does it's various stuff.
Good luck!

How to have an Activity notify a Fragment that the back button has been pressed

I have been researching this for a few days and have yet to find a working solution. There is lots of information available but because of my inexperience with Android I can't get any of the suggestions to work.
I have an Activity with a stack of 3 Fragments on top of it all of which are presented using FragmentManager Transactions and added to the backstack. While the third Fragment is active, I need to intercept the onBackPressed() method and perform some extra stuff before the Fragment is destroyed.
I have tried using Callbacks and Interfaces to capture onBackPressed() at the Activity and send it to the 3rd Fragment with no luck.
What is the proper way to have a Fragment deep in the stack watch for the Activity's onBackPressed() method.
Let me know if this is not clear.
Thanks for the help.
Not compiled and tested, but this lays out the basic approach:
public interface BackButonListener {
boolean OnBackButtonPressed();
}
public interface BackButtonWatchable {
void addBackButtonListener(BackButtonListener listener);
void removeBackButtonListener(BackButtonListener listener);
}
public class MyActivity extends Activity implements BackButtonWatchable {
...
private static ArrayList<BackButtonListener> backButtonListeners
= new ArrayList<BackButtonListener>();
#Override
public void addBackButtonListener(BackButtonListener listener) {
backButtonListeners.add(listener);
}
#Override
public void removeBackButtonListener(BackButtonListener listener) {
backButtonListeners.remove(listener);
}
...
#Override
public void onBackButtonPressed()
{
boolean supressBackButton = false;
for (BackButtonListener listener: backButtonListeners)
{
if (!listener.OnBackButtonPressed()) {
suppressBackButton = true;
}
}
if (!suppressBackButton) {
super.onBackButtonPressed();
}
}
}
public class MyFragment extends Fragment implements BackButtonListerer {
#Override
public void onResume()
{
((BackButtonWatchable)getActivity()).addBackButtonListener(this);
}
#Override
public void onPause() {
((BackButtonWatchable)getActivity()).removeBackButtonListener(this);
}
}
Crete interface
public interface OnBackPressedListener {
void onBackPressed();
}
and create field in activity
private OnBackPressedListener mListener;
and your onBackPressed() should look like
if (mListener != null) {
mListener.onBackPressed();
} else { /* do your acitivty usual stuff */ }
When fragment is created you register this fragment as mListener in your activity and don't forger to set it to null in onDestroy.
This is the post that answered my question. For a Android newbie, this told me where everything needed to go.
https://stackoverflow.com/a/30865486/2640458
The Fragment that needed to see the onBackPress() method from it's activity:
public class RatingFragment extends Fragment implements ContentActivity.OnBackPressedListener {
#Override
public void doBack() {
getFragmentManager().popBackStack();
}
The very important subscription to the listener in the above Fragment:
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View view = inflater.inflate(R.layout.fragment_rating, container, false);
((ContentActivity)getActivity()).setOnBackPressedListener(this);
}
The Activity that needs to send the onBackPress() method to the above Fragment:
public class ContentActivity extends Activity {
protected OnBackPressedListener onBackPressedListener;
public interface OnBackPressedListener {
void doBack();
}
public void setOnBackPressedListener(OnBackPressedListener onBackPressedListener) {
this.onBackPressedListener = onBackPressedListener;
}
#Override
public void onBackPressed() {
if (onBackPressedListener != null)
onBackPressedListener.doBack();
else
super.onBackPressed();
}
#Override
protected void onDestroy() {
onBackPressedListener = null;
super.onDestroy();
}
}

How to implement onBackPressed() & intents in fragment?

I know that onBackPressed() is a method in activity but, I want to use the functionality in fragments such that when back button is pressed, it gets redirected to another activity via Intent. Is there any solution to this ?
public class News_Events_fragment extends Fragment {
ProgressDialog pd;
ListView lv1;
SharedPreferences sharedPreferences = null;
int NotiCount;
TextView txt_title, txt_msg, textView;
Context context;
Intent intent ;
ArrayList<SliderMsgTitleModel> CurrentOfficersPastList;
NewsActivityAdapter pastAdapter;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
context = (Context) getActivity();
View rootView = inflater.inflate(R.layout.activity_news, container, false);
new AsyncTask<Void, Void, ArrayList<SliderMsgTitleModel>>() {
protected void onPreExecute() {
pd = new ProgressDialog(getActivity());
pd.setCancelable(true);
pd.setTitle("UPOA");
pd.setMessage("Please wait,loading the data...");
pd.show();
}
#Override
protected ArrayList<SliderMsgTitleModel> doInBackground(
Void... params) {
System.out.println("In Background");
CurrentOfficersPastList = new ArrayList<SliderMsgTitleModel>();
// display view for selected nav drawer item
ParseQuery<ParseObject> query = ParseQuery.getQuery("message");
query.whereEqualTo("featured_status", true);
// query.whereEqualTo("push_status", true);
query.orderByDescending("updatedAt");
query.selectKeys(Arrays.asList("title"));
query.selectKeys(Arrays.asList("message"));
try {
query.setCachePolicy(ParseQuery.CachePolicy.NETWORK_ELSE_CACHE);
List<ParseObject> results = query.find();
for (int i = 0; i < results.size(); i++) {
ParseObject object = results.get(i);
CurrentOfficersPastList.add(new SliderMsgTitleModel(
object.getString("title"), object
.getString("message")));
System.out.println("title is=="
+ object.getString("title") + "&& message is"
+ object.getString("message") + "size is"
+ CurrentOfficersPastList.size());
}
} catch (Exception e) {
e.getMessage();
}
pd.dismiss();
return CurrentOfficersPastList;
}
#SuppressWarnings("unchecked")
#Override
protected void onPostExecute(ArrayList<SliderMsgTitleModel> value) {
pd.dismiss();
/*Intent ent = new Intent(getActivity(), NewsActivity.class);
ent.putExtra("NEWSLIST", (ArrayList<SliderMsgTitleModel>) value);
startActivity(ent);
System.out.println("Value is" + value.size());*/
CurrentOfficersPastList = new ArrayList<SliderMsgTitleModel>();
CurrentOfficersPastList = value;
lv1 = (ListView) getActivity().findViewById(R.id.list_title);
pastAdapter = new NewsActivityAdapter(getActivity(), R.layout.activity_news_txt, CurrentOfficersPastList);
lv1.setAdapter(pastAdapter);
}
}.execute();
return rootView;
}
public void onBackPressed() {
// TODO Auto-generated method stub
//super.onBackPressed();
//Toast.makeText(getApplicationContext(), "click",2000).show();
String cameback="CameBack";
intent = new Intent(getActivity(),HomeActivity.class);
intent.putExtra("Comingback", cameback);
startActivity(intent);
}
}
You can interact with the fragment using a callback interface. In your activity add the following:
public class MyActivity extends Activity {
protected OnBackPressedListener onBackPressedListener;
public interface OnBackPressedListener {
void doBack();
}
public void setOnBackPressedListener(OnBackPressedListener onBackPressedListener) {
this.onBackPressedListener = onBackPressedListener;
}
#Override
public void onBackPressed() {
if (onBackPressedListener != null)
onBackPressedListener.doBack();
else
super.onBackPressed();
}
#Override
protected void onDestroy() {
onBackPressedListener = null;
super.onDestroy();
}
}
In your fragment add the following:
public class MyFragment extends Fragment implements MyActivity.OnBackPressedListener {
#Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
((MyActivity) getActivity()).setOnBackPressedListener(this);
}
#Override
public void doBack() {
//BackPressed in activity will call this;
}
}
Yes, There is. You should implement like this.
#Override
public void onBackPressed() {
if (fragment != null)
//user defined onBackPressed method. Not of Fragment.
fragment.onBackPressed();
} else {
//this will pass BackPress event to activity. If not called, it will
//prevent activity to get BackPress event.
super.onBackPressed();
}
}
Explanation
Check whether your fragment is initialized or not. If it is, then pass on back press event to your fragment.
If above condition not passed, just pass back press to your activity so that it will handle it.
Note
Here condition can be anything. I just take fragment initialization as an example. May be that can't be helped you. You need to define your own condition to pass it to fragment.
Edit
I created a sample application on GitHub to implement Back Stack of fragment .
Download Fragment Back Stack application.
Override onKeyDown instead of onBackPressed. Not necessarily . But this works for me
public boolean onKeyDown(int keyCode, KeyEvent event) {
switch (keyCode) {
case KeyEvent.KEYCODE_BACK:
String cameback="CameBack";
intent = new Intent(getActivity(),HomeActivity.class);
intent.putExtra("Comingback", cameback);
startActivity(intent);
return true
}
return false;
}
You can implement onKeyListener for your fragment and call next activity within that.
I've never tried this. But i hope it may help
For Example
fragmentObject.getView().setOnKeyListener( new OnKeyListener()
{
#Override
public boolean onKey( View v, int keyCode, KeyEvent event )
{
if( keyCode == KeyEvent.KEYCODE_BACK )
{
//your code here
}
return false;
}
} );
You need to override onBackPressed method in fragment.

InputMethodService onCreateInputView never called

I have a very simple InputMethodService where all I do is log the different stages of the lifecycle. My onCreateInputView is never called, and the log shows strange things.
MyInput D onCreate
D onInitializeInterface
D onBindInput
D onStartInput
D onUnbindInput
D onBindInput
D onStartInput
D onUnbindInput
D onBindInput
D onStartInput
D onShowInputRequested
I only clicked on a text input when the onShowInputRequested is called. When a navigate between screens, it cycles between onBind, onStartInput, onUnbind. Am I missing something?
public class MyInput extends InputMethodService {
private static final String TAG = "MyInput";
private InputMethodManager mInputMethodManager;
#Override
public void onCreate() {
super.onCreate();
mInputMethodManager = (InputMethodManager) getSystemService(INPUT_METHOD_SERVICE);
Log.d(TAG, "onCreate");
}
#Override
public void onInitializeInterface() {
super.onInitializeInterface();
Log.d(TAG, "onInitializeInterface");
}
#Override
public View onCreateInputView() {
Log.d(TAG, "onCreateInputView");
LayoutInflater inflater = (LayoutInflater) this.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
return inflater.inflate(R.layout.my_keyboard, null);
}
#Override
public void onFinishInput() {
super.onFinishInput();
Log.d(TAG, "onFinishInput");
}
#Override
public void onStartInput(EditorInfo attribute, boolean restarting) {
super.onStartInput(attribute, restarting);
Log.d(TAG, "onStartInput");
}
#Override
public void onFinishInputView(boolean finishingInput) {
super.onFinishInputView(finishingInput);
Log.d(TAG, "onFinishInputView");
}
#Override
public boolean onShowInputRequested(int flags, boolean configChange) {
Log.d(TAG, "onShowInputRequested");
return super.onShowInputRequested(flags, configChange);
}
#Override
public void onBindInput() {
super.onBindInput();
Log.d(TAG, "onBindInput");
}
#Override
public void onUnbindInput() {
super.onUnbindInput();
Log.d(TAG, "onUnbindInput");
}
#Override
public void onStartInputView(EditorInfo attribute, boolean restarting) {
super.onStartInputView(attribute, restarting);
Log.d(TAG, "onStartInputView restarting = " + restarting);
}
#Override
public void onCurrentInputMethodSubtypeChanged(InputMethodSubtype subtype) {
Log.d(TAG, "onCurrentInputMethodSubtypeChanged");
}
}
I've removed all the overriden method and left only the onCreateInputView and it is now called, no idea what wasn't working, especially because I was calling the superclass methods everywhere...
Try to change onShowInputRequested:
#Override
public boolean onShowInputRequested(int flags, boolean configChange) {
return true;
}
I had generally the same, that in some cases my keyboard was not showing, and this helped me.

Android Disable Multitouch on Views

I am facing multitouch issue. The problem is I can simultaneously touch two buttons on my screen. I know this question is asked several times in this forum and the only solution is to declare android:splitMotionEvents="false" in your parent layout. But after declaring this the issue remains. Is it the problem with the hardware or is it with the code ? Any pointer here is appreciated.
This issue appears beacuse since android 4.0 each onClick performed in a new thread.
How i solved it:
//1. create your own click listener
public abstract class AbstractCarOnClickListener {
protected static volatile boolean processing = false;
protected void executeBlock() {
ActivityUtil.scheduleOnMainThread(new Runnable() {
public void run() {
processing=false;
}
}, 400);
}
}
//2. create subclass of your listener
public abstract class AppButtonsOnClickListener extends AbstractCarOnClickListener implements View.OnClickListener {
public void onClick(View v) {
if(processing) return;
try{
processing=true;
onCarButtonClick(v);
} finally {
executeBlock();
}
}
public abstract void onCarButtonClick(View v);
}
//3. set listener to your view
public void onClick(View v) {
clickListener.onClick(v);
}
public OnClickListener clickListener = new AppButtonsOnClickListener(){
public void onCarButtonClick(View v) {
hintContainer.setVisibility(View.GONE);
if (v == cancelButton) {
listener.onCancelButtonClicked();
}
}
}
This is what worked for me. In addition to setting the android:splitMotionEvents="false" on every ViewGroup that contains the buttons I put this in MyAdapter.getView()...
view.setOnTouchListener(new OnTouchListener() {
#Override
public boolean onTouch(View cell, MotionEvent event) {
// Process touches only if: 1) We havent touched a cell, or 2) This event is on the touched cell
if (mTouchedCell == null || cell.equals(mTouchedCell)) {
int action = event.getAction();
if (action == MotionEvent.ACTION_DOWN) {
cell.startAnimation(mShrink);
mTouchedCell = cell;
} else if (action == MotionEvent.ACTION_CANCEL) {
if (cell.equals(mTouchedCell)) {
cell.startAnimation(mGrow);
}
mTouchedCell = null;
return true;
} else if (action == MotionEvent.ACTION_UP) {
cell.startAnimation(mFadeOut);
mTouchedCell = null;
}
return false;
}
return true;
}
});
...and of course this in the adapter...
private static View mTouchedCell = null;

Categories

Resources