Not able to use an interface since the object is null - java

I have a dialog that contains a button. When I press that button, I want the view of MainActivity to be changed.
I have tried it with an interface but I get this error:
java.lang.NullPointerException: Attempt to invoke interface method
'void ch.yourclick.kitt.classes.Popup$IControl.status(boolean)' on a
null object reference
Popup.java
public interface IControl {
void status(boolean status);
}
public IControl iControl = null;
#SuppressLint({"ClickableViewAccessibility", "ResourceType"})
#RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
#Nullable
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, Bundle savedInstanceState) {
final View view = inflater.inflate(_layout, container, false);
view.findViewById(R.id.turbineStartUp).setOnClickListener(v -> {
iControl.status(true);
});
MainActivity.java
public class MainActivity extends AppCompatActivity implements View.OnClickListener, Popup.IControl {
private final Popup mPopup = new Popup(R.layout.fragment_dialog);
#Override
public void status(boolean status) {
System.out.println(status);
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mPopup.iControl = this;
I don't see why the object is null, though I set mPopup.iControl = this; in onCreate(). What is wrong with my code?

The reason is that when the instruction
private final Popup mPopup = new Popup(R.layout.fragment_dialog);
is executed, it calls the class Popup.java with
public IControl iControl = null;
and runs onCreateView and here
iControl.status(true);
refers to null objet.
To fix that, i suggest to customize the constructor of Popup class by adding an Icontrol parameter, something like that
private final Popup mPopup = new Popup(R.layout.fragment_dialog, this);
and edit the Popup.java file

Related

Dialog on close: Keep the view changes

This is my dialog:
#SuppressLint("ValidFragment")
public class Popup extends DialogFragment {
private final int _layout;
#SuppressLint("ValidFragment")
public Popup(int layout) {
_layout = layout;
}
#SuppressLint({"ClickableViewAccessibility", "ResourceType"})
#RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
#Nullable
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, Bundle savedInstanceState) {
final View view = inflater.inflate(_layout, container, false);
return view;
}
And this is how I invoke it:
public class MainActivity extends AppCompatActivity implements View.OnClickListener, Popup.ICustomTts, Popup.ITarget, Popup.IDialog, Popup.IControl {
private final Popup mPopupTurbine = new Popup(R.layout.fragment_turbine);
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button turbineBtn = findViewById(R.id.turbine);
turbineBtn.setOnClickListener(view -> {
mPopupTurbine.show(getSupportFragmentManager(), "Speak");
});
When I click outside of that dialog, it will be closed. The problem is, I do some changes in that dialog (e.g. typed a text in TextView) and then I close that dialog. When I want to show it again, all the changes are lost. So how can I just hide the dialog so that the changes are still there when I re-display it?
I think in MainActivity I could add mPopupTurbine.getDialog().hide(); but where do I add this line of code?
You can use a ViewModel that lives throughout the life of your activity and remember your Popup fragment lives inside your activity.
Every time you make a change inside Popup save that data in a LiveData or Flow. Observe the LiveData inside Popup and update your UI.
You can post back entered data to your MainActivity:
#SuppressLint("ValidFragment")
public class Popup extends DialogFragment {
public Popup() {
// fragment constructor must be empty
}
private static final String LAYOUT_ID_KEY = "LAYOUT_ID_KEY";
private static final String PARAM1_KEY = "PARAM1_KEY";
public static Popup newInstance(int layoutId, String initialParam1) {
Popup popup = new Popup();
Bundle bundle = new Bundle();
bundle.putInt(LAYOUT_ID_KEY, layoutId);
bundle.putString(PARAM1_KEY, initialParam1);
popup.setArguments(bundle);
return popup;
}
private PopupCallback popupCallback;
#Override
public void onAttach(#NonNull Context context) {
super.onAttach(context);
popupCallback = (PopupCallback) context;
}
#Nullable
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, Bundle savedInstanceState) {
int layoutId = getArguments().getInt(LAYOUT_ID_KEY);
final View view = inflater.inflate(layoutId, container, false);
EditText editText = view.findViewById(R.id.edittext);
// set latest value of param1
editText.setText(getArguments().getString(PARAM1_KEY));
return view;
}
#Override
public void onDismiss(#NonNull DialogInterface dialog) {
EditText v = getView().findViewById(R.id.edittext);
// post back the param1
popupCallback.onDismissPopup(v.getText().toString());
super.onDismiss(dialog);
}
interface PopupCallback {
void onDismissPopup(String param1);
}
}
and receive and keep them in MainActivity:
public class MainActivity extends AppCompatActivity implements Popup.PopupCallback {
private String param1Backup;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button turbineBtn = findViewById(R.id.turbine);
turbineBtn.setOnClickListener(view -> {
Popup.newInstance(R.layout.fragment_turbine, param1Backup).show(getSupportFragmentManager(), "Speak");
});
}
#Override
public void onDismissPopup(String param1) {
param1Backup = param1;
}
}
Use viewModel to save your current values and attach the lifecycle of viewModel with your activity to save the current state.
Purpose of viewModel is to survive the configuration changes in your app.
You can use Singleton Class to save those data temporarily and moment you invoke it check if you have saved any data in it and put it back in your dialog.
public class SingletonClass{
public boolean isDialogDone;
public string dialogTitle, dialogMsg;
public static SingletonClass getInstance(){
if (instance == null) {
synchronized(SingletonClass.class) {
if (instance == null) {
instance = new SingletonClass();
}
}
}
return instance;
}
}
Then while invoking your dialogBox, you can simply check
if(!SingletonClass.getInstance().isDialogDone){
editText.setText(SingletonClass.getInstance().dialogMsg);
}
Ofc you also need to add listener to your EditText so that you can save the msg user is typing.

How to set up listeners nicely between fragments?

I have an app with 4 tabs, all are Fragments and have an adapter because I'm using RecyclerView. On the first tab I have items. I want the second tab to show the items that are checked on the first and listen to the changes. The 3rd tab shows the items from the 2nd tab (=1st tab checked items) when I click on a button on the first segment. Now I set the listeners in onCreate and onCreateView. Sometimes it's working, sometimes not. My suspicion is that the create methods aren't executed in the same order every time. The other problem is that sometimes my Fragment has to notify the listener, sometimes the the Fragment's adapter. How do I treat it nicely?
First tab (it's adapter will notify)
public class EventFragment extends Fragment implements BettingEventAdapter.BettingItemClickListener {
private RecyclerView recyclerView;
static private BettingEventAdapter adapter;
private BettingListDatabase database;
private static Answer bettingData = null;
private static final String TAG = "EVENT";
private static BettingEventAdapter.BettingItemClickListener listener;
public static void setListener(BettingEventAdapter.BettingItemClickListener _listener) {
listener = _listener;
}
#Override
public void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
database = BettingListDatabase.getInstance(this.getContext());
loadBettingData();
}
#Nullable
#Override
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable ViewGroup container,
#Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_events,
container, false);
recyclerView = view.findViewById(R.id.MainRecyclerView);
adapter = new BettingEventAdapter(this);
adapter.addBettingItemListener(listener);
recyclerView.setLayoutManager(new LinearLayoutManager(getActivity().getBaseContext()));
recyclerView.setAdapter(adapter);
loadItemsInBackground();
return view;
}
Second tab:
public class TicketFragment extends Fragment implements BettingEventAdapter.BettingItemClickListener {
private RecyclerView recyclerView;
TextView prizeTextView;
EditText stakeInput;
Button bSave;
private static BettingTicketAdapter.TicketSaveClickListener listener;
private BettingListDatabase database;
private BettingTicketAdapter adapter;
double odds=1;
int stake=0;
#Override
public void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
database = BettingListDatabase.getInstance(this.getContext());
EventFragment.setListener(this);
}
#Nullable
#Override
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_ticket,
container, false);
recyclerView = view.findViewById(R.id.TicketRecyclerView);
adapter = new BettingTicketAdapter();
recyclerView.setLayoutManager(new LinearLayoutManager(getActivity().getBaseContext()));
recyclerView.setAdapter(adapter);
}
Third tab:
public class TicketListFragment extends Fragment implements BettingTicketAdapter.TicketSaveClickListener {
private BettingTicketListAdapter parentAdapter;
private BettingListDatabase database;
#Override
public void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
database = BettingListDatabase.getInstance(this.getContext());
TicketFragment.setListener(this);
}
#Nullable
#Override
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
super.onCreateView(inflater, container, savedInstanceState);
View view = inflater.inflate(R.layout.fragment_ticket_list,
container, false);
RecyclerView parentRecyclerView = view.findViewById(R.id.SavedTicketParentRecyclerView);
parentAdapter = new BettingTicketListAdapter();
//TODO db-ből feltölteni
loadItemsInBackground();
parentRecyclerView.setLayoutManager(new LinearLayoutManager(getActivity().getBaseContext()));
parentRecyclerView.setAdapter(parentAdapter);
return view;
}
Pager activity:
public class PagerActivity extends AppCompatActivity {
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_pager);
}
#Override
protected void onResume() {
super.onResume();
ViewPager mainViewPager = findViewById(R.id.mainViewPager);
TabPagerAdapter tabPagerAdapter = new TabPagerAdapter(getSupportFragmentManager(), this);
mainViewPager.setAdapter(tabPagerAdapter);
}
}
https://developer.android.com/training/basics/fragments/communicating
To allow a Fragment to communicate up to its Activity, you can define an interface in the Fragment class and implement it within the Activity. The Fragment captures the interface implementation during its onAttach() lifecycle method and can then call the Interface methods in order to communicate with the Activity.
Here is an example for your Fragment:
EventFragment
public class EventFragment extends Fragment {
OnEventSelectedListener callback;
public void setOnEventSelectedListener(OnEventSelectedListener callback) {
this.callback = callback;
}
// This interface can be implemented by the Activity, parent Fragment,
// or a separate test implementation.
public interface OnEventSelectedListener {
public void onEventSelected(int position);
}
// ...
}
PagerActivity
public class PagerActivity extends AppCompatActivity implements EventFragment.OnEventSelectedListener{
// ...
// In order to receive event callbacks from the fragment, the activity that
// hosts it must implement the interface defined in the fragment class.
//For example, the following activity implements the interface from the above example.
public void onEventSelected(int position) {
// ...
}
#Override
public void onAttachFragment(Fragment fragment) {
if (fragment instanceof EventFragment) {
EventFragment eventFragment = (EventFragment) fragment;
eventFragment.setOnEventSelectedListener(this);
}
}
}
For example, the following method in the fragment is called when the user clicks on a list item. The fragment uses the callback interface to deliver the event to the parent activity.
#Override
public void onListItemClick(ListView l, View v, int position, long id) {
// Send the event to the host activity
callback.onEventSelected(position);
}

