Interface not worked from activity to currently loaded fragment - android

I wanted to pass data from Activity to Currently loaded fragment on button click.
For that i created Interface and define into activity and implement in interface but couldn't get response in fragment.
I Needed output whenever button clicks fire in Activity.
Here is my code. Please help me to resolve this.
Inteface
public interface Click {
void onClick(String msg);
}
Main Actvity
public class MainActivity extends FragmentActivity {
DrawerLayout dlMain;
Button btnClick;
Click click;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
FragmentOne fragmentOne = new FragmentOne();
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.replace(R.id.flContainer, fragmentOne,"FragmentOne");
ft.commit();
click = (Click) getSupportFragmentManager().findFragmentByTag("FragmentOne").;
dlMain = (DrawerLayout) findViewById(R.id.dlMain);
btnClick = (Button) findViewById(R.id.btnClick);
btnClick.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Log.e("Btn Click", "click");
click.onClick("Button Clicked!");
}
});
}
}
FragmentOne
public class FragmentOne extends Fragment implements Click {
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_one, container, false);
return view;
}
#Override
public void onClick(String msg) {
Toast.makeText(getActivity(), msg, Toast.LENGTH_SHORT).show();
}
}
But there i am getting error in MainActivity
This is my Error Logs.
05-09 10:30:49.092 19101-19101/com.psk.interfacetest
E/Btn Click: click
05-09 10:30:49.095 19101-19101/com.psk.interfacetest E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.psk.interfacetest, PID: 19101
java.lang.NullPointerException
at com.psk.interfacetest.MainActivity$1.onClick(MainActivity.java:37)
at android.view.View.performClick(View.java:4471)
at android.view.View$PerformClick.run(View.java:18778)
at android.os.Handler.handleCallback(Handler.java:808)
at android.os.Handler.dispatchMessage(Handler.java:103)
at android.os.Looper.loop(Looper.java:193)
at android.app.ActivityThread.main(ActivityThread.java:5345)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:515)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:824)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:640)
at dalvik.system.NativeStart.main(Native Method)

Your case, fragment replacing can not finish. So you should register interface from fragment.You can examine this code.
public class AActivity extends FragmentActivity {
Click click;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
FragmentOne fragmentOne = new FragmentOne();
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.replace(R.id.flContainer, fragmentOne,"FragmentOne");
ft.commit();
DrawerLayout dlMain = (DrawerLayout)findViewById(R.id.dlMain);
Button btnClick = (Button) findViewById(R.id.btnClick);
btnClick.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Log.e("Btn Click", "click");
click.onClick("Button Clicked!");
}
});
}
public void setCallback(Click callback) {
this.click=callback;
}
public interface Click {
void onClick(String msg);
}
}
public class AFragment extends Fragment implements AActivity.Click {
#Override
public void onViewCreated(View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
if (getActivity() != null) {
((AActivity)getActivity()).setCallback(this);
}
}
#Override
public void onClick(String msg) {
}
}

try this
public class MainActivity extends FragmentActivity {
DrawerLayout dlMain;
Button btnClick;
Click click;
private FragmentOne fragmentOne;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
fragmentOne = new FragmentOne();
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.replace(R.id.imageTitleTextView, fragmentOne, "FragmentOne");
ft.commit();
//click = (Click) getSupportFragmentManager().findFragmentByTag("FragmentOne");
dlMain = (DrawerLayout) findViewById(R.id.dlMain);
btnClick = (Button) findViewById(R.id.btnClick);
btnClick.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Log.e("Btn Click", "click");
fragmentOne.listener.onClick("Button Clicked!");
}
});
}
}
public class FragmentOne extends Fragment {
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_one, container, false);
return view;
}
Click listener = new Click() {
#Override
public void onClick(String msg) {
Toast.makeText(getActivity(), msg, Toast.LENGTH_SHORT).show();
}
};
}

Related

Is it possible to implement separate buttons onclickListener in both Activity and Fragment?

