Having troubles getting data from List Adapter for OnItemClick - java

Im having an issue with getting data that is obtained when my listadapter is set to my listview. Im trying to get this data in onItemClick so that i can put it into my intent extra's for my other activity to obtain.
The Problem
Currently i've created null string variables and then in my adapter assigning the strings with the desired text by methods within my model. However the problem im having is that the text that is being pulled is not the correct text for the position that onitemclick was called for.
Here some code...
XMLParseActivity
public class XMLParseActivity extends Activity implements AdapterView.OnItemClickListener {
private ListView mIssueListView;
private IssueParser mIssueParser;
private List<IssueFeed> mIssueList;
private IssueAdapter mIssueAdapter;
private String result_connectedtype = "";
private String result_symptom = "";
private String result_problem = "";
private String result_solution = "";
private String result_comments = "";
...
public class IssueAdapter extends ArrayAdapter<IssueFeed> {
public List<IssueFeed> issueFeedList;
public IssueAdapter(Context context, int textViewResourceId, List<IssueFeed> issueFeedList) {
super(context, textViewResourceId, issueFeedList);
this.issueFeedList = issueFeedList;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View view = convertView;
IssueHolder issueHolder = null;
if (convertView == null) {
view = View.inflate(XMLParseActivity.this, R.layout.issue_list_item, null);
issueHolder = new IssueHolder();
issueHolder.issueConnectedType = (TextView) view.findViewById(R.id.result_connected_type);
issueHolder.issueSymptomView = (TextView) view.findViewById(R.id.result_symptom);
view.setTag(issueHolder);
} else {
issueHolder = (IssueHolder) view.getTag();
}
IssueFeed issueFeed = issueFeedList.get(position);
issueHolder.issueConnectedType.setText(issueFeed.getConnected_type());
issueHolder.issueSymptomView.setText(issueFeed.getSymptom());
//THE DATA I WANT TO USE IN MY INTENT
result_solution = issueFeed.getSolution();
result_comments = issueFeed.getComments();
result_connectedtype = issueFeed.getConnected_type();
result_problem = issueFeed.getProblem();
result_symptom = issueFeed.getSymptom();
return view;
}
}
static class IssueHolder {
public TextView issueSymptomView;
public TextView issueConnectedType;
}
#Override
public void onItemClick(AdapterView<?> adapterView, View v, int position, long id) {
//Put the strings in intent extra
Intent intent = new Intent(this, SpecificIssueActivity.class);
intent.putExtra("symptom", result_symptom);
intent.putExtra("problem", result_problem);
intent.putExtra("solution", result_solution);
intent.putExtra("comments", result_comments);
intent.putExtra("connectedtype", result_connectedtype);
startActivity(intent);
}
The listAdapter is set in a asynctask in the below code
public class DoLocalParse extends AsyncTask<String, Void, List<IssueFeed>> {
ProgressDialog prog;
String jsonStr = null;
Handler innerHandler;
#Override
protected void onPreExecute() {
prog = new ProgressDialog(XMLParseActivity.this);
prog.setMessage("Loading....");
prog.show();
}
#Override
protected List<IssueFeed> doInBackground(String... params) {
mIssueParser = new IssueParser(null);
mIssueList = mIssueParser.parseLocally(params[0]);
return mIssueList;
}
#Override
protected void onPostExecute(List<IssueFeed> result) {
prog.dismiss();
runOnUiThread(new Runnable() {
#Override
public void run() {
mIssueAdapter = new IssueAdapter(XMLParseActivity.this, R.layout.issue_list_item,
mIssueList);
int count = mIssueAdapter.getCount();
if (count != 0 && mIssueAdapter != null) {
mIssueListView.setAdapter(mIssueAdapter);
}
}
});
}
}
And my model IssueFeed looks like this
public class IssueFeed implements Serializable {
private String connected_type;
private String symptom;
private String problem;
private String solution;
private String comments;
public IssueFeed() {
}
public IssueFeed(String connected_type, String symptom, String problem, String solution, String comments) {
this.connected_type = connected_type;
this.symptom = symptom;
this.problem = problem;
this.solution = solution;
this.comments = comments;
}
public String getConnected_type() {
return connected_type;
}
public String getSymptom() {
return symptom;
}
public String getProblem() {
return problem;
}
public String getSolution() {
return solution;
}
public String getComments() {
return comments;
}
public void setConnected_type(String connected_type) {
this.connected_type = connected_type;
}
public void setSymptom(String symptom) {
this.symptom = symptom;
}
public void setProblem(String problem) {
this.problem = problem;
}
public void setSolution(String solution) {
this.solution = solution;
}
public void setComments(String comments) {
this.comments = comments;
}
}

I have solve the issue by getting the data from some simple methods in my model to obtain the values.

Related

How to parse json data from json array to recyclerview java android?

I can parse json data to my recyclerview. but when i meet json that has array data in it, my app forceclose when i try to get that. How to solve this? or anyone has similar sample code with this case?
Api:
https://v1.nocodeapi.com/fariz/fit/FunuohzdbtxBkVtC/aggregatesDatasets?dataTypeName=steps_count,heart_minutes,weight,activity_summary
Activity_Stepcounter.java
Call<nodeApi> call = jsonPlaceHolderApi.getNode();
call.enqueue(new Callback<nodeApi>() {
#Override
public void onResponse(Call<nodeApi> call, Response<nodeApi> response) {
progressBar.setVisibility(View.GONE);
nodeApi resource = response.body();
List<nodeApi.steps_count> dataList = resource.steps_count;
Adapter_meeting rv_adapter = new Adapter_meeting(dataList, Activity_Stepcounter.this);
rv.setLayoutManager(new LinearLayoutManager(Activity_Stepcounter.this));
rv.setAdapter(rv_adapter);
rv.hasFixedSize();
rv_adapter.notifyDataSetChanged();
}
#Override
public void onFailure(Call<nodeApi> call, Throwable t) {
call.cancel();
}
});
Adapter_meeting.java
public class Adapter_meeting extends RecyclerView.Adapter<Adapter_meeting.viewHolder> {
private final List<nodeApi.steps_count> mitem_meeting;
private final Context mContext;
public Adapter_meeting(List<nodeApi.steps_count> Item_meeting, Context mContext) {
this.mitem_meeting = Item_meeting;
this.mContext = mContext;
}
#NonNull
#Override
public viewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
final View view;
view = LayoutInflater.from(parent.getContext()).inflate(R.layout.rv_step_counter, parent, false);
final viewHolder vHolder = new viewHolder(view);
return vHolder;
}
#Override
public void onBindViewHolder(#NonNull viewHolder holder, int position) {
holder.tv_namaEvent.setText(mitem_meeting.get(position).getValue());
holder.tv_lokasiEvent.setText(mitem_meeting.get(position).getStartTime());
holder.tv_waktuEvent.setText(mitem_meeting.get(position).getEndTime());
holder.tv_tanggalEvent.setText(mitem_meeting.get(position).getStartTimeMillis());
}
#Override
public int getItemCount() {
return mitem_meeting.size();
}
public class viewHolder extends RecyclerView.ViewHolder {
private final TextView tv_namaEvent;
private final TextView tv_lokasiEvent;
private final TextView tv_waktuEvent;
private final TextView tv_tanggalEvent;
public viewHolder(#NonNull View itemView) {
super(itemView);
tv_namaEvent = (TextView) itemView.findViewById(R.id.id_tv_namaEvent);
tv_lokasiEvent = (TextView) itemView.findViewById(R.id.id_tv_lokasiEvent);
tv_waktuEvent = (TextView) itemView.findViewById(R.id.id_tv_waktuEvent);
tv_tanggalEvent = (TextView) itemView.findViewById(R.id.id_tv_tanggalEvent);
}
}}
JsonPlaceHolderApi.java
public interface JsonPlaceHolderApi {
#GET("aggregatesDatasets?dataTypeName=steps_count,heart_minutes,weight,activity_summary")
Call<nodeApi> getNode();}
nodeApi.java
public class nodeApi {
#SerializedName("steps_count")
public List<steps_count> steps_count = null;
public class steps_count {
public Integer value;
public String startTimeMillis;
public String endTimeMillis;
public String startTime;
public String endTime;
public steps_count(Integer value, String startTimeMillis, String endTimeMillis, String startTime, String endTime) {
this.value = value;
this.startTimeMillis = startTimeMillis;
this.endTimeMillis = endTimeMillis;
this.startTime = startTime;
this.endTime = endTime;
}
public Integer getValue() {
return value;
}
public void setValue(Integer value) {
this.value = value;
}
public String getStartTimeMillis() {
return startTimeMillis;
}
public void setStartTimeMillis(String startTimeMillis) {
this.startTimeMillis = startTimeMillis;
}
public String getEndTimeMillis() {
return endTimeMillis;
}
public void setEndTimeMillis(String endTimeMillis) {
this.endTimeMillis = endTimeMillis;
}
public String getStartTime() {
return startTime;
}
public void setStartTime(String startTime) {
this.startTime = startTime;
}
public String getEndTime() {
return endTime;
}
public void setEndTime(String endTime) {
this.endTime = endTime;
}
}
}
error
E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.iot.testapp, PID: 12849
android.content.res.Resources$NotFoundException: String resource ID #0x19
at android.content.res.Resources.getText(Resources.java:335)
at android.widget.TextView.setText(TextView.java:4555)
at com.iot.testapp.adapter.Adapter_meeting.onBindViewHolder(Adapter_meeting.java:47)
at com.iot.testapp.adapter.Adapter_meeting.onBindViewHolder(Adapter_meeting.java:26)
On these lines:
holder.tv_tanggalEvent.setText(mitem_meeting.get(position).getStartTimeMillis());
holder.tv_lokasiEvent.setText(mitem_meeting.get(position).getStartTime());
holder.tv_waktuEvent.setText(mitem_meeting.get(position).getEndTime());
Compilator thinks, that you are passing String resource, but you are actually passing simple String. Just add +"" and it should start working.
holder.tv_tanggalEvent.setText(mitem_meeting.get(position).getStartTimeMillis()+"");
holder.tv_namaEvent.setText(mitem_meeting.get(position).getStartTime()+"");
holder.tv_waktuEvent.setText(mitem_meeting.get(position).getEndTime()+"");
You should pass text to textviews in form of String resource with placeholders, but it doesn't really make sense, when you don't pass there anything except the changing value.
holder.tv_namaEvent.setText(mitem_meeting.get(position).getValue());
You are trying to set Int.
Try:
String value = String.valueOf(mitem_meeting.get(position).getValue());
holder.tv_namaEvent.setText(value);
Please check all fields for null and read about name convention in Android :)
Also time in milis should be stored in Long type.
You can also read about Kotlin language, mvvn pattern etc.
Thanks, i got help from discord
I have to make jsonresponse first and then convert it to arraylist using nodeApi.java.
public class JsonResponse {
private nodeApi[] steps_count;
public nodeApi[] getStep_count() {
return steps_count;
}
public void setnodeApi(nodeApi[] step_count) {
this.steps_count = step_count;
}
}
Activity_Stepcounter.java
Call<JsonResponse> call = jsonPlaceHolderApi.getStep();
call.enqueue(new Callback<JsonResponse>() {
#Override
public void onResponse(Call<JsonResponse> call, Response<JsonResponse> response) {
progressBar.setVisibility(View.GONE);
JsonResponse jsonResponse = response.body();
listStep = new ArrayList<>(Arrays.asList(jsonResponse.getStep_count()));
Adapter_meeting rv_adapter = new Adapter_meeting(listStep, Activity_Stepcounter.this);
rv.setLayoutManager(new LinearLayoutManager(Activity_Stepcounter.this));
rv.setAdapter(rv_adapter);
rv.hasFixedSize();
rv_adapter.notifyDataSetChanged();
}
#Override
public void onFailure(Call<JsonResponse> call, Throwable t) {
call.cancel();
}
});
**there are some refactor/rename.

