I'm facing some problems in Android development. Environment is set to run in min API 23.
This is what I try to achieve :
I have a MainActivity with a BottomNavigationView. When an item in the BottomNavigationView is clicked it launches a Fragment. This works very well,I can send data to a fragment and have an interface to dialog with my activity.
The problem is :
On my Last fragment (ProgramFragment), I would like to make a Form Wizard. So, I would like to launch other fragments from the ProgramFragment. I used the same method I used in the MainActivity and I can launch the first fragment (RecStartFragment) where there is a button in the Layout. I want that when the button is clicked, the next fragment (RecDataPatientFragment) is shown. I get an error when I click on the button, saying that :
java.lang.NullPointerException: Attempt to invoke interface method
'void x.RecStartFragment$OnRecStartFragmentListener.startRecProg()'
on a null object reference at
x.RecStartFragment$1.onClick(RecStartFragment.java:30)
Is there a way to achieve that ? Why is that working from an activity but not from a fragment ?
Here is the code of the fragment RecStartFragment
package x;
import android.app.Fragment;
import android.content.Context;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
public class RecStartFragment extends Fragment {
private static final String TAG = RecStartFragment.class.getName();
private View v;
OnRecStartFragmentListener onRecStartFragmentListener;
private Button btnStartRec;
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, Bundle savedInstanceState) {
if(v != null) {
return v;
}
v = inflater.inflate(R.layout.fragment_rec_start, null);
btnStartRec = v.findViewById(R.id.btn_start_rec);
btnStartRec.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
onRecStartFragmentListener.startRecProg();
}
});
return v;
}
public interface OnRecStartFragmentListener
{
public void startRecProg();
}
#Override
public void onAttach(Context context) {
super.onAttach(context);
try {
onRecStartFragmentListener = (OnRecStartFragmentListener) context;
} catch (Exception e)
{
}
}
Thank you in advance !
You have a Null Pointer Exception (NPE) indicating that the field OnRecStartFragmentListener onRecStartFragmentListener has not been initialised.
From your code, you are trying to initialise the field in onAttach() and catching exceptions, but not doing anything with them:
#Override
public void onAttach(Context context) {
super.onAttach(context);
try {
onRecStartFragmentListener = (OnRecStartFragmentListener) context;
} catch (Exception e)
{
}
}
Try printing the stacktrace of any exceptions:
e.printStackTrace()
The context passed in onAttach is your MainActivity ? If so, is it implementing OnRecStartFragmentListener ?
You should implement the interface in your activity:
Activity implementation:
public class MainActivity extends AppCompatActivity implements RecStartFragment.OnRecStartFragmentListener{
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
loadFragment();
}
#Override
public void startRecProg() {
//Do whatever you need do here.
Log.e("Calback:","Interface is working");
}
}
Related
I created a ListDialog extending a DialogFragment class and I have a problem with understanding of this code in the DijalogX class
((MainActivity)getActivity()).setTextField(selectedItem);
I understand that with this code above I put selected String variable to the setTextField method as an argument and after that this variable is showed in TextView on MainActivity class.
My questions:
Why I need a cast from getActivity() to the MainActivity and how I get access from DijalogX(fragment) to the method setTextField in MainActivity? Please explain a little about this process.
I also tried instead of ((MainActivity)getActivity()).setTextField(selectedItem)
use an Interface and everything works nice and I got the same resoult but I am wondering what is better solution here Interface or ((MainActivity)getActivity()).setTextField(selectedItem)?
MainActivity
package com.example.dezox.dijaloglist;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
public class MainActivity extends AppCompatActivity{
private Button btnStartDialog;
private TextView tvSelectedOption;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initWidgets();
setupListener();
}
private void initWidgets() {
btnStartDialog = findViewById(R.id.btnDialog);
tvSelectedOption = findViewById(R.id.tvselectedOption);
}
private void setupListener() {
btnStartDialog.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
DijalogX dijalogX = new DijalogX();
dijalogX.show(getSupportFragmentManager(), "dx");
tvSelectedOption.setText("");
}
});
}
public void setTextField(String odabrano){
tvSelectedOption.setText(odabrano);
}
public String getTextField(){
return tvSelectedOption.getText().toString();
}
}
DijalogX
package com.example.dezox.dijaloglist;
import android.app.Dialog;
import android.content.DialogInterface;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.app.DialogFragment;
import android.support.v7.app.AlertDialog;
public class DijalogX extends DialogFragment {
private String[] languageList;
#Override
public void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
initListResource();
}
private void initListResource() {
languageList = getResources().getStringArray(R.array.language_list);
}
#NonNull
#Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity(),
android.R.style.Theme_Material_Dialog_Alert)
.setTitle("Select Language: ")
.setItems(languageList, new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
String selectedItem = languageList[which];
//THIS PART OF THE CODE I DONT UNDERSTAND:
((MainActivity)getActivity()).setTextField(selectedItem);
}
});
return builder.create();
}
}
You have declared a method in MainActivity called setTextField. If you called
Activity a = getActivity();
you would not be able to call your custom method (it is on your derived class, not the base Activity class).
a.setTextField(selectedIte); // WON'T WORK - NO SUCH METHOD
If instead you call
MainActivity ma = (MainActivity)getActivity();
it is now cast as your derived class and you can then call
ma.setTextField(selectedItem);
Doing it in two lines like this is the same as calling the one-liner in your code
((MainActivity)getActivity()).setTextField(selectedItem);
As far as casting vs. an interface, an interface is a bit more flexible of an approach. If you tried to use this fragment in a different activity (not MainActivity) the casting approach would fail. If you are only ever going to use the fragment in this Activity then either would work.
I just started to learn the fragment API on Android.
I want just to send a message back to my containing activity(I did it). Now I want to clear a misunderstanding about downcasting.
Here is my fragment:
import android.content.Context;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.EditText;
public class DetailFragment extends Fragment {
private EditText textFirstName, textLastName, textAge;
private FragmentListener mListener;
public DetailFragment() {
}
#Override
public void onAttach(Context context) {
super.onAttach(context);
if (!(context instanceof FragmentListener)) throw new AssertionError();
mListener = (FragmentListener) context;
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_detail, container, false);
textFirstName = (EditText) rootView.findViewById(R.id.textFirstName);
textLastName = (EditText) rootView.findViewById(R.id.textLastName);
textAge = (EditText) rootView.findViewById(R.id.textAge);
Button doneButton = (Button) rootView.findViewById(R.id.done_button);
doneButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
done();
}
});
return rootView;
}
private void done() {
if (mListener == null) {
throw new AssertionError();
}
String firstName = textFirstName.getText().toString();
String lastName = textLastName.getText().toString();
int age = Integer.valueOf(textAge.getText().toString());
mListener.onFragmentFinish(firstName, lastName, age);
}
public interface FragmentListener {
void onFragmentFinish(String firstName, String lastName, int age);
}
}
I don't understand the downcasting here:
mListener = (FragmentListener) context;
How Context class relate to my FragmentListener interface?
I find this is contradictory to my knowledge about downcasting(Downcasting is casting to a subtype, downward to the inheritance tree.)
The two types, Context and FragmentListener are unrelated. However, a subclass of Context might implement the FragmentListener interface. Your onAttach() method checks that this is, in fact, what's happening and does the downcast so the FragmentListener functionality is available through the mListener member field.
Any Context (most likely an Activity) that attaches an instance of DetailFragment will need to implement DetailFragment.FragmentListener to avoid an AssertionError at run time.
There is an error in this line:
addSlide(AppIntroSampleSlider.newInstance(R.layout.app_intro1));
addSlide (android.support.v4.app.Fragment)
In AppIntroBase, it cannot be applied
My code is here:
import android.content.Intent;
import android.os.Bundle;
import android.widget.Toast;
import com.github.paolorotolo.appintro.AppIntro;
/**
* Created by Arvind on 2/6/2017.
*/
public class MyIntro extends AppIntro {
#Override
public void init(Bundle savedInstanceState) {
//adding the three slides for introduction app you can ad as many you needed
addSlide(AppIntroSampleSlider.newInstance(R.layout.app_intro1));
addSlide(AppIntroSampleSlider.newInstance(R.layout.app_intro2));
addSlide(AppIntroSampleSlider.newInstance(R.layout.app_intro3));
// Show and Hide Skip and Done buttons
showStatusBar(false);
showSkipButton(false);
// Turn vibration on and set intensity
// You will need to add VIBRATE permission in Manifest file
setVibrate(true);
setVibrateIntensity(30);
//Add animation to the intro slider
setDepthAnimation();
}
#Override
public void onSkipPressed() {
// Do something here when users click or tap on Skip button.
Toast.makeText(getApplicationContext(),
getString(R.string.app_intro_skip), Toast.LENGTH_SHORT).show();
Intent i = new Intent(getApplicationContext(), MainActivity.class);
startActivity(i);
}
#Override
public void onNextPressed() {
// Do something here when users click or tap on Next button.
}
#Override
public void onDonePressed() {
// Do something here when users click or tap tap on Done button.
finish();
}
#Override
public void onSlideChanged() {
// Do something here when slide is changed
}
}
I created a class i.e. AppIntroSampleSlider.
My AppIntroSampleSlider class is:
package com.example.arvind.appintro1;
import android.app.Fragment;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
/**
* Created by Arvind on 13-Feb-17.
*/
public class AppIntroSampleSlider extends Fragment {
private static final String ARG_LAYOUT_RES_ID = "layoutResId";
public static AppIntroSampleSlider newInstance(int layoutResId) {
AppIntroSampleSlider sampleSlide = new AppIntroSampleSlider();
Bundle bundleArgs = new Bundle();
bundleArgs.putInt(ARG_LAYOUT_RES_ID, layoutResId);
sampleSlide.setArguments(bundleArgs);
return sampleSlide;
}
private int layoutResId;
public AppIntroSampleSlider() {}
#Override
public void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if(getArguments() != null && getArguments().containsKey(ARG_LAYOUT_RES_ID))
layoutResId = getArguments().getInt(ARG_LAYOUT_RES_ID);
}
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
return inflater.inflate(layoutResId, container, false);
}
}
I want to why it is showing error in the code.So Please help me to solve this error.
I found a better example without error
http://www.androidhive.info/2016/05/android-build-intro-slider-app/
AppIntro library works best with the following import in your AppIntroSampleSlider.java file:
import android.support.v4.app.Fragment;
Instead of:
import android.app.Fragment;
How to send data to another fragment in one activity?
I have two fragment that have been created using Android Studio Design View Editor. I ccreated these two fragment on my MainActivity. fragment1 is the ID of first fragment, it contain just EditText and a button. fragment2 is the ID of second fragment, it just contain textView.
How to send data from EditText of fragment1 to textView of fragment2?
I have write some code below, please check it.
MainActivity.java
package com.example.radioswiba.belajar2buahfragment;
import android.net.Uri;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
public class MainActivity extends AppCompatActivity implements Fragment1.OnFragmentInteractionListener, Fragment2.OnFragmentInteractionListener{
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
#Override
public void onFragmentInteraction(Uri uri) {
}
}
Fragment1.java
//this code was generated by Android Studio
//i have deleted some unused code and comments
package com.example.radioswiba.belajar2buahfragment;
import android.content.Context;
import android.net.Uri;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.EditText;
public class Fragment1 extends Fragment {
//let's define some of variable
private EditText text_input;
private Button button_send;
private OnFragmentInteractionListener mListener;
public Fragment1() {
// Required empty public constructor
}
//this generated by Android Studio
public static Fragment1 newInstance(String param1, String param2) {
Fragment1 fragment = new Fragment1();
Bundle args = new Bundle();
args.putString(ARG_PARAM1, param1);
args.putString(ARG_PARAM2, param2);
fragment.setArguments(args);
return fragment;
}
//this generated by Android Studio
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getArguments() != null) {
mParam1 = getArguments().getString(ARG_PARAM1);
mParam2 = getArguments().getString(ARG_PARAM2);
}
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
// my code here
View rootView = inflater.inflate(R.layout.fragment_fragment1, container, false);
text_input = (EditText) rootView.findViewById(R.id.status_text);
button_send = (Button) rootView.findViewById(R.id.post_btn);
button_send.setOnClickListener(postStatus);
return rootView;
}
View.OnClickListener postStatus = new View.OnClickListener(){
#Override
public void onClick(View v){
text_of_me = text_input.getText().toString();
//
//WHAT SHOULD I WRITE HERE?
//SHOULD I USED BUNDLE?
}
};
// TODO: Rename method, update argument and hook method into UI event
public void onButtonPressed(Uri uri) {
if (mListener != null) {
mListener.onFragmentInteraction(uri);
}
}
#Override
public void onAttach(Context context) {
super.onAttach(context);
if (context instanceof OnFragmentInteractionListener) {
mListener = (OnFragmentInteractionListener) context;
} else {
throw new RuntimeException(context.toString()
+ " must implement OnFragmentInteractionListener");
}
}
#Override
public void onDetach() {
super.onDetach();
mListener = null;
}
public interface OnFragmentInteractionListener {
// TODO: Update argument type and name
void onFragmentInteraction(Uri uri);
}
}
Fragment2.java
//the code almost same with Fragment1.java
I have search similar quenstion on stackoverflow, but i can not figure out. I have found many solution like below:
Fragment fragment = new Fragment();
Bundle bundle = new Bundle();
bundle.putInt(key, value);
fragment.setArguments(bundle);
There we create a new Fragment, meanwhile i have had two fragment on my activity, i have create it manually from file -> new -> new fragment from android Studio Menu. Should i create new Fragment by using above code?
A good way to communicate between fragments and/or activities is with Otto, an event bus library.
if you implement it correctly, I am quite confident it gonna solve your issue.
Here is few examples :
http://www.vogella.com/tutorials/JavaLibrary-EventBusOtto/article.html
https://github.com/CardinalNow/event-bus-example
http://www.recursiverobot.com/post/48752686831/playing-around-with-otto-on-android
I am trying to learn fragment.I am clicking a fragment class and my app crashes.I have declared it in the manifest..But why it is happening..My Menu class
public class Menu extends ListActivity {
String classes[] = { "SpinnerDemo", "GridDemo", "AutoCompleteDemo", "DynamicDemo",
"WebViewDemo1", "WebViewDemo3", "LaunchDemo", "LifecycleLoggingActivity", "IntentCheckActivity", "CallIntentActivity",
"MainFragmentDemoActivity", "Simplebrowser", "Flipper", "SharedPrefs", "Internaldata",
"Externaldata", "Sqliteexample", "GLexample", "TextVoice",
"StatusBar", "SeekBarVolume" };
#Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
setListAdapter(new ArrayAdapter<String>(Menu.this,
android.R.layout.simple_list_item_1, classes));
}
#Override
protected void onListItemClick(ListView l, View v, int position, long id) {
// TODO Auto-generated method stub
super.onListItemClick(l, v, position, id);
Class ourclass;
String path = classes[position];
try {
ourclass = Class.forName("com.example.practise." + path);
Intent ourintent = new Intent(Menu.this, ourclass);
startActivity(ourintent);
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
My MainFragmentDemoActivity class
public class MainFragmentDemoActivity extends Activity implements ListFragmentDemo.Communicator {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main_fragmenttesting);
}
#Override
public void Message(String os_name) {
DetailFragmentDemo detail=(DetailFragmentDemo)getFragmentManager().findFragmentById(R.id.detail_Fragment);
if (detail != null && detail.isInLayout()) {
detail.setText(os_name);
}
}
My menifest
<activity
android:name="com.example.practise.MainFragmentDemoActivity"
android:label="MainFragmentDemoActivity" >
</activity>
I have two other class ListFragmentDemo and DetailFragmentDemo.These are the fragments which i am implemening from MainFragmentDemoActivity.My xml
<fragment
android:id="#+id/list_Fragment"
android:layout_width="0dp"
android:layout_height="fill_parent"
android:layout_weight="1"
class="com.example.practise.ListFragmentDemo"></fragment>
<fragment
android:id="#+id/detail_Fragment"
android:layout_width="0dp"
android:layout_height="fill_parent"
android:layout_weight="2"
class="com.example.practise.DetailFragmentDemo">
</fragment>
logcat
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.practise/com.example.practise.MainFragmentDemoActivity}
Caused by: android.view.InflateException: Binary XML file line #8: Error inflating class fragment
Caused by: java.lang.ClassCastException: com.example.practise.ListFragmentDemo cannot be cast to android.app.Fragment
I am learning from this link
http://www.tutorialsbuzz.com/2014/03/android-fragments-example-ui-multi-pane.html
my ListFragmentDemo
package com.example.practise;
import android.app.Activity;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.Button;
import static android.widget.AdapterView.*;
public class ListFragmentDemo extends Fragment implements View.OnClickListener {
private Communicator communicator;
Button android_btn, ios_btn, window_btn;
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
if (activity instanceof Communicator) {
communicator = (Communicator) activity;
} else {
throw new ClassCastException(activity.toString() + "must implement ListFragmentDemo");
}
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.list_fragment, container, false);
android_btn = (Button) view.findViewById(R.id.android_btn_id);
ios_btn = (Button) view.findViewById(R.id.ios_btn_id);
window_btn = (Button) view.findViewById(R.id.windows_btn_id);
android_btn.setOnClickListener(this);
ios_btn.setOnClickListener(this);
window_btn.setOnClickListener(this);
return view;
}
public interface Communicator {
public void Message(String os_name);
}
#Override
public void onClick(View view) {
switch (view.getId()) {
case R.id.android_btn_id:
updateFragment("Android");
break;
case R.id.windows_btn_id:
updateFragment("Windows");
break;
case R.id.ios_btn_id:
updateFragment("IOS");
break;
}
}
private void updateFragment(String os_name){
communicator.Message(os_name);
}
}
My DetailFragmentDemo
package com.example.practise;
import android.os.Bundle;
import android.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
public class DetailFragmentDemo extends Fragment{
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view=inflater.inflate(R.layout.detail_fragment,container,false);
return view;
}
// we call this method when button from listfragment is clicked
public void setText(String item)
{
TextView textView=(TextView)getView().findViewById(R.id.display_tv);
textView.setText(item);
}
}
Your ListFragmentDemo extends from android.support.v4.app.Fragment (the support version of the Fragment class) and not android.app.Fragment (the version which is inside Android)
Change
import android.support.v4.app.Fragment;
to
import android.app.Fragment;
in the ListFragmentDemo class
Any Class that extends Activity in your application must be declared in the manifest, however, that does not appear to be your problem. Technically, this does answer your question though ;)
This line:
Caused by: java.lang.ClassCastException: com.example.practise.ListFragmentDemo cannot be cast to android.app.Fragment
Does "ListFragmentDemo" extend Fragment?
I think the problem is that you're Activity(Main Activity/ Activity that hosts the Fragments) doesn't extend the FragmentActivity class.
If you're using the Support Library for ActionBar, the just make sure your Activity class extends the ActionBarActivity class.
That's why your Fragments can't be cast into the Main Activity.(ClassCastException)
So it should be:
public class MainFragmentDemoActivity extends FragmentActivity .... {
or:
public class MainFragmentDemoActivity extends ActionBarActivity .... {
Open for correction, as always!
Regards,
Edward Quixote.