My MainActivity contain buttons which is used to switch to different fragments. Inside each fragment there are also has buttons. Activity button onClickListener work fine before implementing button onClickListener in fragments. I wonder if this is not supported by Android or my code is not correct.
Any pointer is appreciated. Thank you.
Fragment code:
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
v = inflater.inflate(fragment1, container, false);
b2=(Button)v.findViewById(R.id.button2);
b2.setOnClickListener(new View.OnClickListener()
{
public void onClick(View v){
button2Clicked(v);
}
});
return inflater.inflate(R.layout.fragment1, container, false);
}
public void button2Clicked(View view){
//do something
}
Activity code:
public class MainActivity extends FragmentActivity {
private Button btnHealth;
private Button btnSetting;
private Button btnSleep;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//Init component
btnHealth = (Button) findViewById(R.id.btnHealth);
btnSleep = (Button) findViewById(R.id.btnSleep);
btnSetting = (Button) findViewById(R.id.btnSetting);
replaceFragment(1);
btnHealth.setOnClickListener(new AdapterView.OnClickListener(){
#Override
//On click function
public void onClick(View view) {
replaceFragment(0);
}
});
btnSleep.setOnClickListener(new AdapterView.OnClickListener(){
#Override
//On click function
public void onClick(View view) {
replaceFragment(1);
}
});
btnSetting.setOnClickListener(new AdapterView.OnClickListener(){
#Override
//On click function
public void onClick(View view) {
replaceFragment(2);
}
});
}
//Create method replace fragment
private void replaceFragment(int pos) {
Fragment fragment = null;
switch (pos) {
case 0:
fragment = new Fragment1();
break;
case 1:
fragment = new Fragment2();
break;
case 2:
fragment = new Fragment3();
break;
default:
fragment = new Fragment2();
break;
}
if(null!=fragment) {
FragmentManager fragmentManager = getFragmentManager();
FragmentTransaction transaction = fragmentManager.beginTransaction();
transaction.replace(R.id.main_content, fragment);
transaction.addToBackStack(null);
transaction.commit();
}
}
}
It is possible. If you want to handle the OnClick Event of the fragment inside the Activity class, you can do so by using FragmentInteractionListener (interface). Example: Android - handle fragment onClick from activity

popBackStack() not working when going back from Activity 2 Fragment to Activity 1 Fragment

I have 2 Activity - MainActivity and MainActivity2 .
MainActivity has 2 fragments
MainActivity2 has 1 fragment
So i pass data from MainActivity_Frag_one to MainActivity_Frag_two.
When i click device back button and the blue button in MainActivity_Frag_two , it works well by going back to MainActivity_Frag_one.
After that, I pass data from MainActivity_Frag_two to MainActivity2_Frag_one using intent
When i click device back button it works well by going back to MainActivity_Frag_two but the blue button is not working (no effect when clicked, also no error shows).
May i know which part has gone wrong?
MainActivity.java
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
FragmentManager manager=getSupportFragmentManager();
FragmentTransaction transaction=manager.beginTransaction();
MainActivity_Frag_one MainActivity_Frag_one=new MainActivity_Frag_one();
transaction.add(R.id.activity_one_container,MainActivity_Frag_one);
transaction.commit();
}
MainActivity_Frag_one.java
public class MainActivity_Frag_one extends Fragment {
EditText get_text;
Button get_button;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_main_activity__frag_one,container,false);
get_text=(EditText)rootView.findViewById(R.id.input_name);
get_button=(Button)rootView.findViewById(R.id.submit_button);
get_button.setOnClickListener(new View.OnClickListener(){
public void onClick(View v){
FragmentManager manager=getFragmentManager();
FragmentTransaction transaction=manager.beginTransaction();
Bundle bundle=new Bundle();
bundle.putString("message", get_text.getText().toString());
MainActivity_Frag_two fragobj=new MainActivity_Frag_two();
fragobj.setArguments(bundle);
transaction.replace(R.id.activity_one_container,fragobj);
transaction.addToBackStack("zzz");
transaction.commit();
}
});
return rootView;
}
}
MainActivity_Frag_two.java
public class MainActivity_Frag_two extends Fragment {
ImageView get_button;
Button get_to_second_activity;
String strtext;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_main_activity__frag_two,container,false);
TextView display_text=(TextView)rootView.findViewById(R.id.display_text);
strtext=getArguments().getString("message");
display_text.setText(strtext);
get_button=(ImageView)rootView.findViewById(R.id.back_button);
get_button.setOnClickListener(new View.OnClickListener(){
public void onClick(View v){
getFragmentManager().popBackStack();
}
});
get_to_second_activity=(Button)rootView.findViewById(R.id.to_second_activity);
get_to_second_activity.setOnClickListener(new View.OnClickListener(){
public void onClick(View v){
Intent intent = new Intent(getActivity(),MainActivity2.class);
intent.putExtra("Check","data from mainactivity_frag_two is : "+strtext);
startActivity(intent);
FragmentManager manager=getFragmentManager();
FragmentTransaction transaction=manager.beginTransaction();
transaction.addToBackStack("");
transaction.commit();
}
});
return rootView;
}
}
MainActivity2.java
public class MainActivity2 extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main2);
FragmentManager manager=getSupportFragmentManager();
FragmentTransaction transaction=manager.beginTransaction();
MainActivity2_Frag_one MainActivity2_Frag_one=new MainActivity2_Frag_one();
transaction.add(R.id.activity_two_container,MainActivity2_Frag_one);
transaction.commit();
}
}
MainActivity2_Frag_one.java
public class MainActivity2_Frag_one extends Fragment {
TextView get_display;
ImageView get_button;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_main_activity2__frag_one,container,false);
get_display=(TextView)rootView.findViewById(R.id.display);
String data1=getActivity().getIntent().getExtras().getString("Check");
get_display.setText(data1);
get_button=(ImageView)rootView.findViewById(R.id.back_to_previous_frag);
get_button.setOnClickListener(new View.OnClickListener(){
public void onClick(View v){
getFragmentManager().popBackStack();
}
});
return rootView;
}
}
To go back to the previous activity you don't need to pop the fragment from the back stack. You can just call finish().
In your MainActivity2_Frag_one.java
Replace this :
get_button.setOnClickListener(new View.OnClickListener(){
public void onClick(View v){
getFragmentManager().popBackStack();
}
});
with
get_button.setOnClickListener(new View.OnClickListener(){
public void onClick(View v){
getActivity().finish();
}
});
The reason is popBackStack() can be used within the same activity.