Passing data in recycler view from API

I tried to make a covid-19 tracking app by watching Youtube tutorials.
My app shows the country list with flags and when you click on any country it opens an activity and shows the details of that country i.e total cases, deaths, recovered, etc. The video on Youtube uses ListView and I am using recyclerView
I fetched the country list successfully and set onClickListener on the view and it opens second activity which shows the case in detail. But I don't know how to show the data.
my adapter class:
class Countries_adapter extends RecyclerView.Adapter<Countries_adapter.MyViewHolder> {
Context ct;
List<Countries_data> list;
public Countries_adapter(Context context,List<Countries_data> country)
{
ct=context;
list=country;
}
#Override
public MyViewHolder onCreateViewHolder( ViewGroup parent, int viewType) {
View v = LayoutInflater.from(ct).inflate(R.layout.countries_row,parent,false);
return new MyViewHolder(v);
}
#Override
public void onBindViewHolder(MyViewHolder holder, final int position) {
holder.tvCountryName.setText(list.get(position).getCountry());
holder.tvtotal.setText(list.get(position).getActive());
Glide.with(ct).load(list.get(position).getFlag()).into(holder.imageView);
holder.linearLayout.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Intent i = new Intent(ct,CountriesDetails.class);
i.putExtra("Country",list.get(position).getCountry());
ct.startActivity(i);
}
});
}
#Override
public int getItemCount() {
return list.size();
}
public class MyViewHolder extends RecyclerView.ViewHolder {
TextView tvCountryName,tvtotal;
ImageView imageView;
LinearLayout linearLayout;
public MyViewHolder( View itemView) {
super(itemView);
tvCountryName = itemView.findViewById(R.id.tvCountryName);
tvtotal=itemView.findViewById(R.id.tvCountrytotalcaese);
imageView = itemView.findViewById(R.id.imageFlag);
linearLayout=itemView.findViewById(R.id.linear_layout);
}
}
my AffectedCoutries class activity is as follows:
public class AffectedCountries extends AppCompatActivity {
EditText edtSearch;
RecyclerView recyclerView;
SimpleArcLoader simpleArcLoader;
public static ArrayList countryList = new ArrayList<>();
Countries_data countryData;
Countries_adapter CountriesAdapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_affected_countries);
edtSearch = findViewById(R.id.edtSearch);
recyclerView=findViewById(R.id.recyclerAffectedCountries);
simpleArcLoader = findViewById(R.id.loader);
fetchData();
}
private void fetchData() {
String url = "https://corona.lmao.ninja/v2/countries/";
simpleArcLoader.start();
StringRequest request = new StringRequest(Request.Method.GET, url,
new Response.Listener<String>() {
#Override
public void onResponse(String response) {
try {
JSONArray jsonArray = new JSONArray(response);
for(int i=0;i<jsonArray.length();i++){
JSONObject jsonObject = jsonArray.getJSONObject(i);
String countryName = jsonObject.getString("country");
String cases = jsonObject.getString("cases");
String todayCases = jsonObject.getString("todayCases");
String deaths = jsonObject.getString("deaths");
String todayDeaths = jsonObject.getString("todayDeaths");
String recovered = jsonObject.getString("recovered");
String active = jsonObject.getString("active");
String critical = jsonObject.getString("critical");
JSONObject object = jsonObject.getJSONObject("countryInfo");
String flagUrl = object.getString("flag");
countryData = new Countries_data(flagUrl,countryName,cases,todayCases,deaths,todayDeaths,recovered,active,critical);
countryList.add(countryData);
}
CountriesAdapter = new Countries_adapter(AffectedCountries.this,countryList);
recyclerView.setLayoutManager(new LinearLayoutManager(AffectedCountries.this));
recyclerView.setAdapter(CountriesAdapter);
simpleArcLoader.stop();
simpleArcLoader.setVisibility(View.GONE);
} catch (JSONException e) {
e.printStackTrace();
simpleArcLoader.start();
simpleArcLoader.setVisibility(View.GONE);
Toast.makeText(AffectedCountries.this,"catch response", Toast.LENGTH_SHORT).show();
}
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
simpleArcLoader.stop();
simpleArcLoader.setVisibility(View.GONE);
Toast.makeText(AffectedCountries.this,"error response", Toast.LENGTH_SHORT).show();
}
});
RequestQueue requestQueue = Volley.newRequestQueue(this);
requestQueue.add(request);
}
}
my Countries_data class(model class)
public class Countries_data {
public String country;
public String cases;
public String todayCases;
public String deaths;
public String todayDeaths;
public String recovered;
public String active;
public String critical;
public String flag;
public Countries_data(String flag, String country, String cases, String
todayCases, String deaths, String todayDeaths, String recovered,
String active, String critical) {
this.country = country;
this.cases = cases;
this.todayCases = todayCases;
this.deaths = deaths;
this.todayDeaths = todayDeaths;
this.recovered = recovered;
this.active = active;
this.critical = critical;
this.flag = flag;
}
public String getCountry() {
return country;
}
public void setCountry(String country) {
this.country = country;
}
public String getCases() {
return cases;
}
public void setCases(String cases) {
this.cases = cases;
}
public String getTodayCases() {
return todayCases;
}
public void setTodayCases(String todayCases) {
this.todayCases = todayCases;
}
public String getDeaths() {
return deaths;
}
public void setDeaths(String deaths) {
this.deaths = deaths;
}
public String getTodayDeaths() {
return todayDeaths;
}
public void setTodayDeaths(String todayDeaths) {
this.todayDeaths = todayDeaths;
}
public String getRecovered() {
return recovered;
}
public void setRecovered(String recovered) {
this.recovered = recovered;
}
public String getActive() {
return active;
}
public void setActive(String active) {
this.active = active;
}
public String getCritical() {
return critical;
}
public void setCritical(String critical) {
this.critical = critical;
}
public String getFlag() {
return flag;
}
public void setFlag(String flag) {
this.flag = flag;
}
}
my Country_details class
public class CountriesDetails extends AppCompatActivity {
TextView tvCountry, tvCases, tvRecovered,tvdeaths;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_countries_details2);
tvCountry = findViewById(R.id.tvCountry);
tvCases = findViewById(R.id.tvCases);
tvRecovered = findViewById(R.id.tvRecovered);
tvdeaths=findViewById(R.id.tvTotalDeaths);
String positionCountry = getIntent().getStringExtra("Country");
Log.i("country name", positionCountry);
}
}
How to set the data in tvcases?
How can I show the data? Do I have to create a separate recycler view and then fetch the data from the API or can I use my main activity to show the data?
I have some sad information for you: Google Play policy restricts such apps from being published in store... especially when you are showing deaths count. Been there, done that, my app was blocked...
besides above:
you are passing country name in intent:
i.putExtra("Country",list.get(position).getCountry());
but trying to read "position" in details Activity - it will be always 0 (default)
edit due to comments:
pass position of clicked View
holder.linearLayout.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Intent i = new Intent(ct,CountriesDetails.class);
i.putExtra("position", position);
ct.startActivity(i);
}
});
in CountriesDetailss onCreate method receive this position and restore proper Countries_data object from your static countryList array in AffectedCountries
int position = getIntent().getIntExtra("position", 0);
Countries_data country = AffectedCountries.countryList.get(position);
tvCountry.setText(country.getCountry());
that should work, but this isn't best way to store data, in fact its very weak... after downloading data (list of countries) you should store it somehow, e.g. SQLite/Room lib or at least SharedPreferences... then in details activity you should restore int position and using it take proper object from database or preferences, instead of stright from static array
it may be also useful to implement Parcelable inteface to your Countries_data - this will allow to put whole Countries_data object into Intents extras, not only primitive int with position in array. in this case details activity won't even need access to whole array or sql database/preferences, it will get whole object straight from Intents extras

