The issue I have is there're always Null Pointer Exception when I settext textview, so I cannot setText to my view.
I think the object didn't fill the field from getData method. How to fix this?
I am following this step https://firebase.google.com/docs/firestore/query-data/listen#listen_to_multiple_documents_in_a_collection and this Parcelable object passing from android activity to fragment.
This is the error output from android studio console
E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.my.plkbi, PID: 24337
java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.String com.my.plkbi.Layanan.getSyarat()' on a null object reference
at com.my.plkbi.SubMainFragment.onCreateView(SubMainFragment.java:78)
at androidx.fragment.app.Fragment.performCreateView(Fragment.java:2600)
at androidx.fragment.app.FragmentManagerImpl.moveToState(FragmentManagerImpl.java:881)
at androidx.fragment.app.FragmentManagerImpl.moveFragmentToExpectedState(FragmentManagerImpl.java:1238)
at androidx.fragment.app.FragmentManagerImpl.moveToState(FragmentManagerImpl.java:1303)
at androidx.fragment.app.BackStackRecord.executeOps(BackStackRecord.java:439)
at androidx.fragment.app.FragmentManagerImpl.executeOps(FragmentManagerImpl.java:2079)
at androidx.fragment.app.FragmentManagerImpl.executeOpsTogether(FragmentManagerImpl.java:1869)
at androidx.fragment.app.FragmentManagerImpl.removeRedundantOperationsAndExecute(FragmentManagerImpl.java:1824)
at androidx.fragment.app.FragmentManagerImpl.execPendingActions(FragmentManagerImpl.java:1727)
at androidx.fragment.app.FragmentManagerImpl$2.run(FragmentManagerImpl.java:150)
at android.os.Handler.handleCallback(Handler.java:751)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:6119)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:886)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:776)
EDIT: Add constructor to add object from other object, I follow this How do I copy an object in Java?
This is the object about the field database and Parcelable
public class Layanan implements Parcelable {
private String Nama;
private String Syarat;
private String Langkah;
private String Lampiran;
public Layanan(){
//this("connect to internet", "connect to internet", "connect to internet", "connect to internet");
}
//Constructor to add value from another object
public Layanan(Layanan another) {
this.nama = another.nama;
this.syarat = another.syarat;
this.langkah = another.langkah;
this.lampiran = another.lampiran;
this.deskripsi = another.deskripsi;
}
protected Layanan(Parcel in) {
Nama = in.readString();
Syarat = in.readString();
Langkah = in.readString();
Lampiran = in.readString();
}
public static final Creator<Layanan> CREATOR = new Creator<Layanan>() {
#Override
public Layanan createFromParcel(Parcel in) {
return new Layanan(in);
}
#Override
public Layanan[] newArray(int size) {
return new Layanan[size];
}
};
public static Layanan newInstance() {
Bundle args = new Bundle();
Layanan fragment = new Layanan();
fragment.setArguments(args);
return fragment;
}
private void setArguments(Bundle args) {
}
public String getNama() {
return Nama;
}
public String getSyarat() {
return Syarat;
}
public void setSyarat(String syarat) {
Syarat = syarat;
}
public String getLangkah() {
return Langkah;
}
public void setNama(String nama) {
Nama = nama;
}
public void setLangkah(String langkah) {
Langkah = langkah;
}
public String getLampiran() {
return Lampiran;
}
public void setLampiran(String lampiran) {
Lampiran = lampiran;
}
#Override
public int describeContents() {
return 0;
}
#Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(Nama);
dest.writeString(Syarat);
dest.writeString(Langkah);
dest.writeString(Lampiran);
}
}
This is how i get data from Firebase, it's inside in activity
Layanan UP;
Layanan GU;
Layanan LS;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if(savedInstanceState == null) {
//initMF();
MainFragment homeFragment = MainFragment.newInstance();
Bundle extras = new Bundle();
getData("UP");
Log.d(TAG, "This is the value name of " + UP.getNama()); //Output: This is the value name of null
extras.putParcelable(UPParcelable, UP);
if (UP.getSyarat()!=null) Log.d(TAG, "Value Added");
if (UP.getSyarat()==null) Log.d(TAG, "Value not Added"); //Output: Value not Added
homeFragment.setArguments(extras);
getSupportFragmentManager().beginTransaction().add(R.id.main_activity, homeFragment).commit();
}
...
...
public void getData(final String p){
mFirebase.collection("panduan_layanan")
.whereEqualTo("nama", p)
.addSnapshotListener(new EventListener<QuerySnapshot>() {
#Override
public void onEvent(#Nullable QuerySnapshot value, #Nullable FirebaseFirestoreException e) {
if (e != null){
Log.w(TAG, "onEvent:error", e);
return;
}
Layanan newLayanan = new Layanan();
for (QueryDocumentSnapshot doc : value) {
if (doc.get("nama") != null && doc.get("syarat") != null && doc.get("langkah") != null && doc.get("lampiran")!= null){
newLayanan.setNama(doc.getString("nama"));
newLayanan.setLampiran(doc.getString("lampiran"));
newLayanan.setLangkah(doc.getString("langkah"));
newLayanan.setSyarat(doc.getString("syarat"));
Log.d(TAG, "Update data: Success" + p);
Log.d(TAG, "This is the " + p + " syarat" + newLayanan.getSyarat());
if (newLayanan.getSyarat() != null) Log.d(TAG, "new layanan is" + newLayanan.getNama()); //new layanan isUP, it is work too
}
}
if (p.equals("UP")) UP = new Layanan(newLayanan);
Log.d(TAG, "the" + UP.getNama()); //Output theUP so it is work in here
if (p.equals("GU")) GU = new Layanan(newLayanan);
if (p.equals("LS")) LS = new Layanan(newLayanan);
}
});
}
...
Thank you so much
You can't do that because firebase execute that block asynchronously. So the field doesn't get value immediately just like Frank's comment said
Related
I am trying to update the UI depending on whether the data is being loaded or has loaded but it is not working properly. I am using enum class for different states.
Initially the error was
Attempt to invoke virtual method 'void androidx.lifecycle.LiveData.observe(androidx.lifecycle.LifecycleOwner, androidx.lifecycle.Observer)' on a null object reference
Then I passed an empty new MutableLiveData()<>. Now, it doesn't crashes the application, however, the getDataStatus() observer isn't working correctly. Kindly look at my implementations and see if they are right.
DataSource
public class ArticlesDataSource extends PageKeyedDataSource<Integer, NewsItem> {
private static final int FIRST_PAGE = 1;
private static final String TAG = "ArticlesDataSource";
public static final String SORT_ORDER = "publishedAt";
public static final String LANGUAGE = "en";
public static final String API_KEY = Utils.API_KEY;
public static final int PAGE_SIZE = 10;
private String mKeyword;
private MutableLiveData<DataStatus> dataStatusMutableLiveData = new MutableLiveData<>();
public ArticlesDataSource(String keyword) {
mKeyword = keyword;
dataStatusMutableLiveData = new MutableLiveData<>();
}
public MutableLiveData<DataStatus> getDataStatusMutableLiveData() {
return dataStatusMutableLiveData;
}
#Override
public void loadInitial(#NonNull LoadInitialParams<Integer> params, #NonNull LoadInitialCallback<Integer, NewsItem> callback) {
dataStatusMutableLiveData.postValue(DataStatus.LOADING);
NewsAPI newsAPI = ServiceGenerator.createService(NewsAPI.class);
Call<RootJsonData> call = newsAPI.searchArticlesByKeyWord(mKeyword, SORT_ORDER, LANGUAGE, API_KEY, FIRST_PAGE, PAGE_SIZE);
call.enqueue(new Callback<RootJsonData>() {
#Override
public void onResponse(Call<RootJsonData> call, Response<RootJsonData> response) {
if (response.body() != null) {
callback.onResult(response.body().getNewsItems(), null, FIRST_PAGE + 1);
dataStatusMutableLiveData.postValue(DataStatus.LOADED);
}
}
#Override
public void onFailure(Call<RootJsonData> call, Throwable t) {
Log.d(TAG, "onFailure: " + t.getMessage());
dataStatusMutableLiveData.postValue(DataStatus.ERROR);
}
});
}
#Override
public void loadBefore(#NonNull LoadParams<Integer> params, #NonNull LoadCallback<Integer, NewsItem> callback) {
NewsAPI newsAPI = ServiceGenerator.createService(NewsAPI.class);
Call<RootJsonData> call = newsAPI.searchArticlesByKeyWord(mKeyword, SORT_ORDER, LANGUAGE, API_KEY, FIRST_PAGE, PAGE_SIZE);
call.enqueue(new Callback<RootJsonData>() {
#Override
public void onResponse(Call<RootJsonData> call, Response<RootJsonData> response) {
// if the current page is greater than one
// we are decrementing the page number
// else there is no previous page
Integer adjacentKey = (params.key > 1) ? params.key - 1 : null;
if (response.body() != null) {
// passing the loaded data
// and the previous page key
callback.onResult(response.body().getNewsItems(), adjacentKey);
}
}
#Override
public void onFailure(Call<RootJsonData> call, Throwable t) {
Log.d(TAG, "onFailure: " + t.getMessage());
}
});
}
#Override
public void loadAfter(#NonNull LoadParams<Integer> params, #NonNull LoadCallback<Integer, NewsItem> callback) {
NewsAPI newsAPI = ServiceGenerator.createService(NewsAPI.class);
Call<RootJsonData> call = newsAPI.searchArticlesByKeyWord(mKeyword, SORT_ORDER, LANGUAGE, API_KEY, params.key, PAGE_SIZE);
call.enqueue(new Callback<RootJsonData>() {
#Override
public void onResponse(Call<RootJsonData> call, Response<RootJsonData> response) {
dataStatusMutableLiveData.postValue(DataStatus.LOADED);
if (response.code() == 429) {
// no more results
List<NewsItem> emptyList = new ArrayList<>();
callback.onResult(emptyList, null);
}
if (response.body() != null) {
// if the response has next page
// incrementing the next page number
Integer key = params.key + 1;
// passing the loaded data and next page value
if (!response.body().getNewsItems().isEmpty()) {
callback.onResult(response.body().getNewsItems(), key);
}
}
}
#Override
public void onFailure(Call<RootJsonData> call, Throwable t) {
Log.d(TAG, "onFailure: " + t.getMessage());
dataStatusMutableLiveData.postValue(DataStatus.ERROR);
}
});
}
}
DataSourceFactory
public class ArticlesDataSourceFactory extends DataSource.Factory {
private final MutableLiveData<ArticlesDataSource> itemLiveDataSource;
private String mQuery;
private final LiveData<DataStatus> dataStatusLiveData = Transformations.switchMap(itemLiveDataSource, (itemDataSource) -> {
return itemDataSource.getDataStatusMutableLiveData();
});
public ArticlesDataSourceFactory() {
mQuery = "news";
itemLiveDataSource = new MutableLiveData<>();
}
#Override
public DataSource<Integer, NewsItem> create() {
ArticlesDataSource itemDataSource = new ArticlesDataSource(mQuery);
itemLiveDataSource.postValue(itemDataSource);
// dataStatusMutableLiveData = itemDataSource.getDataStatusMutableLiveData();
return itemDataSource;
}
public MutableLiveData<ArticlesDataSource> getArticlesLiveDataSource() {
return itemLiveDataSource;
}
public void setQuery(String query) {
mQuery = query;
}
public MutableLiveData<DataStatus> getDataStatusMutableLiveData() {
return dataStatusMutableLiveData;
}
public void setDataStatusMutableLiveData(DataStatus dataStatus){
dataStatusMutableLiveData.postValue(dataStatus);
}
public LiveData<DataStatus> getDataStatusLiveData() {
return dataStatusLiveData;
}
}
ViewModel
public class ArticlesViewModel extends ViewModel {
public LiveData<PagedList<NewsItem>> itemPagedList;
private MutableLiveData<ArticlesDataSource> liveDataSource;
private ArticlesDataSourceFactory articlesDataSourceFactory;
private LiveData dataStatus = new MutableLiveData<>();
public ArticlesViewModel() {
articlesDataSourceFactory = new ArticlesDataSourceFactory();
liveDataSource = articlesDataSourceFactory.getArticlesLiveDataSource();
dataStatus = articlesDataSourceFactory.getDataStatusMutableLiveData();
PagedList.Config pagedListConfig =
(new PagedList.Config.Builder())
.setEnablePlaceholders(false)
.setPageSize(10).build();
itemPagedList = (new LivePagedListBuilder(articlesDataSourceFactory, pagedListConfig)).build();
}
public void setKeyword(String query) {
if (query.equals("") || query.length() == 0)
articlesDataSourceFactory.setDataStatusMutableLiveData(DataStatus.EMPTY);
else {
articlesDataSourceFactory.setQuery(query);
refreshData();
}
}
void refreshData() {
if (itemPagedList.getValue() != null) {
itemPagedList.getValue().getDataSource().invalidate();
}
}
public LiveData<DataStatus> getDataStatus() {
return dataStatus;
}
}
Fragment
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View rootView = inflater.inflate(R.layout.fragment_articles, container, false);
mContext = getActivity();
progressBar = rootView.findViewById(R.id.progress_circular);
emptyStateTextView = rootView.findViewById(R.id.empty_view);
swipeRefreshLayout = rootView.findViewById(R.id.swipe_refresh);
textViewTitle = rootView.findViewById(R.id.text_view_top_headlines);
recyclerView = rootView.findViewById(R.id.recycler_view);
if (savedInstanceState != null) {
keyword = savedInstanceState.getString("keyword");
}
initEmptyRecyclerView();
articlesViewModel = ViewModelProviders.of(this).get(ArticlesViewModel.class);
articlesViewModel.itemPagedList.observe(getViewLifecycleOwner(), new Observer<PagedList<NewsItem>>() {
#Override
public void onChanged(PagedList<NewsItem> newsItems) {
adapter.submitList(newsItems);
// TODO: Handle UI changes
// handleUIChanges(newsItems);
}
});
articlesViewModel.getDataStatus().observe(getViewLifecycleOwner(), new Observer<DataStatus>() {
#Override
public void onChanged(DataStatus dataStatus) {
switch (dataStatus) {
case LOADED:
progressBar.setVisibility(View.GONE);
emptyStateTextView.setVisibility(View.INVISIBLE);
swipeRefreshLayout.setRefreshing(false);
textViewTitle.setVisibility(View.VISIBLE);
break;
case LOADING:
progressBar.setVisibility(View.VISIBLE);
swipeRefreshLayout.setRefreshing(true);
textViewTitle.setVisibility(View.INVISIBLE);
emptyStateTextView.setVisibility(View.INVISIBLE);
break;
case EMPTY:
progressBar.setVisibility(View.GONE);
swipeRefreshLayout.setRefreshing(false);
textViewTitle.setVisibility(View.INVISIBLE);
emptyStateTextView.setVisibility(View.VISIBLE);
emptyStateTextView.setText(R.string.no_news_found);
break;
case ERROR:
progressBar.setVisibility(View.GONE);
swipeRefreshLayout.setRefreshing(false);
textViewTitle.setVisibility(View.INVISIBLE);
emptyStateTextView.setVisibility(View.VISIBLE);
emptyStateTextView.setText(R.string.no_internet_connection);
break;
}
}
});
swipeRefreshLayout.setOnRefreshListener(() -> {
articlesViewModel.setKeyword(keyword);
});
setHasOptionsMenu(true);
return rootView;
}
DataStatus
public enum DataStatus {
ERROR,
LOADING,
LOADED,
EMPTY
}
When you call invalidate(), a new datasource will be created by the factory. However, you are directly exposing the data status liveData of the "current" created datasource, without taking into consideration that more will be created in the future.
The solution is to store the current data source in the factory in a MutableLiveData, and expose the "most recent current data status" using switchMap.
public class ArticlesDataSourceFactory extends DataSource.Factory {
private final MutableLiveData<ArticlesDataSource> itemLiveDataSource = new MutableLiveData<>();
private String mQuery = "news";
private final LiveData<DataStatus> dataStatusLiveData = Transformations.switchMap(itemLiveDataSource, (itemDataSource) -> {
return itemDataSource.getDataStatusMutableLiveData();
});
public ArticlesDataSourceFactory() {
}
#Override
public DataSource<Integer, NewsItem> create() {
ArticlesDataSource itemDataSource = new ArticlesDataSource(mQuery);
itemLiveDataSource.postValue(itemDataSource);
...
public LiveData<DataStatus> getDataStatusLiveData() {
return dataStatusLiveData;
}
I have 2 model classes(Data,Title) which contain the same field:
String dataID. I want to get both of this IDs with interface implementation.
I am passing Title model through Bundle to another Activity, passing Data model through Bundle in that same activity(just creating new instance of the activity and resetting information).
I want both of my model classes to implement SharedID interface, with method String getSharedId();
How can I get different ids but from different models? I need to put only one parameter and it should be String in my ViewModelFactory constructor.
public class Data implements SharedId,Parcelable {
private String text;
private String textHeader;
private int viewType;
private String mainId;
private String dataID;
public Data() { }
public String getDataID() {
return dataID;
}
public void setDataID(String dataID) {
this.dataID = dataID;
}
public String getText() {return (String) trimTrailingWhitespace(text); }
public void setText(String text) {
this.text = (String) trimTrailingWhitespace(text);
}
public String getTextHeader() {
return (String) trimTrailingWhitespace(textHeader);
}
public void setTextHeader(String textHeader) {
this.textHeader = textHeader;
}
public int getViewType() {
return viewType;
}
public void setViewType(int viewType) {
this.viewType = viewType;
}
public String getMainId() {
return mainId;
}
public void setMainId(String mainId) {
this.mainId = mainId;
}
protected Data(Parcel in) {
text = in.readString();
textHeader = in.readString();
viewType = in.readInt();
mainId = in.readString();
dataID = in.readString();
}
#Override
public String toString() {
return "Data{" +
"order=" +
", text='" + text + '\'' +
", textHeader='" + textHeader + '\'' +
", viewType=" + viewType +
'}';
}
#SuppressWarnings("StatementWithEmptyBody")
public static CharSequence trimTrailingWhitespace(CharSequence source) {
if (source == null) {
return "";
}
int i = source.length();
// loop back to the first non-whitespace character
while (--i >= 0 && Character.isWhitespace(source.charAt(i))) {
}
return source.subSequence(0, i + 1);
}
public static final Creator<Data> CREATOR = new Creator<Data>() {
#Override
public Data createFromParcel(Parcel in) {
return new Data(in);
}
#Override
public Data[] newArray(int size) {
return new Data[size];
}
};
#Override
public int describeContents() {
return 0;
}
#Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(text);
dest.writeString(textHeader);
dest.writeInt(viewType);
dest.writeString(mainId);
dest.writeString(dataID);
}
#Override
public String getSharedDataId() {
return getDataID();
}
}
public class Title implements SharedId,Parcelable {
private String dataID;
private String title;
public Title() { }
protected Title(Parcel in) {
dataID = in.readString();
title = in.readString();
}
public String getDataID() {
return dataID;
}
public void setDataID(String dataID) {
this.dataID = dataID;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public static final Creator<Title> CREATOR = new Creator<Title>() {
#Override
public Title createFromParcel(Parcel in) {
return new Title(in);
}
#Override
public Title[] newArray(int size) {
return new Title[size];
}
};
#Override
public int describeContents() {
return 0;
}
#Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(dataID);
dest.writeString(title);
}
#NonNull
#Override
public String toString() {
return "Title{" +
"dataID='" + dataID + '\'' +
", titleOrder=" +
", title='" + title + '\'' +
'}';
}
#Override
public String getSharedDataId() {
return getDataID();
}
}
And My DetailActivity code, I already succeeded with the mission of passing id, but i need to do this trough interfaces :( So help me out friends, would really appreciate it!
public class DetailActivity extends AppCompatActivity implements
DetailAdapter.OnDialogClickListener,
DetailAdapter.OnDetailClickListener {
private static String id;
private String parentId;
private Data data;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_detail);
TextView tvToolbarTitle = findViewById(R.id.title_toolbar_detail);
tvToolbarTitle.setSelected(true);
findViewById(R.id.btn_back).setOnClickListener(v -> finish());
ArrayList<SharedId> sharedIds = new ArrayList<>();
sharedIds.add(new Title());
sharedIds.add(new Data());
for (SharedId sharedId : sharedIds){
System.out.println(sharedId.getSharedDataId());
}
Bundle bundle = getIntent().getExtras();
if (bundle != null) {
Title model = bundle.containsKey("ID") ? bundle.getParcelable("ID") : null;
Data childModel = bundle.containsKey("idDetail") ? bundle.getParcelable("idDetail") : null;
}
if (bundle != null) {
Title model = bundle.containsKey("ID") ? bundle.getParcelable("ID") : null;
Data childModel = bundle.containsKey("idDetail") ? bundle.getParcelable("idDetail") : null;
String parentId = bundle.getString("mainScreenId");
if (parentId != null) {
this.parentId = parentId;
}
if (model != null) {
this.id = model.getDataID();
tvToolbarTitle.setText(model.getTitle());
}
if (childModel != null) {
this.id = childModel.getDataID();
tvToolbarTitle.setText(childModel.getTextHeader());
}
}
RecyclerView recyclerView = findViewById(R.id.rv_detail);
DetailAdapter adapter = new DetailAdapter(this, this);
recyclerView.setAdapter(adapter);
// TODO: 3/1/19 change it to single ID // DetailViewModelFactory(); // id != null ? id : parentId
DetailViewModelFactory detailViewModelFactory = new DetailViewModelFactory(id != null ? id : parentId);
DetailActivityViewModel viewModel = ViewModelProviders.of(this, detailViewModelFactory).get(DetailActivityViewModel.class);
FirebaseListLiveData<Data> liveData = viewModel.getLiveDataQuery();
liveData.observe(this, adapter::setNewData);
}
#Override
public void onDialogClicked(#NonNull String text) {
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setMessage(HtmlCompat.fromHtml(text, 0, null, new HandlerHtml()));
builder.setPositiveButton("Ok", null);
builder.show();
}
#Override
public void onDetailClicked(Data data) {
Intent intent = new Intent();
DetailActivity.open(DetailActivity.this);
intent.putExtra("idDetail", data);
intent.putExtra("mainScreenId", id);
startActivity(intent);
}
public static void open(#NonNull Context context) {
context.startActivity(new Intent(context, InfoActivity.class));
}
}
I found a bit different, but working solution!
I create an interface
public interface SharedId {
String getSharedDataId();
String getHeader();
}
Both of my model classes Data + Title implemented Interface and methods from it.
In DetailActivity i created 2 Strings.
private String mainId;
private String detailId;
And then passed ids with my model classes with bundle
`SharedId mainId = new Title();
SharedId detailId = new Data();
Bundle bundle = getIntent().getExtras();
if (bundle != null) {
mainId = bundle.containsKey("ID") ? bundle.getParcelable("ID") : null;
detailId = bundle.containsKey("idDetail") ?
bundle.getParcelable("idDetail") : null;
}
if (mainId != null) {
this.detailId = mainId.getSharedDataId();
tvToolbarTitle.setText(mainId.getHeader());
}
if (detailId != null) {
this.mainId = detailId.getSharedDataId();
tvToolbarTitle.setText(detailId.getHeader());
}
And passed in my ViewmodelFactory
DetailViewModelFactory detailViewModelFactory =
new DetailViewModelFactory(this.detailId != null ?
this.detailId : this.mainId);
public class FragmentPatientsByVital extends Fragment {
private RecyclerView mRecyclerView;
private ArrayList<Patient> mList;
private AdapterVitalPatient mAdapter;
private MultiStateToggleButton mMultiStateToggleButton;
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fragment_patient_by_vital, container, false);
initUi(v);
if (mList != null)
updateList(mList);
return v;
}
private void initUi(View v) {
mRecyclerView = (RecyclerView) v.findViewById(R.id.recycler_view);
mMultiStateToggleButton = (MultiStateToggleButton) v.findViewById(R.id.mstb_multi_id);
mRecyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
mMultiStateToggleButton.setOnValueChangedListener(new ToggleButton.OnValueChangedListener() {
#Override
public void onValueChanged(int position) {
mAdapter.filterBy(position);
}
});
}
public void updateList(ArrayList<Patient> mList) {
if (mList == null) return;
this.mList = mList;
if (mAdapter == null)
mAdapter = new AdapterVitalPatient(mList);
mRecyclerView.setAdapter(mAdapter);
}
public static FragmentPatientsByVital newIntance() {
FragmentPatientsByVital f = new FragmentPatientsByVital();
return f;
}
}
Adapter
public class AdapterVitalPatient extends RecyclerView.Adapter<AdapterVitalPatient.ViewHolder> {
private ArrayList<Patient> mList;
public AdapterVitalPatient(ArrayList<Patient> mList) {
this.mList = mList;
}
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
return new ViewHolder(InjectUtils.getInflator().inflate(R.layout.adapter_vital_patient, parent, false));
}
#Override
public void onBindViewHolder(ViewHolder holder, int position) {
Patient p = mList.get(position);
holder.mNameTextView.setText(p.getName());
if (mList.get(position).getSummary() != null) {
holder.updateRecords(mList.get(position).getSummary());
} else {
try {
holder.callApi(p.getEmail(), position);
} catch (Exception e) {
e.printStackTrace();
}
}
}
#Override
public int getItemCount() {
return mList.size();
}
public void filterBy(int position) {
switch (position) {
case 0: //!--- Any
break;
case 1: //!--- Normal
break;
case 2: //!--- High
break;
case 3: //!--- Low
break;
}
}
public class ViewHolder extends RecyclerView.ViewHolder {
private final TextView mNameTextView;
private final ProgressBar mProgressBar;
private final GridLayout mTableLayout;
public ViewHolder(View itemView) {
super(itemView);
mNameTextView = (TextView) itemView.findViewById(R.id.textview_title);
mProgressBar = (ProgressBar) itemView.findViewById(R.id.progress_bar);
mTableLayout = (GridLayout) itemView.findViewById(R.id.table_layout);
}
public void callApi(String email, final int pos) {
try {
RahaDelegates api = InjectUtils.getNetworkObj().create(RahaDelegates.class);
Call<String> call = api.getLatestVitals(String.format(RahaDelegates.GET_LATEST_VITALS, email));
InjectUtils.getNetworkClient().callApi(call, new ApiInterface() {
#Override
public void onResponse(boolean result, String completeResponse) {
Type token = new TypeToken<ArrayList<Vital>>() {
}.getType();
mList.get(getAdapterPosition()).setSummary((ArrayList<Vital>) InjectUtils.getGsonObj().fromJson(completeResponse, token));
updateRecords(mList.get(pos).getSummary());
mProgressBar.setVisibility(View.GONE);
}
#Override
public void onFailure(String message) {
mProgressBar.setVisibility(View.GONE);
}
});
} catch (Exception e){
e.printStackTrace();
}
}
public void updateRecords(ArrayList<Vital> details) {
mTableLayout.setVisibility(View.VISIBLE);
mProgressBar.setVisibility(View.GONE);
mTableLayout.removeAllViews();
for (int i = 0; i < details.size(); i++) {
Log.e("List Size", String.valueOf(details.size()));
Vital v = details.get(i);
if (!v.getVitalName().toLowerCase().contains("lungreco") && !v.getVitalName().toLowerCase().contains("kickco")) {
View view = InjectUtils.getInflator().inflate(R.layout.adapter_home_vital_patient, mTableLayout, false);
mTableLayout.addView(view);
TextView name = (TextView) view.findViewById(R.id.vital_name);
TextView value = (TextView) view.findViewById(R.id.vital_value);
name.setText(v.getVitalName());
if (v.getVitalName().toLowerCase().contains("bodyc")) {
value.setText(v.getFat() + "/" + v.getMuscale() + " " + v.getUnit());
} else if (v.getVitalName().toLowerCase().contains("temp")) {
if (v.getValue() != null) {
value.setText(Math.round(Float.valueOf(v.getValue())) + " " + v.getUnit());
}
} else if (v.getVitalName().toLowerCase().contains("heartra")) {
value.setText(v.getValue());
} else if (v.getVitalName().toLowerCase().contains("etalbe")) {
value.setText(v.getValue() + " " + v.getUnit());
} else if (v.getVitalName().toLowerCase().contains("bloodpres")) {
value.setText(v.getSystolic() + "/" + v.getDiastolic() + " " + v.getUnit());
} else if (v.getVitalName().toLowerCase().contains("loodoxy")) {
value.setText(v.getValue() + " " + v.getUnit());
} else if (v.getVitalName().toLowerCase().contains("oodglucos")) {
value.setText(v.getValue() + " " + v.getUnit());
}
}
}
}
}
}
02-10 09:06:39.430 1600-1600/? E/BoostFramework: Exception java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.Object java.lang.reflect.Method.invoke(java.lang.Object, java.lang.Object[])' on a null object reference
02-10 09:06:39.476 16831-17154/? E/AndroidCll-SettingsSync: Could not get or parse settings
02-10 09:06:39.547 16831-17062/? E/Appboy v2.5.0 .bo.app.cj: Received server error from request: invalid_api_key
02-10 09:06:39.547 16831-17062/? E/Appboy v2.5.0 .bo.app.ci: Error occurred while executing Braze request: invalid_api_key
02-10 09:06:39.603 16831-17154/? E/AndroidCll-SettingsSync: Could not get or parse settings
02-10 09:06:39.759 1600-1600/? E/BoostFramework: Exception java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.Object java.lang.reflect.Method.invoke(java.lang.Object, java.lang.Object[])' on a null object reference
02-10 09:06:41.294 16594-16594/sa.digitrends.rahah.doctor E/AndroidRuntime: FATAL EXCEPTION: main
Process: sa.digitrends.rahah.doctor, PID: 16594
java.lang.NullPointerException: Attempt to invoke virtual method 'int java.util.ArrayList.size()' on a null object reference
at sa.digitrends.doctor.adapter.AdapterVitalPatient$ViewHolder.updateRecords(AdapterVitalPatient.java:125)
at sa.digitrends.doctor.adapter.AdapterVitalPatient$ViewHolder$1.onResponse(AdapterVitalPatient.java:106)
at sa.app.base.retrofit.client.NetworkClient$1.onResponse(NetworkClient.java:60)
at retrofit2.ExecutorCallAdapterFactory$ExecutorCallbackCall$1$1.run(ExecutorCallAdapterFactory.java:68)
at android.os.Handler.handleCallback(Handler.java:754)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:163)
at android.app.ActivityThread.main(ActivityThread.java:6238)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:933)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:823)
02-10 09:06:41.761 16831-16831/? E/Referral: (LauncherApplication.java:890) restarted
You can remove below code segment from onBindView and add it inside another method that needs to fire when user do that relevant action
if (mList.get(position).getSummary() != null) {
holder.updateRecords(mList.get(position).getSummary());
} else {
try {
holder.callApi(p.getEmail(), position);
} catch (Exception e) {
e.printStackTrace();
}
}
then you can do notifydatasetchanged after get success response inside that public void onResponse(boolean result, String completeResponse)
It seems you have server error
Appboy v2.5.0 .bo.app.cj: Received server error from request: invalid_api_key 02-10 09:06:39.547 16831-17062/? E/Appboy v2.5.0 .bo.app.ci: Error occurred while executing Braze request: invalid_api_key 02-10 09:06:39.603 16831-17154
Error is due to NullPointerException
java.lang.NullPointerException: Attempt to invoke virtual method 'int java.util.ArrayList.size()' on a null object reference
Update updateRecords methods as below
public void updateRecords(#Nullable ArrayList<Vital> details) {
mProgressBar.setVisibility(View.GONE);
if(details == null) {
return;
}
. . .
. . .
. . .
}
In general there can be further improvement made.
Avoid making API calls directly from Fragments or any Classes having views
Parse response in background thread. Below code might block your main thread for long time, when response is huge.
InjectUtils.getGsonObj().fromJson(completeResponse, token)
I have 5 fragments inside my activity where one fragment stays active at one time. Clicking on a recyclerview item opens another fragment and puts current fragment in the backstack.
The same code was working fine some days ago, but now the app is throwing NotSerializableException whenever I click the home button to put the app in background. I have tried putting the initializing the variables inside onStart and then giving the null value in onStop but that didn't work.
Fragment Code:
public class PaperListFragment extends Fragment implements Serializable {
private static final String TAG = "PaperListFragment";
private static final String QUESTIONS_FRAGMENT_TAG = "questions_fragment";
private static final String ADD_PAPER_FRAGMENT_TAG = "add_paper_fragment";
private OnFragmentActiveListener mOnFragmentActiveListener;
private TextView mHeadingText;
private Bundle mOutState;
private FirebaseAuth mAuth;
private DatabaseReference mDatabaseReference;
private ProgressBar mProgressBar;
private OnItemClickListener mOnItemClickListener;
private FloatingActionButton mFab;
private RecyclerView mRecyclerViewPaper;
private ArrayList<Paper> mPaperList = new ArrayList<>();
private Subject mSubject = new Subject();
private Exam mExam = new Exam();
#Nullable
#Override
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_recycler_list, container, false);
mProgressBar = (ProgressBar) rootView.findViewById(R.id.progressbar_news);
mFab = (FloatingActionButton) rootView.findViewById(R.id.floatingActionButton);
mProgressBar.setVisibility(View.VISIBLE);
Log.d(TAG, "onCreateView: Fragment created");
mAuth = FirebaseAuth.getInstance();
mDatabaseReference = FirebaseDatabase.getInstance().getReference();
if (mAuth.getCurrentUser() == null) {
startActivity(new Intent(getActivity(), LoginActivity.class));
getActivity().finish();
return null;
}
if (getArguments() != null) {
mOnFragmentActiveListener = (OnFragmentActiveListener) getArguments().getSerializable(Keys.FRAGMENT_ACTIVE_LISTENER);
mSubject = (Subject) getArguments().getSerializable(Keys.SUBJECT_KEY);
mExam = (Exam) getArguments().getSerializable(Keys.EXAMS_KEY);
}
mRecyclerViewPaper = (RecyclerView) rootView.findViewById(R.id.recycler_list);
LinearLayoutManager layoutManager = new LinearLayoutManager(getActivity()) {
#Override
public boolean canScrollVertically() {
return false;
}
};
mRecyclerViewPaper.setLayoutManager(layoutManager);
Log.d(TAG, "onCreateView: Layout Manager Set.");
mFab.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
startAddPaperFragment();
}
});
mOnItemClickListener = new OnItemClickListener() {
#Override
public void onItemClicked(RecyclerView.ViewHolder holder, int position) {
Log.d(TAG, "onItemClicked: Clicked item position is: "+ position);
QuestionListFragment questionFragment = new QuestionListFragment();
questionFragment.setRetainInstance(true);
startFragment(position, questionFragment, QUESTIONS_FRAGMENT_TAG);
}
#Override
public void OnItemLongClicked(RecyclerView.ViewHolder holder, int position) {
}
};
mHeadingText = (TextView) rootView.findViewById(R.id.heading_textview);
mHeadingText.setText(mExam.getExam_name()+" > "+ mSubject.getSubject_name());
if (mOutState != null) {
mPaperList = (ArrayList<Paper>) mOutState.getSerializable(Keys.PAPER_LIST_KEY);
updateUI();
} else {
updateUIFromDatabase();
}
return rootView;
}
private void startFragment(int position, Fragment fragment, String fragmentTag) {
Paper paper = new Paper();
if (mPaperList.size() > 0) {
paper = mPaperList.get(position);
}
Bundle args = new Bundle();
args.putSerializable(Keys.EXAMS_KEY, mExam);
args.putSerializable(Keys.SUBJECT_KEY, mSubject);
args.putSerializable(Keys.PAPER, paper);
args.putSerializable(Keys.FRAGMENT_ACTIVE_LISTENER, mOnFragmentActiveListener);
fragment.setArguments(args);
FragmentTransaction fragmentTransaction = getActivity().getSupportFragmentManager().beginTransaction();
fragmentTransaction.setCustomAnimations(R.anim.slide_in_right, R.anim.slide_out_left, R.anim.slide_in_left, R.anim.slide_out_right);
fragmentTransaction.replace(R.id.questions_fragment_container, fragment, fragmentTag);
fragmentTransaction.addToBackStack(fragmentTag);
fragmentTransaction.commit();
}
private void startAddPaperFragment() {
AddPaperFragment addPaperFragment = new AddPaperFragment();
addPaperFragment.setRetainInstance(true);
startFragment(0, addPaperFragment, ADD_PAPER_FRAGMENT_TAG);
}
private void updateUIFromDatabase() {
if (getArguments() != null){
Exam exam = (Exam) getArguments().getSerializable(Keys.EXAMS_KEY);
Subject subject = (Subject) getArguments().getSerializable(Keys.SUBJECT_KEY);
DatabaseReference paperReference =
mDatabaseReference
.child(Keys.APP_DATA_KEY)
.child(Keys.EXAM_PAPERS)
.child(exam.getExam_name())
.child(subject.getSubject_name());
Query query = paperReference.orderByChild(Keys.TIME_ADDED);
query.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
mPaperList.clear();
for (DataSnapshot paperChild : dataSnapshot.getChildren()) {
mPaperList.add(paperChild.getValue(Paper.class));
}
updateUI();
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});
}
}
private void updateUI() {
PaperRecyclerAdapter adapter = new PaperRecyclerAdapter(
getActivity(),
mRecyclerViewPaper,
mPaperList,
mOnItemClickListener
);
mRecyclerViewPaper.setAdapter(adapter);
mProgressBar.setVisibility(View.GONE);
}
#Override
public void onResume() {
super.onResume();
if (getArguments()!=null){
mOnFragmentActiveListener.onFragmentActive(
this,
"Topics"
);
}
}
#Override
public void onPause() {
super.onPause();
mOutState = new Bundle();
mOutState.putSerializable(Keys.PAPER_LIST_KEY, mPaperList);
}
}
Exception:
2018-12-26 17:49:38.344 14834-14834/in.crazybytes.bankmaniaadmin E/AndroidRuntime: FATAL EXCEPTION: main
Process: in.crazybytes.bankmaniaadmin, PID: 14834
java.lang.RuntimeException: Parcelable encountered IOException writing serializable object (name = in.crazybytes.bankmaniaadmin.activities.QuestionsActivity)
at android.os.Parcel.writeSerializable(Parcel.java:1526)
at android.os.Parcel.writeValue(Parcel.java:1474)
at android.os.Parcel.writeArrayMapInternal(Parcel.java:723)
at android.os.BaseBundle.writeToParcelInner(BaseBundle.java:1408)
at android.os.Bundle.writeToParcel(Bundle.java:1133)
at android.os.Parcel.writeBundle(Parcel.java:763)
at android.support.v4.app.FragmentState.writeToParcel(FragmentState.java:124)
at android.os.Parcel.writeTypedArray(Parcel.java:1306)
at android.support.v4.app.FragmentManagerState.writeToParcel(FragmentManager.java:639)
at android.os.Parcel.writeParcelable(Parcel.java:1495)
at android.os.Parcel.writeValue(Parcel.java:1401)
at android.os.Parcel.writeArrayMapInternal(Parcel.java:723)
at android.os.BaseBundle.writeToParcelInner(BaseBundle.java:1408)
at android.os.Bundle.writeToParcel(Bundle.java:1133)
at android.os.Parcel.writeBundle(Parcel.java:763)
at android.app.ActivityManagerProxy.activityStopped(ActivityManagerNative.java:3697)
at android.app.ActivityThread$StopInfo.run(ActivityThread.java:3768)
at android.os.Handler.handleCallback(Handler.java:751)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:6123)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:867)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:757)
Caused by: java.io.NotSerializableException: com.google.firebase.auth.internal.zzj
at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1224)
at java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.java:1584)
at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1549)
at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1472)
at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1218)
at java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.java:1584)
at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1549)
at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1472)
at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1218)
at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:346)
at android.os.Parcel.writeSerializable(Parcel.java:1521)
at android.os.Parcel.writeValue(Parcel.java:1474)
at android.os.Parcel.writeArrayMapInternal(Parcel.java:723)
at android.os.BaseBundle.writeToParcelInner(BaseBundle.java:1408)
at android.os.Bundle.writeToParcel(Bundle.java:1133)
at android.os.Parcel.writeBundle(Parcel.java:763)
at android.support.v4.app.FragmentState.writeToParcel(FragmentState.java:124)
at android.os.Parcel.writeTypedArray(Parcel.java:1306)
at android.support.v4.app.FragmentManagerState.writeToParcel(FragmentManager.java:639)
at android.os.Parcel.writeParcelable(Parcel.java:1495)
at android.os.Parcel.writeValue(Parcel.java:1401)
at android.os.Parcel.writeArrayMapInternal(Parcel.java:723)
at android.os.BaseBundle.writeToParcelInner(BaseBundle.java:1408)
at android.os.Bundle.writeToParcel(Bundle.java:1133)
at android.os.Parcel.writeBundle(Parcel.java:763)
at android.app.ActivityManagerProxy.activityStopped(ActivityManagerNative.java:3697)
at android.app.ActivityThread$StopInfo.run(ActivityThread.java:3768)
at android.os.Handler.handleCallback(Handler.java:751)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:6123)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:867)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:757)
Note: The weird thing is that one of fragment has the exact same code and is hosted inside the same activity, but when that fragment is active and app goes to background, interestingly the app is not crashing.
**Exam Model Class:
package in.crazybytes.bankmaniaadmin.models;
import java.io.Serializable;
public class Exam implements Serializable {
private String mExam_name;
private String mExam_key;
private Long mTime_added;
private int mNum_subjects;
private int mNum_questions;
public Exam(String exam_name, String exam_key, Long time_added, int num_subjects, int num_questions) {
mExam_name = exam_name;
mExam_key = exam_key;
mTime_added = time_added;
mNum_subjects = num_subjects;
mNum_questions = num_questions;
}
public Exam() {
}
public String getExam_name() {
return mExam_name;
}
public void setExam_name(String exam_name) {
mExam_name = exam_name;
}
public String getExam_key() {
return mExam_key;
}
public void setExam_key(String exam_key) {
mExam_key = exam_key;
}
public Long getTime_added() {
return mTime_added;
}
public void setTime_added(Long time_added) {
mTime_added = time_added;
}
public int getNum_subjects() {
return mNum_subjects;
}
public void setNum_subjects(int num_subjects) {
mNum_subjects = num_subjects;
}
public int getNum_questions() {
return mNum_questions;
}
public void setNum_questions(int num_questions) {
mNum_questions = num_questions;
}
}
Paper Model Class
package in.crazybytes.bankmaniaadmin.models;
import java.io.Serializable;
public class Paper implements Serializable {
private String mPaper_name;
private String mPaper_key;
private Long mTime_added;
private int mNum_questions;
public Paper(String paper_name, String paper_key, Long time_added, int num_questions) {
mPaper_name = paper_name;
mPaper_key = paper_key;
mTime_added = time_added;
mNum_questions = num_questions;
}
public Paper() {
}
public String getPaper_key() {
return mPaper_key;
}
public void setPaper_key(String paper_key) {
mPaper_key = paper_key;
}
public Long getTime_added() {
return mTime_added;
}
public void setTime_added(Long time_added) {
mTime_added = time_added;
}
public int getNum_questions() {
return mNum_questions;
}
public void setNum_questions(int num_questions) {
mNum_questions = num_questions;
}
public String getPaper_name() {
return mPaper_name;
}
public void setPaper_name(String paper_name) {
mPaper_name = paper_name;
}
}
Subject Model Class:
package in.crazybytes.bankmaniaadmin.models;
import java.io.Serializable;
public class Subject implements Serializable {
private String mSubject_name;
private String mSubject_key;
private Long mTime_added;
private int mNum_papers;
private int mNum_questions;
public Subject(String subject_name, String subject_key, Long time_added, int num_papers, int num_questions) {
mSubject_name = subject_name;
mSubject_key = subject_key;
mTime_added = time_added;
mNum_papers = num_papers;
mNum_questions = num_questions;
}
public Subject() {
}
public String getSubject_name() {
return mSubject_name;
}
public void setSubject_name(String subject_name) {
mSubject_name = subject_name;
}
public String getSubject_key() {
return mSubject_key;
}
public void setSubject_key(String subject_key) {
mSubject_key = subject_key;
}
public Long getTime_added() {
return mTime_added;
}
public void setTime_added(Long time_added) {
mTime_added = time_added;
}
public int getNum_papers() {
return mNum_papers;
}
public void setNum_papers(int num_papers) {
mNum_papers = num_papers;
}
public int getNum_questions() {
return mNum_questions;
}
public void setNum_questions(int num_questions) {
mNum_questions = num_questions;
}
}
Somehow QuestionsActivity is getting into the fragment save state, even if you don't intend for that to happen. While QuestionsActivity is being serialized, another object that is not serializable is being encountered. That's why you see TextViews and other things attempting to get serialized because all the instance variables of QuestionsActivity get serialized by default.
My best guess for why this is happening is due to this line:
args.putSerializable(Keys.FRAGMENT_ACTIVE_LISTENER, mOnFragmentActiveListener);
But it's difficult to know for sure without seeing where OnFragmentActiveListener is defined. I'm assuming either QuestionsActivity implements OnFragmentActiveListener, or QuestionsActivity defines OnFragmentActiveListener as an inner class. Either way, if you put an OnFragmentActiveListener into fragment arguments, you will encounter an exception because you indirectly are storing the entire QuestionsActivity as a fragment arg too. When a fragment stops, all fragment args become part of the fragment save state. And that's the cause of the error.
I would suggest not passing the OnFragmentActiveListener around as a fragment arg. If the OnFragmentActiveListener comes from the activity, just use getActivity() to get a reference to the activity and then get a reference to the listener.
I also noticed PaperListFragment implements Serializable and I'm assuming you did the same thing for QuestionsActivity. You probably did this to get around compile errors. But this has led to runtime errors because the instance variables on both of these classes are not all serializable. So to avoid more runtime issues, I would suggest never having activities or fragments implement serializable because these classes are inherently not serializable due to their members.
I want to pass ArrayList<Palatte_Model> from one Activity to another fragment. I am using ParcelableArraylist. Here I attached my code
public class Palette_Model implements Parcelable{
public String data_format_value;
public int data_format_id;
public Palette_Model(String data_format_value, int data_format_id) {
this.data_format_value = data_format_value;
this.data_format_id = data_format_id;
}
public String getData_format_value() {
return data_format_value;
}
public void setData_format_value(String data_format_value) {
this.data_format_value = data_format_value;
}
public int getData_format_id() {
return data_format_id;
}
public void setData_format_id(int data_format_id) {
this.data_format_id = data_format_id;
}
protected Palette_Model(Parcel in) {
data_format_value = in.readString();
data_format_id = in.readInt();
}
#Override
public int describeContents() {
return this.hashCode();
}
#Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(data_format_value);
dest.writeInt(data_format_id);
}
public void readfromParcel(Parcel source){
data_format_id = source.readInt();
data_format_value = source.readString();
}
public static final Creator<Palette_Model> CREATOR = new Creator<Palette_Model>() {
#Override
public Palette_Model createFromParcel(Parcel in) {
return new Palette_Model(in);
}
#Override
public Palette_Model[] newArray(int size) {
return new Palette_Model[size];
}
};
}
here i attached my activity class code. to send arraylist to fragment
Platte_fragment dFragment = new Platte_fragment();
Bundle bundle = new Bundle();
bundle.putParcelableArrayList("arraylist", strQuestion);
dFragment.setArguments(bundle);
// dFragment.show(fragmentManager, "array list");
FragmentTransaction fts = getSupportFragmentManager().beginTransaction();
fts.replace(R.id.questContFragId, dFragment);
fts.addToBackStack(dFragment.getClass().getSimpleName());
fts.commit();
here I mentioned my fragment class code:
I fetch the ArrayList from Activity. it shows a null value
ArrayList<Palette_Model> strQuestion ;
strQuestion = new ArrayList<>();
try {
Bundle bundle = this.getArguments();
strQuestion = bundle.getParcelableArrayList("arraylist");
}catch (NullPointerException e){
Log.e("er",e.getMessage());
}
The shown method may produce NullpointerException.
I had a similar problem. After some research, I found out somewhere in my code ArrayList<Type> list is pointing to nothing(NullpointerException).
What helped me was to check if Bundle extras is null:
ArrayList<Category> categories = new ArrayList<Category>(); // you initialize it here
Bundle extras = getIntent().getExtras();
if (extras != null) {
categories = extras.getParcelableArrayList("categories");
}
So if retrieved data is null it won't attach null pointer to ArrayList.
Check this link for more info about NullPointerException