Android: Error using calling AlertDialog from inside Fragment

Why do i always get error when i try to call AlertDialog from my fragment?
At first i try to put it in OnCreate but it also get the same error log...
MainFragment.java
public class MainFragment extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main_fragment);
if (savedInstanceState == null) {
FragmentTransaction ft = getFragmentManager().beginTransaction();
LoginFragment fragment = new LoginFragment();
ft.add(R.id.simple_fragment, fragment).commit();
}
}
}
LoginFragment.java
public class LoginFragment extends Fragment implements OnClickListener {
Helper application;
static LoginFragment newInstance() {
LoginFragment f = new LoginFragment();
Bundle args = new Bundle();
f.setArguments(args);
return f;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
AlertDialog.Builder dlgAlert = new AlertDialog.Builder(getActivity().getApplicationContext());
dlgAlert.setMessage("TEST");
dlgAlert.setPositiveButton("OK", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
dialog.dismiss();
}
});
dlgAlert.setCancelable(false);
dlgAlert.create().show();
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.activity_login, container, false);
Button inner = (Button) v.findViewById(R.id.btnSignUp);
inner.setOnClickListener(LoginFragment.this);
return v;
}
#Override
public void onClick(View v) {
}
}
and this is the error log
12-19 10:14:25.295: E/AndroidRuntime(1083): java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.myfirstapp/com.example.fragment.MainFragment}: android.view.WindowManager$BadTokenException: Unable to add window -- token null is not for an application
anyone has ever encountered this before?
Just try
AlertDialog.Builder dlgAlert = new AlertDialog.Builder(getActivity());
If you are dealing with nested fragments. When a fragment has it's own child fragments you need to use getChildFragmentManager().

Passing String to Fragment