my project has problem saving ArrayList<T> with SharedPreferences

i have a problem which is making me crazy.
i know how to use "SharedPreferences" in android but i dont know where to put it in my project,like onCreate(),onDestroy() or somewhere else.
*i want to save NoteLab.mNotes in NoteListFragment
*Note.java
package notes.com.example.alireza;
public class Note {
public UUID nId;
public Date nDate;
public String nTitle;
public String nDetails;
public Note(){
nId = UUID.randomUUID();
nDate = new Date();
}
public Date getnDate(){
return nDate;
}
public UUID getnUUID(){
return nId;
}
public String getnTitle() {
return nTitle;
}
public void setnTitle(String nTitle) {
this.nTitle = nTitle;
}
public String getnDetails() {
return nDetails;
}
public void setnDetails(String nDetails) {
this.nDetails = nDetails;
}
}
*NoteLab.java
package notes.com.example.alireza;
import android.content.Context;
import java.util.ArrayList;
import java.util.UUID;
class NoteLab {
public static ArrayList<Note> mNotes;
public static NoteLab noteLab;
public Context mAppContext;
private NoteLab(Context AppContext){
mAppContext = AppContext;
mNotes = new ArrayList<Note>();
}
public static NoteLab get(Context context){
if (noteLab == null){
noteLab = new NoteLab(context.getApplicationContext());
}
return noteLab;
}
public static ArrayList<Note> getNotes(){
return mNotes;
}
public static Note getNote(UUID mId){
for (Note n: mNotes){
if (mId == n.getnUUID()){
return n;
}
}
return null;
}
}
*NoteListFragment.java
package notes.com.example.alireza;
public class NoteListFragment extends ListFragment {
Note note;
ArrayList<Note> notes;
public static Date date;
#Override
public void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
notes = NoteLab.get(getActivity()).getNotes();
myArrayAdapter arrayAdapter = new myArrayAdapter(notes);
setListAdapter(arrayAdapter);
}
#Override
public void onStart() {
super.onStart();
View emptyView = getActivity().getLayoutInflater().inflate(R.layout.emptymainlist,null);
((ViewGroup)getListView().getParent()).addView(emptyView);
getListView().setEmptyView(emptyView);
}
#Override
public void onListItemClick(ListView l, View v, int position, long id) {
int checked = 1;
Note c = ((myArrayAdapter)getListAdapter()).getItem(position);
Intent i = new Intent(getActivity(),NoteActivity.class);
i.putExtra("id",c.getnUUID());
i.putExtra(NoteListActivity.EXTRA_DATE,checked);
startActivity(i);
}
//custom arrayList
public class myArrayAdapter extends ArrayAdapter<Note> {
public myArrayAdapter(ArrayList<Note> notes) {
super(getActivity(), 0, notes);
}
#SuppressLint("SetTextI18n")
#Override
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null) {
convertView = getActivity().getLayoutInflater().inflate(R.layout.notelistfragment_item, null);
}
Note n = getItem(position);
date = n.getnDate();
PersianCalendar persianCalendar = new PersianCalendar();
persianCalendar.setTime(date);
TextView titleTextView = convertView.findViewById(R.id.titleTextView);
titleTextView.setText(n.getnTitle());
TextView detailTextView = convertView.findViewById(R.id.detailsTextView);
detailTextView.setText(n.getnDetails());
TextView dateTextView = convertView.findViewById(R.id.dateTextView);
dateTextView.setText(DateFormat.getDateInstance(DateFormat.FULL).format(date) + " : تاریخ ذخیره ");
return convertView;
}
}
#Override
public void onResume() {
super.onResume();
((myArrayAdapter)getListAdapter()).notifyDataSetChanged();
}
as you understand from the codes, i want to save my mNotes arrayList which is placed in NoteLab.java.there is NoteListActivtiy.java too which is supporting NoteListFragment but i think this can be done in NoteListFragment.
thanks to stackoverflow and everyone who tryes to help me.
You can use Gson library to convert what you want to String then you can get it back again.
Where should you put your code ?? it depends on your business (or requirements).
If you want to pass your array of items to fragment or another activity you can use Gson lib to convert it to string then put it into bundle and pass this bundle to whatever you want. Then in the fragment or the activity you can get this array by Gson also.
Here is an example:
Gson gson = new Gson();
gson.toSring(yourData);
// then you can get the data by
Gson gson = new Gson();
String data = yourBundle.getString("your_key");
yourDataModel = gson.fromJson(data, YourDataModel.class);
// it will work even with ArrayList