Get data from EditText from Fragment to Activity

I need to pass String data from EditTexts from Fragment to Activity, I know that I have to use interface. But I still have the same error (Null Object). Can you tell me how to fix it? Here is my code:
Main Activity
public class IntroActivity extends AppCompatActivity implements fragment_intro_activity_2.OnDataPass {
Button button_intro;
EditText et;
boolean showingFirst;
String wynik;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_intro);
button_intro = findViewById(R.id.button_intro);
et = findViewById(R.id.edOperetka);
FullScreencall();
getSupportFragmentManager().beginTransaction().replace(R.id.frame_contrainer_intro,
new fragment_intro_activity_1()).commit();
showingFirst = true;
button_intro.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if(showingFirst==true){
getSupportFragmentManager().beginTransaction().replace(R.id.frame_contrainer_intro,
new fragment_intro_activity_2()).commit();
showingFirst = false;
}else {
//
// Toast.makeText(IntroActivity.this, "123123", Toast.LENGTH_SHORT).show();
wynik = et.getText().toString();
onDataPass(wynik);
}
}
});
}
Fragment
public class fragment_intro_activity_2 extends Fragment {
View v;
OnDataPass dataPasser;
public fragment_intro_activity_2() {
// Required empty public constructor
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
v = inflater.inflate(R.layout.fragment_fragment_intro_activity_2, container, false);
return v;
}
public interface OnDataPass {
void onDataPass(String data);
}
#Override
public void onAttach(Context context) {
super.onAttach(context);
dataPasser = (OnDataPass) context;
}
public void passData(String data) {
dataPasser.onDataPass(data);
}
}
Logcat
Process: com.example.wynagrodzeniedodatkowe, PID: 32263
java.lang.NullPointerException: Attempt to invoke virtual method 'android.text.Editable android.widget.EditText.getText()' on a null object reference
at com.example.wynagrodzeniedodatkowe.IntroActivity$1.onClick(IntroActivity.java:54
And this 54 line is this: wynik = et.getText().toString();
Looking at the logcat message, it tells me that the following line
findViewById(R.id.edOperetka)
Returns null so make sure that the ID is created correctly in the XML and references correctly from the code (that it's the same ID).
If you wan't to retrieve the EditText inside your fragment you can do the following.
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
v = inflater.inflate(R.layout.fragment_fragment_intro_activity_2, container, false);
EditText et = v.findViewById(R.id.edOperetka);
return v;
}
Now you can retrieve the text from as you did before.

How to deal with bad_alloc in android java

I am using a ViewPager to show fragments. When i swipe it multiple times it gives following error:
E/libc++abi: terminating with uncaught exception of type std::bad_alloc: std::bad_alloc
--------- beginning of crash
A/libc: Fatal signal 6 (SIGABRT), code -6 in tid 6900
I am showing and caching image (using this) as well as i am using TextView to show text on Fragment.
I tried to get help from other links but could not get succeed.
I tried to duplicate your issue on my side, however I'm not getting the error but the images are not loaded. But the files got cached in my internal storage. By the way, in your case, it is advisable to use Picasso or Universal Image Loader as those libraries will handle loading, caching and even error. This may not be your direct solution to your problem, but just in case if you're looking for alternative, you can try this solution.
For the sake of simplicity, I am using Picasso. I have created an example project just in case if you need reference. You need to add compile 'com.squareup.picasso:picasso:2.5.2' in your gradle dependency;
1) Fragment
public class FragmentImage extends Fragment {
private TextView imageName;
private ImageView image;
public static final String IMAGE_URL = "link";
public static final String POSITION = "position";
private String url = null;
private int position = 0;
public static FragmentImage newInstance(String link, int position) {
// Required empty public constructor
FragmentImage fragmentImage = new FragmentImage();
Bundle bundle = new Bundle();
bundle.putString(IMAGE_URL, link);
bundle.putInt(POSITION, position);
fragmentImage.setArguments(bundle);
return fragmentImage;
}
#Override
public void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if(null != getArguments()){
url = getArguments().getString(IMAGE_URL);
position = getArguments().getInt(POSITION);
}
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_fragment_image, container, false);
}
#Override
public void onViewCreated(View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
image = (ImageView)view.findViewById(R.id.image);
imageName = (TextView)view.findViewById(R.id.imageName);
imageName.setText("Position "+position);
Picasso.with(getActivity())
.load(url)
.placeholder(R.mipmap.ic_launcher)
.error(R.mipmap.ic_launcher)
.into(image);
}
}
2) FragmentAdapter
public class FragmentImagePager extends FragmentPagerAdapter {
private String[] imageUrls = {"https://www.ricoh.com/r_dc/caplio/r7/img/sample_04.jpg",
"http://i-cdn.phonearena.com/images/articles/47012-image/photo2.jpg",
"http://www.flooringvillage.co.uk/ekmps/shops/flooringvillage/images/request-a-sample--547-p.jpg",
"http://www.cameraegg.org/wp-content/uploads/2013/03/Canon-EOS-100D-Rebel-SL1-Sample-Image.jpg",
"http://imgsv.imaging.nikon.com/lineup/lens/singlefocal/wide/af-s_35mmf_14g/img/sample/sample4_l.jpg"};
public FragmentImagePager(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int position) {
return FragmentImage.newInstance(imageUrls[position], position);
}
#Override
public int getCount() {
return imageUrls.length;
}
}
3) Activity
public class MainActivity extends AppCompatActivity{
private ViewPager fragmentList;
private FragmentImagePager fragmentImagePager;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
fragmentList = (ViewPager)findViewById(R.id.fragmentList);
fragmentImagePager = new FragmentImagePager(getSupportFragmentManager());
fragmentList.setAdapter(fragmentImagePager);
fragmentList.setOffscreenPageLimit(fragmentImagePager.getCount());
}
}