I have an EditText view in my MainActivity that the user can input a url. This MainActivity also contains a fragment which will hold a WebView.
I have it set up so that when the fragment is displayed the url will load in the WebView. However I don't know how I can pass the String to the Fragment?
Below is the Main Activity code:
public class MainActivity extends FragmentActivity {
Button goBtn;
EditText urlInput;
String url;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
goBtn = (Button)findViewById(R.id.button1);
urlInput = (EditText)findViewById(R.id.editText1);
goBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
url = "http://"+urlInput.getText().toString(); //THIS TO FRAGMENT!
Toast.makeText(v.getContext(), "Search:" + url, Toast.LENGTH_SHORT).show();
}
});
and this is the fragment code:
WebView webDisplay;
String url;
AsyncHttpClient client;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.frag1_layout, container, false);
urlDisplay = (TextView)v.findViewById(R.id.textView1);
webDisplay = (WebView)v.findViewById(R.id.webView1);
return v;
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
//url = "http://"+this.getActivity() ???
client = new AsyncHttpClient();
client.get(url, new AsyncHttpResponseHandler(){
#Override
public void onSuccess(String response) {
Toast.makeText(getActivity(), "Success!", Toast.LENGTH_SHORT).show();
webDisplay.setWebViewClient(new WebViewClient() {
public boolean shouldOverrideUrlLoading(WebView view, String url) {
view.loadUrl(url);
return true;
}});
webDisplay.loadUrl(url);
}
});
The value I am concerned about it the String URL variable in MainActivity.java.
The transaction of the fragments is controlled by a class TabFragment.
public class TabFragment extends Fragment {
private static final int TAB1_STATE = 0x1;
private static final int TAB2_STATE = 0x2;
private int mTabState;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fragment_tab, container, false);
//References to buttons in layout file
Button tabBtn1 = (Button)v.findViewById(R.id.tabBtn1);
Button tabBtn2 = (Button)v.findViewById(R.id.tabBtn2);
//add listener to buttons
tabBtn1.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View arg0) {
//Action to perform when Tab 1 clicked...
goToTab1View();
}
});
tabBtn2.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
//Action to perform when Tab 2 clicked...
goToTab2View();
}
});
return v;
}
//Tab action functions.
protected void goToTab1View() {
if(mTabState != TAB1_STATE){
mTabState = TAB1_STATE;
FragmentManager fm = getFragmentManager();
if(fm!= null){
//Perform fragment transaction
FragmentTransaction ft = fm.beginTransaction();
ft.replace(R.id.fragment_content, new FragTab1());
ft.commit();
}
}
}
protected void goToTab2View() {
if(mTabState != TAB2_STATE){
mTabState = TAB2_STATE;
FragmentManager fm = getFragmentManager();
if(fm!= null){
//Perform fragment transaction
FragmentTransaction ft = fm.beginTransaction();
ft.replace(R.id.fragment_content, new FragTab2());
ft.commit();
}
}
}
Or create Bundle and set it using method fragment.setArguments(myBundle);
This answer is in case the fragment already exists
You can define a public method in your fragment. Something like:
public void setString(final String str) { //... }
After that make your activity to implement OnClickListener interfave. And when the button is pressed just type something like that:
public void onClick(View view) {
// Form url...
((YourWebViewFragment) getFragmentManager().findFragmentById(fragments_id)).setString(url);
}

How to implement saveFragmentInstanceState?

Could you anyone advice me how to implement saveFragmentInstanceState() or some other methods to retrieving fragment instance when back button is pressed. I use own stack for fragment, viz code bellow:
public class stackA extends ActivityInTab {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.i("StackA", "onCreate");
if(savedInstanceState == null){
navigateTo(new fragmentA());
}
}
}
Next there is implementation of ActivityInTab class. I think for this class must be implemented methods for saving and retrieving fragment state but still I can't find the way how to do this.
abstract class ActivityInTab extends FragmentActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_in_tab);
Log.i("ActivityInTab", "onCreate");
}
protected void navigateTo(Fragment newFragment) {
FragmentManager manager = getSupportFragmentManager();
FragmentTransaction ft = manager.beginTransaction();
ft.replace(R.id.content, newFragment);
ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
ft.addToBackStack(null);
ft.commit();
}
#Override
public void onBackPressed() {
Log.i("ActivityInTab", "onBackPressed");
FragmentManager manager = getSupportFragmentManager();
if (manager.getBackStackEntryCount() > 1) {
super.onBackPressed();
} else {
// Otherwise, ask user if he wants to leave :)
//showExitDialog();
super.onBackPressed();
}
}
}
And finally, this is imlementation of Fragments:
public class fragmentA extends Fragment {
private LinearLayout ll;
private FragmentActivity fa;
private String textViewText;
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
Log.i("Fragment A", "onCreateView");
fa = super.getActivity();
ll = (LinearLayout) inflater.inflate(R.layout.fragmenta, container,
false);
Button next = (Button) ll.findViewById(R.id.button1);
Button randomBtn = (Button) ll.findViewById(R.id.random_button);
final TextView randomText = (TextView) ll
.findViewById(R.id.random_textview);
next.setOnClickListener(new View.OnClickListener() {
public void onClick(View view) {
((ActivityInTab) getActivity()).navigateTo(new
fragmentB());
}
});
randomBtn.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
// TODO Auto-generated method stub
randomText.setText(String.valueOf(Math.random()));
textViewText = randomText.getText().toString();
}
});
if (savedInstanceState != null) {
randomText.setText(savedInstanceState.getString("TextView"));
}
return ll;
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
// setRetainInstance(true);
}
#Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putString("TextView", textViewText);
}
}
I'm able to save instance state only for orientation changes using onSaveInstanceState(Bundle outState), but no for back button.
I would be very grateful for any advice, thanks.
In the onBackPressed Method you have access to the FragmentManager which can retrieve any fragment for you using the FragmentManager methods "findFragmentById" or "findFragmentByTag".
You can get direct access to any fragment whos state you want to save using either of those two methods depending on how you added the fragments.

Categories

Resources