AsyncTask - missing something [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 4 years ago.
Improve this question
I'm doing some project and I'm stuck ... I'm doing something wrong, probably with AsyncTask and I have no idea what to fix and how .... there is code I have right now.
ReviewData.class
public class ReviewData implements Parcelable {
private String mAuthor, mContent;
public ReviewData(String author, String content) {
this.mAuthor = author;
this.mContent = content;
}
private ReviewData(Parcel in) {
mAuthor = in.readString();
mContent = in.readString();
}
public static final Creator<ReviewData> CREATOR = new Creator<ReviewData>() {
#Override
public ReviewData createFromParcel(Parcel in) {
return new ReviewData(in);
}
#Override
public ReviewData[] newArray(int size) {
return new ReviewData[size];
}
};
//Getter method for review author
public String getAuthor() {
return mAuthor;
}
//Setter method for review author
public void setAuthor(String author) {
this.mAuthor = author;
}
//Getter method for review content
public String getContent() {
return mContent;
}
//Setter method for review content
public void setContent(String content) {
this.mContent = content;
}
#Override
public int describeContents() {
return 0;
}
#Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(mAuthor);
dest.writeString(mContent);
}
}
ReviewAdapter.class
public class ReviewAdapter extends RecyclerView.Adapter<ReviewAdapter.ReviewViewHolder> {
private ArrayList<ReviewData> mReviewList;
private Context mContext;
public ReviewAdapter(Context context, ArrayList<ReviewData> reviewList) {
this.mContext = context;
this.mReviewList = reviewList;
}
#Override
public ReviewViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
mContext = parent.getContext();
View view = LayoutInflater.from(mContext).inflate(R.layout.review_item_list,
parent, false);
view.setFocusable(true);
return new ReviewViewHolder(view);
}
#Override
public void onBindViewHolder(final ReviewViewHolder holder, int position) {
if(mReviewList != null) {
ReviewData reviewData = mReviewList.get(position);
holder.reviewAuthor.setText(reviewData.getAuthor());
holder.reviewContent.setText(reviewData.getContent());
}
}
#Override
public long getItemId(int position) {
return position;
}
#Override
public int getItemCount() {
if(mReviewList == null) {
return 0;
} else {
return mReviewList.size();
}
}
public void setReviewList(ArrayList<ReviewData> reviewList) {
if(reviewList != null) {
mReviewList = new ArrayList<>(reviewList);
}
notifyDataSetChanged();
}
public class ReviewViewHolder extends RecyclerView.ViewHolder {
TextView reviewAuthor;
TextView reviewContent;
public ReviewViewHolder(View itemView) {
super(itemView);
reviewAuthor = itemView.findViewById(R.id.review_author);
reviewContent = itemView.findViewById(R.id.review_content);
}
}
}
NetworkUtils.class (but only code for Review url builder, for other thing works perfectly). PS. this parse is written as API documentation said ... it should be someurl/movie/{id}/reviews
//URL builder for reviews
public static URL buildReviewUrl(String id) {
Uri builtUri = Uri.parse(BASE_MOVIE_URL + id + REVIEW).buildUpon()
.appendQueryParameter(QUERY_API_KEY, API_KEY)
.build();
URL url = null;
try {
url = new URL(builtUri.toString());
} catch (MalformedURLException e) {
e.printStackTrace();
}
return url;
}
JsonData. class (also, only for Reviews, for other works perfectly...)
//JSON for Review
public static ArrayList<ReviewData> getReviewFromJson(String json) throws JSONException {
ArrayList<ReviewData> listOfReviews = new ArrayList<>();
try {
JSONObject reviews = new JSONObject(json);
JSONArray reviewsArray = reviews.getJSONArray(QUERY_RESULTS);
for(int i = 0; i < reviewsArray.length(); i++) {
JSONObject jsonReview = reviewsArray.getJSONObject(i);
String author = jsonReview.optString(REVIEW_AUTHOR);
String content = jsonReview.optString(REVIEW_CONTENT);
ReviewData reviewData = new ReviewData(author, content);
listOfReviews.add(reviewData);
}
} catch(JSONException e) {
e.printStackTrace();
Log.e("ReviewJson", "JSON Review Error");
}
return listOfReviews;
}
ReviewAsyncTask.class
public class ReviewAsyncTask extends AsyncTask<String, Void, ArrayList<ReviewData>> {
private ReviewData mReviewData;
public interface ReviewResponse {
void finished(ArrayList<ReviewData> output);
}
private ReviewResponse reviewResponse = null;
public ReviewAsyncTask(ReviewResponse reviewResponse) {
this.reviewResponse = reviewResponse;
}
#Override
protected ArrayList<ReviewData> doInBackground(String... strings) {
String rawData = "";
ArrayList<ReviewData> reviewList = new ArrayList<>();
try {
rawData = NetworkUtils.getResponseFromHttpRequest(NetworkUtils
.buildReviewUrl(String.valueOf(mReviewData)));
reviewList = JsonData.getReviewFromJson(rawData);
} catch (IOException e) {
e.printStackTrace();
Log.e("ReviewAsyncTask", "Error in ReviewAsyncTask");
} catch (JSONException e) {
e.printStackTrace();
Log.e("JSONAsync", "JSON problem");
}
return reviewList;
}
#Override
protected void onPostExecute(ArrayList<ReviewData> reviewData) {
reviewResponse.finished(reviewData);
}
}
and MovieDetails activity (everything works fine except from the comment recycle review to next comment.
public class MovieDetails extends AppCompatActivity implements ReviewAsyncTask.ReviewResponse {
private final static String BASE_URL = "http://image.tmdb.org/t/p/";
private final static String SIZE = "w185/";
private ArrayList<ReviewData> mReviewList;
private ReviewAdapter mReviewAdapter;
#BindView(R.id.poster_detail)
ImageView mMoviePoster;
#BindView(R.id.title_detail)
TextView mMovieTitle;
#BindView(R.id.release_date)
TextView mReleaseDate;
#BindView(R.id.average_vote)
TextView mAverageVote;
#BindView(R.id.synopsis)
TextView mSynopsis;
#BindView(R.id.review_recycler)
RecyclerView mReviewRecycle;
Context mContext;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_movie_details);
ButterKnife.bind(this);
displayMovieDetail();
//Review RecycleView
mReviewList = new ArrayList<>();
mReviewAdapter = new ReviewAdapter(this, mReviewList);
RecyclerView.LayoutManager layoutManager = new LinearLayoutManager(this);
mReviewRecycle.setLayoutManager(layoutManager);
mReviewRecycle.setHasFixedSize(true);
mReviewRecycle.setAdapter(mReviewAdapter);
}
#Override
public void finished(ArrayList<ReviewData> output) {
ReviewAsyncTask reviewAsyncTask = new ReviewAsyncTask(this);
reviewAsyncTask.execute();
}
/* Method for displaying the info about movies in activity details
* #param mMoviePoster sets the movie poster
* #param mMovieTitle sets original title of the movie
* #param mReleaseDate sets release date of the movie
* #param mAverageVote sets average rating grade of the movie
* #param mSynopsis sets plot of the movie */
private void displayMovieDetail() {
int idMovie = (Integer) getIntent().getExtras().get(getString(R.string.movie_id));
List<MovieData> movieList;
movieList = getIntent().getParcelableArrayListExtra(getString(R.string.movie_lsit));
MovieData movieData = movieList.get(idMovie);
Picasso.with(mContext).load(BASE_URL + SIZE +
movieData.getPoster()).into(mMoviePoster);
mMovieTitle.setText(movieData.getTitle());
mReleaseDate.setText(movieData.getReleaseDate());
mAverageVote.setText(Double.toString(movieData.getRating()));
mSynopsis.setText(movieData.getSynopsis());
}
}
P.S. I would share github link but I should give you my personal API key. :(
You need to start the AsyncTask in onCreate() (like you did before) and in finished() you take the results and add them to the Adapter's data list.
Finally, don't forget to call notifyDatasetChanged().
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_movie_details);
// skipping some lines of code here...
mReviewRecycle.setAdapter(mReviewAdapter);
ReviewAsyncTask reviewAsyncTask = new ReviewAsyncTask(this);
reviewAsyncTask.execute();
}
#Override
public void finished(ArrayList<ReviewData> output) {
mReviewList.addAll(output);
mReviewAdapter.notifyDatasetChanged();
}
(Please note that I skipped null checks and error handling for brevity's sake)
In MovieDetails onCreate retrieve current movie ID like you do in displayMovieDetail.
Send that ID to ReviewAsyncTask (you'll need to modify constructor of ReviewAsyncTask)
Retrieve id in ReviewAsyncTask, save it as member variable, and then in doInBackground method send that id to buildReviewUrl as an argument.

Issue with ArrayList from JSON using Retrofit and populating RecyclerView

I’ve been trying to get recycler view working with retrofit. I seem to be pulling in the JSON fine from within getRecipes() method, and my logs are showing me that the some data is there.
However, when I call my getRecipes() method from onCreate(), something seems to be going wrong. When I check to see if my recipeList array contains my JSON results within onCreate, it is telling me it is empty. Why is it doing this if my logs within my getRecipes() method are showing me that data is there...?
Not sure if it is an issue with my recycler view or what I am doing with retrofit, or something else. Been trying for days to figure out, so any advice would be greatly appreciated.
JSON
https://d17h27t6h515a5.cloudfront.net/topher/2017/May/59121517_baking/baking.json
public class ItemListActivity extends AppCompatActivity {
private boolean mTwoPane;
public static final String LOG_TAG = "myLogs";
public static List<Recipe> recipeList = new ArrayList<>();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getRecipes();
setContentView(R.layout.activity_item_list);
getRecipes();
//Logging to check that recipeList contains data
if(recipeList.isEmpty()){
Log.d(LOG_TAG, "Is empty");
}else {
Log.d(LOG_TAG, "Is not empty");
}
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
toolbar.setTitle(getTitle());
RecyclerView recyclerView = (RecyclerView) findViewById(R.id.item_list);
RecyclerView.LayoutManager layoutManager = new LinearLayoutManager(this);
recyclerView.setLayoutManager(layoutManager);
SimpleItemRecyclerViewAdapter simpleItemRecyclerViewAdapter = new SimpleItemRecyclerViewAdapter(recipeList);
recyclerView.setAdapter(simpleItemRecyclerViewAdapter);
if (findViewById(R.id.item_detail_container) != null) {
mTwoPane = true;
}
}
public void getRecipes(){
String ROOT_URL = "https://d17h27t6h515a5.cloudfront.net/topher/2017/May/59121517_baking/";
Retrofit RETROFIT = new Retrofit.Builder()
.baseUrl(ROOT_URL)
.addConverterFactory(GsonConverterFactory.create())
.build();
RecipeService service = RETROFIT.create(RecipeService.class);
Call<List<Recipe>> call = service.getMyJson();
call.enqueue(new Callback<List<Recipe>>() {
#Override
public void onResponse(Call<List<Recipe>> call, Response<List<Recipe>> response) {
Log.d(LOG_TAG, "Got here");
if (!response.isSuccessful()) {
Log.d(LOG_TAG, "No Success");
}
Log.d(LOG_TAG, "Got here");
recipeList = response.body();
//Logging to check data is there
Log.v(LOG_TAG, "LOGS" + recipeList.size());
for (int i = 0; i < recipeList.size(); i++) {
String newString = recipeList.get(i).getName();
Ingredients[] ingredients = recipeList.get(i).getIngredients();
for(int j = 0; j < ingredients.length; j++){
Log.d(LOG_TAG, ingredients[j].getIngredient());
}
Steps[] steps = recipeList.get(i).getSteps();
for(int k = 0; k < steps.length; k++){
Log.d(LOG_TAG, steps[k].getDescription());
}
Log.d(LOG_TAG, newString);
}
}
#Override
public void onFailure(Call<List<Recipe>> call, Throwable t) {
Log.e("getRecipes throwable: ", t.getMessage());
t.printStackTrace();
}
});
}
public class SimpleItemRecyclerViewAdapter
extends RecyclerView.Adapter<SimpleItemRecyclerViewAdapter.ViewHolder> {
private final List<Recipe> mValues;
public SimpleItemRecyclerViewAdapter(List<Recipe> items) {
mValues = items;
}
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.item_list_content, parent, false);
return new ViewHolder(view);
}
#Override
public void onBindViewHolder(final ViewHolder holder, int position) {
holder.mItem = mValues.get(position);
holder.mContentView.setText(mValues.get(position).getName());
holder.mView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (mTwoPane) {
Bundle arguments = new Bundle();
arguments.putString(ItemDetailFragment.ARG_ITEM_ID, holder.mItem.getId());
ItemDetailFragment fragment = new ItemDetailFragment();
fragment.setArguments(arguments);
getSupportFragmentManager().beginTransaction()
.replace(R.id.item_detail_container, fragment)
.commit();
} else {
Context context = v.getContext();
Intent intent = new Intent(context, ItemDetailActivity.class);
intent.putExtra(ItemDetailFragment.ARG_ITEM_ID, holder.mItem.getId());
context.startActivity(intent);
}
}
});
}
#Override
public int getItemCount() {
return mValues.size();
}
public class ViewHolder extends RecyclerView.ViewHolder {
public View mView;
public TextView mContentView;
public Recipe mItem;
public ViewHolder(View view) {
super(view);
mView = view;
mContentView = (TextView) view.findViewById(R.id.content);
}
#Override
public String toString() {
return super.toString() + " '" + mContentView.getText() + "'";
}
}
}
RecipeService
public interface RecipeService {
#GET("baking.json")
Call<List<Recipe>> getMyJson();}
Models
Recipe
public class Recipe{
private Ingredients[] ingredients;
private String id;
private String servings;
private String name;
private String image;
private Steps[] steps;
public Ingredients[] getIngredients ()
{
return ingredients;
}
public void setIngredients (Ingredients[] ingredients)
{
this.ingredients = ingredients;
}
public String getId ()
{
return id;
}
public void setId (String id)
{
this.id = id;
}
public String getServings ()
{
return servings;
}
public void setServings (String servings)
{
this.servings = servings;
}
public String getName ()
{
return name;
}
public void setName (String name)
{
this.name = name;
}
public String getImage ()
{
return image;
}
public void setImage (String image)
{
this.image = image;
}
public Steps[] getSteps ()
{
return steps;
}
public void setSteps (Steps[] steps)
{
this.steps = steps;
}
#Override
public String toString()
{
return "[ingredients = "+ingredients+", id = "+id+", servings = "+servings+", name = "+name+", image = "+image+", steps = "+steps+"]";
}}
Ingredients
public class Ingredients{
private String measure;
private String ingredient;
private String quantity;
public String getMeasure ()
{
return measure;
}
public void setMeasure (String measure)
{
this.measure = measure;
}
public String getIngredient ()
{
return ingredient;
}
public void setIngredient (String ingredient)
{
this.ingredient = ingredient;
}
public String getQuantity ()
{
return quantity;
}
public void setQuantity (String quantity)
{
this.quantity = quantity;
}
#Override
public String toString()
{
return "[measure = "+measure+", ingredient = "+ingredient+", quantity = "+quantity+"]";
}}
Steps
public class Steps{
private String id;
private String shortDescription;
private String description;
private String videoURL;
private String thumbnailURL;
public String getId ()
{
return id;
}
public void setId (String id)
{
this.id = id;
}
public String getShortDescription ()
{
return shortDescription;
}
public void setShortDescription (String shortDescription)
{
this.shortDescription = shortDescription;
}
public String getDescription ()
{
return description;
}
public void setDescription (String description)
{
this.description = description;
}
public String getVideoURL ()
{
return videoURL;
}
public void setVideoURL (String videoURL)
{
this.videoURL = videoURL;
}
public String getThumbnailURL ()
{
return thumbnailURL;
}
public void setThumbnailURL (String thumbnailURL)
{
this.thumbnailURL = thumbnailURL;
}
#Override
public String toString()
{
return "[id = "+id+", shortDescription = "+shortDescription+", description = "+description+", videoURL = "+videoURL+", thumbnailURL = "+thumbnailURL+"]";
}}
Logs
https://gist.github.com/2triggers/12b6eeb32ed8909ab50bbadd4742d7f7
this will be empty always because this line will execute before getting the response from a server.
if(recipeList.isEmpty()){
Log.d(LOG_TAG, "Is empty");
}else {
Log.d(LOG_TAG, "Is not empty");
}
Better call this after this line recipeList = response.body();
SimpleItemRecyclerViewAdapter simpleItemRecyclerViewAdapter = new SimpleItemRecyclerViewAdapter(recipeList);
recyclerView.setAdapter(simpleItemRecyclerViewAdapter);
if (findViewById(R.id.item_detail_container) != null) {
mTwoPane = true;
}
it is because you are sending the recipelist into the adapter before even it is populated , after you are sending the recipelist into the adapter which is empty you are populating your recipelist from getRecipes method, you might be wondering you have declared the getRecipes method before even you are assigning the recipelist to adapter so how come it is empty, yea but the fact is your getRecipes work on background thread so even before your recipelist gets populated your adapter assignment takes place on the main thread so you are basically assigning the empty list, one thing you can do is notify when the adapter when the data changes or when the the recipelist is filled with data that is from within the getRecipe method.
when you assign the recipelist = response.body right after this you can notify the adapter
or move this two lines
SimpleItemRecyclerViewAdapter simpleItemRecyclerViewAdapter = new SimpleItemRecyclerViewAdapter(recipeList);
recyclerView.setAdapter(simpleItemRecyclerViewAdapter);
right after the
recipelist = response.body;
in getRecipes method
Try create the Constructor with all atributes from your Recipe.class
Like:
public Ingredients(String measure, String ingredients, String quantity ){
this.measure = measure;
this.ingredients = ingredients;
this.quantity = quantity
}
Do same in all class where make up your object of list.

Categories

Resources