I've created an FragmentContainerView called GamePadFragment in MainActivity and I would like to get data from the fragment to the main activity. As the FragmentContainerView is relatively new method. I cannot find much info onto it.
I've placed multiple buttons on the FragmentContainerView. May I know how to get data pass (string) from the fragment on a button in FragmentContainerView is clicked.
String Pass:
from the `GamePadFragment` (FragmentContainerView) --> the Activity holding it
on button clicks
The current code in Main Activity is like:
FragmentContainerView gamePadFragment;
public MainActivity() {
super(R.layout.activity_main);
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
gamePadFragment = findViewById (R.id.gamePadFragment);
if (savedInstanceState == null) {
getSupportFragmentManager().beginTransaction()
.setReorderingAllowed(true)
.add(R.id.gamePadFragment, GamePadFragment.class, null)
.commit();
}
// Set Default Appearance
//int wd = gamePadFragment.getWidth();
//gamePadFragment.setLayoutParams(new RelativeLayout.LayoutParams(wd, wd));
}
Use callback
interface MyCallback{
void click(String data);
}
Activity implements this interface
class MyActivity implements MyCallback
send delegate to your fragment,
call callback function in your fragment
Related
I have been struggling to implement a super simple app layout, where my MainActivity opens Fragment#1 in its onCreate method, then the Fragment#1 opens Fragment#2 when an item is clicked.
As of right now, when I open Fragment#1 from my MainActivity, I add Fragment#1 to the BackStack. After opening Fragment#2, when I hit the back button the first click does nothing, then the second click sends me all the way back to my login page, skipping past Fragment #1 and MainActivity.
How can I make it so when I hit the back button on Fragment#2, it opens Fragment#1 back up?
(MainActivity opens Fragment#1)
public class MainActivity extends AppCompatActivity {
private static final String TAG = "MainActivity";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
SearchListFragment fragment = new SearchListFragment();
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
transaction.replace(R.id.main_fragment_container, fragment);
transaction.addToBackStack(TAG);
transaction.commit();
}
}
(Fragment#1 opens Fragment#2)
public class SearchListFragment extends Fragment {
public void viewResults(SearchModel search) {
Bundle args = new Bundle();
args.putString("ID", search.getId());
ResultsFragment fragment = new ResultsFragment();
fragment.setArguments(args);
FragmentTransaction transaction = getParentFragmentManager().beginTransaction();
transaction.replace(R.id.main_fragment_container, fragment);
transaction.commit();
}
}
EDIT
I should have mentioned that I have tried to handle the back press event myself. I tried adding this to my MainActivity but it did not change the behavior:
#Override
public void onBackPressed() {
if (getSupportFragmentManager().getBackStackEntryCount() == 0) {
this.finish();
} else {
getSupportFragmentManager().popBackStack();
}
}
onCreate with
Kotlin
val backpress = requireActivity().onBackPressedDispatcher.addCallback(viewLifecycleOwner, true) {
// Handle the back button event
}
Java
OnBackPressedCallback callback = new OnBackPressedCallback(true /* enabled by default */) {
#Override
public void handleOnBackPressed() {
// Handle the back button event
}
});
requireActivity().getOnBackPressedDispatcher().addCallback(this, callback);
You can provide your back operations in the relevant sections.
getSupportFragmentManager().beginTransaction().replace(R.id.frag_frame, fragment).addToBackStack("text").commit();
I am building an app with 2 fragments. The 1st fragment has an ImageView and 2 TextViews and the 2nd fragment has a set of buttons and EditTexts. In the 2nd fragment, I have a button called "Save". When this button is clicked, I want to download the image inside my 1st fragment to my device folder (The ImageView, the URI, the bitmap and canvas objects are all in the 1st fragment).
Because fragments can't communicate with one another directly, I was thinking of doing this with an interface. What I did was:
I've declared my interface in the 2nd fragment
Applied the logic of the interface's method in the MainActivity (which is the shared activity between the 2 fragments)
Fed the necessary parameters for the method in the 1st fragment.
Didn't work
But I don't think that this was the correct order so it's no surprise that it didn't work. How do I apply the interface in a way that a button click in the 2nd fragment downloads the image in the 1st fragment?
You could try one of these three options:
1.) Using callbacks to communicate via the activity
As shown in this article, you can define an interface in fragment 2 which is then called when the button is clicked. Your activity (which holds fragment 2) provides an implementation for that interface in which the activity calls a method in fragment 1 for downloading the image. For example:
Fragment 1 providing the download method
public class Fragment1 extends Fragment {
OnButtonClickedListener mCallback;
public void startImageDownload() {
// Download the image
}
// ...
}
Fragment 2 defining and calling the interface
public class Fragment2 extends Fragment {
OnButtonClickedListener mCallback;
// Some kind of init method called by onCreate etc.
private void init() {
Button button = (Button) findViewById(R.id.button);
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
// Call the listener if present
if(mCallback != null) {
mCallback.onButtonClicked();
}
}
});
}
public void setOnButtonClickedListener(Activity activity) {
mCallback = activity;
}
// Container Activity must implement this interface
public interface OnButtonClickedListener {
public void onButtonClicked();
}
// ...
}
The Activity reacting on the Button click and calling the download method
public static class MainActivity extends Activity implements Fragment2.OnButtonClickedListener {
Fragment1 mFragment1;
#Override
public void onAttachFragment(Fragment fragment) {
if (fragment instanceof Fragment2) {
// Register the listener
Fragment2 fragment2 = (Fragment2) fragment;
fragment2.setOnButtonClickedListener(this);
} else if (fragment instanceof Fragment1) {
// Keep a reference to fragment 1 for calling the "download" method
mFragment1 = (Fragment1) fragment;
}
}
#Override
public void onButtonClicked() {
// Handle the button click
mFragment1.startImageDownload();
}
}
This way you avoid linking the fragments together, instead you have the activity beeing a loose "connection" between fragment 1 and fragment 2.
This is just an exmple, i did not had time to test it. But i hope it helps.
2.) Using a local broadcast
I would recommend using the LocalBroadcastManager for sending a broadcast in fragment 1 (that the button was clicked) and receiving it in fragment 2 (downloading the image). Here is a great article about local broadcasts.
3.) Another option is to use ViewModel
The ViewModel was recently introduced by the new Android Jetpack and "is designed to store and manage UI-related data in a lifecycle conscious way. The ViewModel class allows data to survive configuration changes such as screen rotations." (from ViewModel Overview).
It can also be used to share data between two fragments: Your activity basically holds the ViewModel and the fragments (inside that activity) can get access to it by calling: ViewModelProviders.of(getActivity()).get(SharedViewModel.class);
I think your scenario you could use Observers or some kind of LiveData to react to the button-click via a ViewModel.
Thanks to #Elletlar for helping me improve my answer.
So, what my problem is that in one fragment(w/i a viewpager, I'll call this Fragment A) I click on this dynamically created button that adds a new fragment(I'll call this Fragment B) in a framelayout which allows me to use PayPal service. On PayPal Activity result, Fragment B communicates with the main Activity via a communicator(an interface class) to call Fragment A to change that text. But I'm getting a null pointer exeception crash.
To be specific:
what I did was that I made a global TextView variable that is initialized on click. I did this b/c I have a list of other things that are dynamically inflated and to avoid the TextView from being initialized with wrong layout I initialized it on click.
bidChange.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
eventListChangeKey = keyVal;
eventListChangeIdx = eventListIdx;
eventBiddingChangeIdx = finalI;
priceToChage = (TextView) biddersLayout.findViewById(R.id.single_list_bidder_bid_price);
Bundle bundle = new Bundle();
bundle.putInt("auctionID", auctionId);
bundle.putInt("dateID", dateId);
bundle.putInt("FromWhere", 2);
Fragment fragment = new Fragment_Home_ItemInfo_Bid();
fragment.setArguments(bundle);
FragmentManager fragmentManager = getActivity().getSupportFragmentManager();
fragmentManager.beginTransaction()
.add(R.id.container_mainScreen, fragment, "itemInfo_bid")
.addToBackStack(null)
.setTransitionStyle(FragmentTransaction.TRANSIT_FRAGMENT_FADE)
.commit();
}
});
In the main activity
public void changeBidderPrice(String s) {
Fragment fragment = viewPagerAdapter.getItem(1);
((Fragment_List) fragment).changePrice(s);
}
is what I do
back in Fragment A
public void changePrice(String val) {
priceToChage.setText(val);
dataMap.get(eventListChangeKey).get(eventListChangeIdx).getBidList().get(eventBiddingChangeIdx).setPrice(val);
}
I've thought this over an over but I just can't figure this out. I've searched for similar cases in StackOverflow but I wasn't able to get a help.
Would the problem be the way I initialize that TextView? or is it the way I'm calling Fragment A from the main activity?
for fragments onViewCreated() is called after onCreateView() and ensures that the fragment's root view is non-null. Any view setup should happen here. E.g., view lookups, attaching listeners.
source : codepath
for activities onCreate()
I'm using FragmentActivity for switching between Fragment. But I would like to have a Admin Button on a fragment, and when I click on it, a new fragment or activity appears like a child (with the back button in action bar).
How can I make it ?
Here is my code, that works, but the back button doesn't appear in action bar :
Fragment :
public class Reports extends Fragment {
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (container == null) {
return null;
}
public void onClick(View v) {
Intent intent = new Intent(getActivity(), LoginActivity.class);
getActivity().startActivity(intent);
}
});
}
}
Activity (for the moment... but maybe Fragment if we need ?) :
public class LoginActivity extends ActionBarActivity {
public static final String TAG = LoginActivity.class.getSimpleName();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.login);
Button loginButton = (Button) findViewById(R.id.loginButton);
loginButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
TextView emailText = (TextView) findViewById(R.id.emailText);
TextView passwordText = (TextView) findViewById(R.id.passwordText);
ParseUser.logInInBackground(emailText.getText().toString(), passwordText.getText().toString(), new LogInCallback() {
public void done(ParseUser user, ParseException e) {
if (user != null) {
Log.i(TAG, "Yeahhh Login OK");
finish();
} else {
runOnUiThread();
}
}
});
}
});
}
Maybe I have to change something in Manifest ?
All you need to do is enable it inside the activity you're currently at.
When inside a FragmentActivity: getActionBar().setHomeAsUpEnabled(boolean).
Otherwise, inside a Fragment: getActivity().getActionBar().setHomeAsUpEnabled(boolean).
U need to override the onCreateOptionsMenu and onOptionsItemSelected. In the onCreateOptionsMenu method do the following : Inflate the menu into the action bar. You can define the contents of the menu item under res/menu folder.
Next in the onOptionsItemSelected method, you can handle the clicks of the back button added in the action bar. Also keep in mind one thing. In the manifest please use a theme which has action bar in it.
Example : Under the application tag use
android:theme="#android:style/Theme.Light" and not anything like android:theme="#android:style/Theme.Light.NoTitleBar
Well if you are starting a new Activity you can enable the back button in it by writing shouldDisplayHomeUp(); in the onCreate() method and on back should take you to the previous activity in the back stack.
And in the other case of adding a new Fragment you can take a look on this answer for reference as it mentions that when you add a new Fragment you add it to the back stack like this
getSupportFragmentManager().beginTransaction()
.add(detailFragment, "detail")
// Add this transaction to the back stack
.addToBackStack()
.commit();
this will make the back button take you to your previous Fragment
I currently making a application however, I'm faced unable to start the activity componentsInfo. I found a lots of solutions on the net, but none of them is works for me. I try to clean my project file and restart Eclipse, errors still occur. I try to debug with DDBS, and find a 'setOnClickListener' had something wrong. I try to edit it. But error still occur.
Note: Implements view.OnClickListener didn't works for me also.
public class MainActivity extends Activity{
private Button mBreakfast;
private Button mLunch;
private Button mDinner;
private Button mSnack;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if (savedInstanceState == null) {
getFragmentManager().beginTransaction()
.add(R.id.container, new PlaceholderFragment()).commit();
}
mBreakfast = (Button) findViewById(R.id.btn_breakfast);
mLunch = (Button) findViewById(R.id.btn_lunch);
mDinner = (Button) findViewById(R.id.btn_dinner);
mSnack = (Button) findViewById(R.id.btn_snack);
mBreakfast.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
Intent intent = new Intent(MainActivity.this,RestInfoFragment.class);
startActivity(intent);
}
});
}
}
And well it is probably a mistake to import!
if so:
import android.content.DialogInterface.OnClickListener;
change to:
import android.view.View.OnClickListener;
RestInfoFragment is a fragment, and you want to start it on click of the button?
Fragments aren't invoked like Activities using Intents.To start a fragment, use this code:
getFragmentManager().beginTransaction()
.replace(R.id.container, new RestInfoFragment).commit();
From your naming , I guess the RestInfoFragment is a Fragment, and you are using a button click in another activity to navigate to the RestInfoFragment, like an Activity.
You can't use Fragment as an activity. Either change your RestInforFragment to extend a FragmentActivity or inflate the fragment in a view.
If you extends FragmentActivity , you don't need any changes to the current MainActivity.
If you are using Fragment
getFragmentManager().beginTransaction()
.replace(R.id.container, new RestInfoFragment).commit();
If your RestInfoFragment is using the whole screen , I recommend the use of FragmentActivity.