Subclassed fragment onCreateView

for the sake of not duplicating the code I've decided in my program to create a BaseFragment (which extends Fragment) to hold for some boilerplate data and provide proper handling of pause/resume, as well as the newInstance(String myPram) method. Long story short: The role of the BaseFragment is to ensure the saving and restoring of the state, i.e. restoring myPramas a local variable...
What I wanted to do next was to extend that BaseFragment in order to handle two different types of layout for two different Fragments (each of the needs the handling of the MyParam filed): EditFragment and DetailFragment.
The problem arises now, because no View is inflated for the Fragment, though they are added as a transaction (so they are transparent!).
EditFragment and DetailFragment both provide the onCreateView() method, in order to build their own views, I am they are correct since I managed to create them without the "subclassing mechanism", and of course BaseFragment does not provide an implementation of the onCreateView() but no result, they draw no UI.
I tried putting some super.onCreateView() here and there, with no result as well...What am I doing wrong?
Here's the base Fragment:
public class TimetableBaseFragment extends Fragment {
public static String ID_FIELD = "id";
public static String ID_DESC = "desc";
private String id;
private String desc;
// Constructor to deliver previous position along with itself
public static Fragment newInstance(String id, String desc) {
TimetableBaseFragment f = new TimetableBaseFragment();
Bundle args = new Bundle();
args.putString(ID_FIELD, id);
args.putString(ID_DESC, desc);
f.setArguments(args);
return f;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Bundle args = getArguments();
if (args != null) {
id = args.getString(ID_FIELD);
desc = args.getString(ID_DESC);
}
if (savedInstanceState != null) {
id = savedInstanceState.getString(ID_FIELD);
desc = savedInstanceState.getString(ID_DESC);
}
}
#Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putString(ID_FIELD, id);
outState.putString(ID_DESC, desc);
}
#Override
public void onActivityCreated(#Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
if (savedInstanceState != null) {
id = savedInstanceState.getString(ID_FIELD);
desc = savedInstanceState.getString(ID_DESC);
}
}
public String getExamId() {
return id;
}
public String getExamDesc() {
return desc;
}
}
And the one I am trying to add is:
public class TimetableEditFragment extends TimetableBaseFragment {
private LinearLayout mLlEditEmpty;
private ArrayList<ScheduleUser> lessons;
private TimetableEditRecyclerViewAdapter mAdapter;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
lessons = new ArrayList<>();
mAdapter = new TimetableEditRecyclerViewAdapter(getActivity());
}
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
ViewGroup rootView = (ViewGroup) inflater.inflate(R.layout.fragment_timetable_edit, container, false);
mLlEditEmpty = (LinearLayout) rootView.findViewById(R.id.LOGIC_empty);
RecyclerView mRvEdit = (RecyclerView) rootView.findViewById(R.id.HEADER_rv);
mRvEdit.setHasFixedSize(true);
mRvEdit.setLayoutManager(new LinearLayoutManager(getActivity()));
mRvEdit.addItemDecoration(new DividerItemDecoration(getActivity(), DividerItemDecoration.VERTICAL_LIST));
mRvEdit.setAdapter(mAdapter);
Toolbar examDesc = (Toolbar) rootView.findViewById(R.id.HEADER_examDesc);
examDesc.setTitle("TOOLBAR Testing");
FloatingActionButton add_fab = (FloatingActionButton) rootView.findViewById(R.id.EDIT_fab);
add_fab.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
addLesson(new ScheduleUser());
}
});
return rootView;
}
public void addLesson(ScheduleUser newItem) {
lessons.add(newItem);
mAdapter.notifyItemInserted(lessons.size() - 1);
}
public class TimetableEditRecyclerViewAdapter extends RecyclerView.Adapter<TimetableEditRecyclerViewAdapter.ViewHolder> {
/* Lots of stuff */
}
}
PS: I've noticed that it's very likely that the child onCreateView() does not get called at all, since I had an error, which was due to be fund at runtime, but the system did not notify.
Please help!

Categories