I've been working on Android App in AndroidStudio. Application has Fragment, let's call it MainFragment, and seperate Java Class file, let's call it SQLiteControler.class The problem is when i try to call method from Fragment in SQLiteController im getting null object reference as error Here is some minified code:
MainFragment
public class MainFragment extends Fragment {
...
//TextViews & ETC
public View onCreateView(@NonNull LayoutInflater inflater,
ViewGroup container, Bundle savedInstanceState) {
view = inflater.inflate(R.layout.fragment_profil, container, false);
return view:
}
public void someMethod(...){
textView.setText("abc");
//somecode
}
}
SQLiteController
public class SQLiteDataHelper {
private Context context;
MainFragment mainFragment;
public SQLiteDataHelper(Context context){
this.context = context;
mainFragment = new MainFragment();
}
public void anothermethod(){
mainFragment.someMethod(...)
}
}
Note: This is minified code
I have tried, a few my solutions like geting instance from MainFragment & ETC, and many more possible solutions from StackOverflow, but still getting same null object reference.
CodePudding user response:
Your problem is that your helper class is creating a totally new instance of MainFragment that has no association with the displayed fragment (views will be null).
You should not create a new fragment instance in the helper. You should define some sort of interface and use it to handle this type of coupling (or use a ViewModel and LiveData - preferred). If you wanted to go the custom interface route, you could define an interface like this:
interface DBDisplayer {
public void showText(String msg);
}
Then you can have your fragment implement this interface:
public class MainFragment extends Fragment implements DBDisplayer {
// I'll assume your helper is a singleton - if not, you'll need to figure
// out how to get an instance of it in your fragment.
private SQLiteDataHelper dbHelper = SQLiteDataHelper.getInstance();
public View onCreateView(@NonNull LayoutInflater inflater,
ViewGroup container, Bundle savedInstanceState) {
view = inflater.inflate(R.layout.fragment_profil, container, false);
return view:
}
@Override
public void onResume() {
super.onResume();
dbHelper.setDisplayer(this);
}
@Override
public void onPause() {
super.onPause();
// remove the displayer when the fragment is not being shown
dbHelper.setDisplayer(null);
}
@Override
public void showText(String msg){
textView.setText(msg);
}
}
Then your controller should have no dependencies on the Fragment, but take in an instance of the interface you defined
public class SQLiteDataHelper {
private Context context;
private DBDisplayer displayer = null;
public SQLiteDataHelper(Context context){
this.context = context;
}
public void setDisplayer(DBDisplayer d) {
displayer = d;
}
public void anothermethod(){
if( displayer != null ) {
displayer.showText("some words");
}
}
}
It would be much better, however, to make a ViewModel for the fragment that has LiveData for the things you want to display. The Fragment would just observe the LiveData and the ViewModel could handle querying the database helper and putting data into the LiveData.