In my android app, on homepage there is a recyclerview consisting cardviews as each item. First,I call ParseServer to get data on server and pass it to the recyclerview adapter. I pass image url along with other details to adapter class.
Inside my MainActivity.java
Parse.initialize(this, "key1", "key2");
ParsePush.subscribeInBackground("", new SaveCallback() {
#Override
public void done(ParseException e) {
if (e == null) {
Log.d("com.parse.push", "successfully subscribed to the broadcast channel.");
} else {
Log.e("com.parse.push", "failed to subscribe for push", e);
}
}
});
if(haveNetworkConnection()){
new task().execute();
mRecyclerView = (RecyclerView)findViewById(R.id.my_recycler_view);
mRecyclerView.setHasFixedSize(true);
mLayoutManager = new LinearLayoutManager(this);
mRecyclerView.setLayoutManager(mLayoutManager);
Class task which fetches data from server:
public class task extends AsyncTask<Void, Void, Void>{
ProgressDialog mProgressDialog;
#Override
protected void onPreExecute() {
super.onPreExecute();
rel.setVisibility(View.VISIBLE);
pro.setVisibility(View.VISIBLE);
titles.clear();
images.clear();
venues.clear();
timings.clear();
urgent.clear();
}
#Override
protected Void doInBackground(Void... params) {
ParseQuery<ParseObject> query = ParseQuery.getQuery("notices");
try {
List<ParseObject> ob = query.find();
for(ParseObject obj:ob){
String str = obj.getString("title");
String str1 = obj.getString("venue");
String str2 = obj.getString("timing");
ParseFile file = obj.getParseFile("images");
String str3 = obj.getString("urgent");
String url;
if(file!=null)
url = file.getUrl();
else{
url = "https://www.medidirect.com.au/MEDIstores/_images/no-thumb.png";
}
titles.add(str);
images.add(url);
venues.add(str1);
timings.add(str2);
urgent.add(str3);
}
} catch (ParseException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
#Override
protected void onPostExecute(Void result) {
AdapNotice mAdapter = new AdapNotice(MainActivity.this,titles,images,venues,timings,urgent);
if(titles.size()<1)
Toast.makeText(MainActivity.this, "Oops, Something went wrong. Please try again", 300).show();
mRecyclerView.setAdapter(mAdapter);
pro.setVisibility(View.GONE);
rel.setVisibility(View.GONE);
}
}
Inside AdapNotice class which is recyclerview adapter:
public class AdapNotice extends RecyclerView.Adapter<AdapNotice.ViewHolder>{
Activity activity;
ArrayList<String> _titles = new ArrayList<String>();
ArrayList<String> _images = new ArrayList<String>();
ArrayList<String> _venues = new ArrayList<String>();
ArrayList<String> _timings = new ArrayList<String>();
ArrayList<String> _urgents = new ArrayList<String>();
private int lastPosition = -1;
int pos;
public AdapNotice(Activity a, ArrayList<String> titles, ArrayList<String> images, ArrayList<String> venues, ArrayList<String> timings, ArrayList<String> urgent) {
activity = a;
_titles = titles;
_images = images;
_venues = venues;
_timings = timings;
_urgents = urgent;
}
public static class ViewHolder extends RecyclerView.ViewHolder{
// each data item is just a string in this case
public TextView title;
public ImageView imgview,urgent;
public TextView venue,venuetext,abctext;
public TextView timing,timingtext,abc1text;
public ViewHolder(View v) {
super(v);
title = (TextView) v.findViewById(R.id.title);
imgview = (ImageView) v.findViewById(R.id.img_notice);
venue = (TextView) v.findViewById(R.id.venue);
timing = (TextView) v.findViewById(R.id.timing);
venuetext = (TextView)v.findViewById(R.id.venuetext);
abctext = (TextView)v.findViewById(R.id.abctext);
timingtext = (TextView)v.findViewById(R.id.timingtext);
abc1text = (TextView)v.findViewById(R.id.abc1text);
urgent = (ImageView)v.findViewById(R.id.urgentstar);
}
}
#Override
public int getItemCount() {
// TODO Auto-generated method stub
if(_titles.size()<=0)
return 0;
return _titles.size();
}
#Override
public void onBindViewHolder(final ViewHolder holder, int position) {
// TODO Auto-generated method stub
try{
holder.title.setText(_titles.get(position));
if(_urgents.get(position).contains("yes")){
holder.urgent.setVisibility(View.VISIBLE);
}
pos = position;
if(!_venues.get(position).contentEquals("---")){
holder.venuetext.setVisibility(View.VISIBLE);
holder.venue.setVisibility(View.VISIBLE);
holder.abctext.setVisibility(View.VISIBLE);
holder.venue.setText(_venues.get(position));
}
if(!_timings.get(position).contentEquals("---")){
holder.timingtext.setVisibility(View.VISIBLE);
holder.timing.setVisibility(View.VISIBLE);
holder.abc1text.setVisibility(View.VISIBLE);
holder.timing.setText(_timings.get(position));
}
Target target = new Target() {
#Override
public void onPrepareLoad(Drawable arg0) {
// TODO Auto-generated method stub
Animation anim = AnimationUtils.loadAnimation(activity, R.anim.rotate);
holder.imgview.setImageResource(R.drawable.loading);
holder.imgview.startAnimation(anim);
}
#Override
public void onBitmapLoaded(Bitmap arg0, LoadedFrom arg1) {
// TODO Auto-generated method stub
holder.imgview.clearAnimation();
holder.imgview.setImageBitmap(arg0);
Log.i("completed", pos+" completed");
storeDB obj = new storeDB(_titles.get(pos), _venues.get(pos), _timings.get(pos), DbBitmapUtility.getBytes(arg0), _urgents.get(pos));
obj.execute();
}
#Override
public void onBitmapFailed(Drawable arg0) {
// TODO Auto-generated method stub
holder.imgview.clearAnimation();
holder.imgview.setImageResource(R.drawable.error);
}
};
Picasso.with(activity).load(_images.get(position)).into(target);
}catch(Exception e){
e.printStackTrace();
}
}
private class storeDB extends AsyncTask<Void, Void, Void>{
String title,venue,timing,urgent;
byte[] image;
public storeDB(String one, String two, String three, byte[] four, String five){
title = one;
venue = two;
timing = three;
image = four;
urgent = five;
}
#Override
protected Void doInBackground(Void... params) {
SQLiteHandler handler = new SQLiteHandler(activity);
handler.addNotice(title, venue, timing, image, urgent);
handler.close();
return null;
}
}
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int arg1) {
View v = LayoutInflater.from(parent.getContext()).inflate(
R.layout.item, parent, false);
Animation animation = AnimationUtils.loadAnimation(activity, (arg1>lastPosition)?R.anim.up_from_bottom:R.anim.down_from_top);
v.startAnimation(animation);
ViewHolder vh = new ViewHolder(v);
return vh;
}
}
I pass the image url to picasso library which loads image into target. Till image is not fetched by picasso, I am showing another loading image and giving it rotate animation effect.
Sometimes, even if image is loaded by picasso, it is not shown in imageview.I know this because on clicking that imageview full image is loaded in another activity which works fine. The rotating animation stops and loaded image also not shown in imageview. Also, the main view freezes sometimes when imageview is being loaded.
So, how can i solve this issue and make my app smoother in operation?
Thanks in advance.
UPDATE I found out that freezing issue was because of the weak reference to target. I solved it with strong reference but how do I solve hanging issue ? App gets hanged for some time when I am scrolling .
You can use a simple approach
Picasso.with(context)
.load(url)
.placeholder(R.drawable.user_placeholder)
.error(R.drawable.user_placeholder_error)
.into(imageView);
placholder image will be shown before loading the image and error image will be shown if error occur
UPDATE
to store in a database just write this much boiler plate code
class MyTarget implements Target {
private ImageView imageView;
public MyTarget(ImageView imageView) {
this.imageView = imageView;
}
#Override
public void onBitmapLoaded(final Bitmap bitmap, Picasso.LoadedFrom from) {
this.imageView.setImageBitmap(bitmap);
//store your bitmap as you were storing
}
}
and then
Picasso.with(context)
.load(url)
.placeholder(R.drawable.user_placeholder)
.error(R.drawable.user_placeholder_error)
.into(new MyTarget(imageView));
Related
In parse i have a class A which has a column (relation) named - view, which relates to class B( contains different images with different object id's).Now what i want to achieve is that : in android i have a activity(A) which has a recycle view which shows all the items of class A. The items are clickable which when clicked brings up the items from class B in parse to activity(B) . Now the issue is we are unable to intent a parse query from activity (A) to activity(B), so that we can display the items of class B in Activity(B).
Is there any different method for this? Any example for this would be of additional help.
EDIT
MainActivity
public class MainActivity extends AppCompatActivity {
ProgressDialog mProgressDialog;
GridAdapter gridAdapter;
RecyclerView recyclerView;
private List<Grid_G_S> grid_list = new ArrayList<>();
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Get the view from gridview_main.xml
setContentView(R.layout.activity_main);
// Execute RemoteDataTask AsyncTask
new RemoteDataTask().execute();
}
// RemoteDataTask AsyncTask
private class RemoteDataTask extends AsyncTask<Void, Void, Void> {
#Override
protected void onPreExecute() {
super.onPreExecute();
// Create a progressdialog
mProgressDialog = new ProgressDialog(MainActivity.this);
// Set progressdialog title
mProgressDialog.setTitle("Parse.com GridView Tutorial");
// Set progressdialog message
mProgressDialog.setMessage("Loading...");
mProgressDialog.setIndeterminate(false);
// Show progressdialog
mProgressDialog.show();
}
#Override
protected Void doInBackground(Void... params) {
// Create the array
grid_list = new ArrayList<>();
try {
ParseQuery<ParseObject> query = new ParseQuery<>("CardViewClass");
List<ParseObject> object1 = query.find();
for (final ParseObject country : object1) {
// Locate images in flag column
ParseFile image = (ParseFile) country.get("images");
ParseRelation<ParseObject> p = country.getRelation("view");
ParseQuery p2 = p.getQuery();
String f = image.getUrl();
Log.i("yji"," "+p2);
List<ParseObject> oc = p2.find();
for (ParseObject country2:oc){
ParseFile imgs = (ParseFile) country2.get("autoImage");
String fr = imgs.getUrl();
}
Grid_G_S setter = new Grid_G_S();
setter.setX(p2);
setter.setTitles((String) country.get("scrollText1"));
setter.setImages(f);
grid_list.add(setter);
}
}catch (ParseException e){
Log.e("err", e.getMessage());
} catch (com.parse.ParseException e) {
e.printStackTrace();
}
return null;
}
#Override
protected void onPostExecute(Void result) {
recyclerView = (RecyclerView) findViewById(R.id.recycler);
RecyclerView.LayoutManager mLayoutManager = new GridLayoutManager(getApplicationContext(),3);
gridAdapter = new GridAdapter(MainActivity.this, grid_list);
recyclerView.setLayoutManager(mLayoutManager);
recyclerView.setItemAnimator(new DefaultItemAnimator());
recyclerView.setAdapter(gridAdapter);
mProgressDialog.dismiss();
}
GridAdapter
public class GridAdapter extends RecyclerView.Adapter {
Context context;
LayoutInflater inflater;
private List<Grid_G_S> grid_g_sList = null;
private ArrayList<Grid_G_S> arraylist;
public GridAdapter(Context context, List<Grid_G_S> grid_list) {
this.context = context;
this.grid_g_sList = grid_list;
inflater = LayoutInflater.from(context);
this.arraylist = new ArrayList<>();
this.arraylist.addAll(grid_list);
}
public class MyViewHolder extends RecyclerView.ViewHolder {
TextView titles;
ImageView gridImages;
View mview;
MyViewHolder(View v) {
super(v);
mview = v;
titles = (TextView) v.findViewById(R.id.grid_single_text);
gridImages = (ImageView) v.findViewById(R.id.grid_single_image);
}
}
#Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View itemView = LayoutInflater.from(parent.getContext())
.inflate(R.layout.grid_single_row, parent, false);
return new MyViewHolder(itemView);
}
#Override
public void onBindViewHolder(MyViewHolder holder, final int position) {
Grid_G_S item = grid_g_sList.get(position);
holder.titles.setText(item.getTitles());
Picasso.with(context)
.load(grid_g_sList.get(position).getImages())
.into(holder.gridImages);
holder.mview.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Intent intent = new Intent(context, Secondactivity.class);
intent.putExtra("image", grid_g_sList.get(position).getImages());
intent.putExtra("query", String.valueOf(grid_g_sList.get(position).getX()));
context.startActivity(intent);
}
});
}
#Override
public int getItemCount() {
return grid_g_sList.size();
}
GridGetterSetter
public class Grid_G_S {
String Images;
String Titles;
ParseQuery x;
public String getImages() {
return Images;
}
public void setImages(String images) {this.Images = images;}
public String getTitles() {
return Titles;
}
public void setTitles(String titles) {this.Titles = titles;}
public ParseQuery getX() {
return x;
}
public void setX(ParseQuery x) {this.x = x;}
SecondActivity
public class Secondactivity extends AppCompatActivity {
String q1;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_secondactivity);
new DownloadingTask().execute();
Intent i = getIntent();
String images = i.getStringExtra("image");
q1 = i.getStringExtra("query");
Log.i("this is ", " " + q1);
}
private class DownloadingTask extends AsyncTask<Void, Void, Void> {
#Override
protected Void doInBackground(Void... voids) {
ParseQuery<ParseObject> query = new ParseQuery<>("CardViewClass");
try {
List<ParseObject> object1 = query.find();
for (final ParseObject country : object1) {
// Locate images in flag column
}
} catch (ParseException e) {
e.printStackTrace();
}
return null;
}
}
I'm new in Android and I have following code that shows the list of item in Adapter.
I have Four Different Adapter from where I am calling one comman AsyncTask to update Result. I have implemented one Interface ApiResponse and overrides apiResponseProcessing() to get result.
In Item of List "Add to Cart" Button Added in every row. OnClick of that button I am requesting to server. On Success of that response i want to update Button with "Added To Cart".
I have question How to update that string which is binded in onBindViewHolder(). I am getting success in that method but dont know how to update clicked Button from that method.
Here's my Adapter
/**
* Adapter
**/
public class AlbumPhotoDetailAdapter
extends RecyclerView.Adapter<AlbumPhotoDetailAdapter.ViewHolder> implements ApiResponse {
private final ArrayList<Photo> mValues;
Album album;
private Activity mContext;
private int mMemberId;
public AlbumPhotoDetailAdapter(Activity context, ArrayList<Photo> items) {
mValues = items;
this.mContext = context;
mMemberId = MemberPreference.getMemberId(mContext);
}
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.album_photo_detail_sub_view, parent, false);
return new ViewHolder(view);
}
#Override
public void onBindViewHolder(final ViewHolder holder, final int position) {
final Photo photo = mValues.get(position);
/**
* Album Owner Name
*/
String mOwnerName = photo.getOwnerName();
String mOwnerProfilePic = photo.getOwnerImage();
String mDateTime = photo.getDatetime();
String mPrice = String.valueOf(photo.getPrice());
/**
* Price String
*/
String priceStr = String.format(mContext.getString(R.string.string_dollar_price), mPrice);
holder.mAlbumPhotoDetailPhotoPrice.setText(priceStr);
/**
* Main Image
*/
Picasso.with(mContext).load(photo.getLink())
.error(R.drawable.ic_place_holder_circle)
.placeholder(R.drawable.ic_place_holder_circle)
.transform(new ImageTransformation(holder.mAlbumPhotoDetailSubMainImage))
.into(holder.mAlbumPhotoDetailSubMainImage);
/**
* Owner Name and Profile Pic
*/
holder.mAlbumPhotoDetailSubOwnerNameTextView.setText(mOwnerName);
Picasso.with(mContext).load(mOwnerProfilePic)
.error(R.drawable.ic_place_holder_circle)
.placeholder(R.drawable.ic_place_holder_circle)
.resize(100, 100)
.transform(new CircleTransform())
.into(holder.mAlbumPhotoDetailSubOwnerImage);
mDateTime = mDateTime != null ? DateUtils.getNiceTime(mDateTime) : "----";
holder.mAlbumPhotoDetailSubOwnerPostedTimeTextView.setText(mDateTime);
// Photo Add to cart.
holder.mAddToCartButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if(InternetConnection.checkConnection(mContext)) {
new BackgroundAsyncTask(mContext, (ApiResponse) mContext, mMemberId, photo.getId()).execute();
} else {
DailyStudio.noInternetConnectionToast(mContext);
}
}
});
}
#Override
public int getItemCount() {
return mValues.size();
}
#Override
public void apiResponseProcessing(String response) {
Log.i(TAG,"Api Response : "+response);
if(response.equals(Fields.JSON_SUCCESS)) {
}
}
/**
* View Holder
*/
public static class ViewHolder extends RecyclerView.ViewHolder {
public final View mView;
private ImageView mAlbumPhotoDetailSubOwnerImage;
private ImageView mAlbumPhotoDetailSubMainImage;
private TextView mAlbumPhotoDetailSubOwnerNameTextView;
private TextView mAlbumPhotoDetailSubOwnerPostedTimeTextView;
private TextView mAlbumPhotoDetailPhotoPrice;
private TextView mAlbumPhotoDetailSubDescription;
private Button mAddToCartButton;
public ViewHolder(View view) {
super(view);
mView = view;
mAlbumPhotoDetailSubOwnerImage = (ImageView) view.findViewById(R.id.album_photo_detail_sub_owner_image);
mAlbumPhotoDetailSubMainImage = (ImageView) view.findViewById(R.id.album_photo_detail_sub_main_image);
mAlbumPhotoDetailSubOwnerNameTextView = (TextView) view.findViewById(R.id.album_photo_detail_sub_owner_name_text_view);
mAlbumPhotoDetailSubOwnerPostedTimeTextView = (TextView) view.findViewById(R.id.album_photo_detail_sub_owner_posted_time_text_view);
mAlbumPhotoDetailPhotoPrice = (TextView) view.findViewById(R.id.album_photo_detail_photo_price);
mAlbumPhotoDetailSubDescription = (TextView) view.findViewById(R.id.album_photo_detail_sub_description);
mAddToCartButton = (Button) view.findViewById(R.id.album_photo_detail_photo_add_to_cart_button);
}
}
}
Here's my Interface
/**
* Interface..
*/
public interface ApiResponse {
public void apiResponseProcessing(String response);
}
Here's my Background AsyncTask
/**
* Background AsyncTask...
*/
public class BackgroundAsyncTask extends AsyncTask<Void, Void, String> {
private Context context;
private String accessToken;
private int memberId;
private int photoId;
private ApiResponse objIBaseApi;
public BackgroundAsyncTask(Context context, ApiResponse apiResponse, int memberId, int photoId) {
this.context = context;
this.memberId = memberId;
this.photoId = photoId;
accessToken = MemberPreference.getAccessToken(context);
this.objIBaseApi = apiResponse;
}
#Override
protected void onPreExecute() {
super.onPreExecute();
}
#Override
protected String doInBackground(Void... params) {
JSONObject json = JSONParser.addToCartPhoto(accessToken, memberId, photoId);
if(json != null) {
Log.i(TAG,"First Json : "+json.toString());
try {
if (json.getString(Fields.RESULT).equalsIgnoreCase(Fields.JSON_SUCCESS)) {
return Fields.JSON_SUCCESS;
} else if(json.getString(Fields.JSON_ERROR).equalsIgnoreCase(Fields.ERROR_ACCESS_DENIED)) {
String refreshToken = MemberPreference.getRefreshToken(context);
JSONObject newJSONObject = JSONParser.loginMemberWithRefreshToken(refreshToken, Integer.toString(memberId));
if(newJSONObject != null) {
if(newJSONObject.getString(Fields.JSON_ERROR).equalsIgnoreCase(Fields.ERROR_ACCESS_DENIED)) {
return Fields.ERROR_ACCESS_DENIED;
} else {
return Fields.JSON_SUCCESS;
}
} else
return Fields.ERROR_ACCESS_DENIED;
} else {
return Fields.JSON_ERROR;
}
} catch (JSONException e) {
e.printStackTrace();
return Fields.JSON_ERROR;
}
}
return Fields.JSON_ERROR;
}
#Override
protected void onPostExecute(String result) {
super.onPostExecute(result);
objIBaseApi.apiResponseProcessing(result);
}
}
Is there any solution or better way to do like this?
Your help would be appreciated. Thank you.
You Can keep one flag isAddedToCart variable in you bean class which you are using in your adapter(Photo). Now just pass the position in your asynctask once user click on "add to cart" button. On getting the successful you just need to find the bean from the list of bean you passed in adapter and change the flag isAddedToCart to true and notify your adapter thats it. Here is the code snippet:-
Photo Class
public class Photo{
private boolean isAddedToCart;
public void setAddedTOCart(boolean isAdded){
isAddedToCart = isAdded;
}
public boolean isAddedToCart(){
return isAddedToCart;
}
}
AlbumPhotoDetailAdapter onBindViewHolder
#Override
public void onBindViewHolder(final ViewHolder holder, final int position) {
final Photo photo = mValues.get(position);
/**
* Album Owner Name
*/
String mOwnerName = photo.getOwnerName();
String mOwnerProfilePic = photo.getOwnerImage();
String mDateTime = photo.getDatetime();
String mPrice = String.valueOf(photo.getPrice());
String isAdded = photo.isAddedToCart();
/**
* Price String
*/
String priceStr = String.format(mContext.getString(R.string.string_dollar_price), mPrice);
holder.mAlbumPhotoDetailPhotoPrice.setText(priceStr);
/**
* Main Image
*/
Picasso.with(mContext).load(photo.getLink())
.error(R.drawable.ic_place_holder_circle)
.placeholder(R.drawable.ic_place_holder_circle)
.transform(new ImageTransformation(holder.mAlbumPhotoDetailSubMainImage))
.into(holder.mAlbumPhotoDetailSubMainImage);
/**
* Owner Name and Profile Pic
*/
holder.mAlbumPhotoDetailSubOwnerNameTextView.setText(mOwnerName);
Picasso.with(mContext).load(mOwnerProfilePic)
.error(R.drawable.ic_place_holder_circle)
.placeholder(R.drawable.ic_place_holder_circle)
.resize(100, 100)
.transform(new CircleTransform())
.into(holder.mAlbumPhotoDetailSubOwnerImage);
mDateTime = mDateTime != null ? DateUtils.getNiceTime(mDateTime) : "----";
holder.mAlbumPhotoDetailSubOwnerPostedTimeTextView.setText(mDateTime);
if(isAdded){
holder.mAddToCartButton.setText("Added TO Cart");
}else{
holder.mAddToCartButton.setText("Add TO Cart");
}
// Photo Add to cart.
holder.mAddToCartButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if(InternetConnection.checkConnection(mContext)) {
new BackgroundAsyncTask(mContext, (ApiResponse) mContext, mMemberId, photo.getId(),position).execute();
} else {
DailyStudio.noInternetConnectionToast(mContext);
}
}
});
}
your Interface
public interface ApiResponse {
public void apiResponseProcessing(String response,int position);
}
Your Adapter apiResponceProcessing()
#Override
public void apiResponseProcessing(String response,int position) {
Log.i(TAG,"Api Response : "+response);
if(response.equals(Fields.JSON_SUCCESS)) {
mValues.get(position).setAddedTOCart(true);
notifyDataSetChange();
}
}
And finally your
BackgroundAsyncTask
public class BackgroundAsyncTask extends AsyncTask<Void, Void, String> {
private Context context;
private String accessToken;
private int memberId;
private int photoId;
private int mPosition;
private ApiResponse objIBaseApi;
public BackgroundAsyncTask(Context context, ApiResponse apiResponse, int memberId, int photoId,int position) {
this.context = context;
this.memberId = memberId;
this.photoId = photoId;
accessToken = MemberPreference.getAccessToken(context);
this.objIBaseApi = apiResponse;
this.mPosition = position;
}
#Override
protected void onPreExecute() {
super.onPreExecute();
}
#Override
protected String doInBackground(Void... params) {
JSONObject json = JSONParser.addToCartPhoto(accessToken, memberId, photoId);
if(json != null) {
Log.i(TAG,"First Json : "+json.toString());
try {
if (json.getString(Fields.RESULT).equalsIgnoreCase(Fields.JSON_SUCCESS)) {
return Fields.JSON_SUCCESS;
} else if(json.getString(Fields.JSON_ERROR).equalsIgnoreCase(Fields.ERROR_ACCESS_DENIED)) {
String refreshToken = MemberPreference.getRefreshToken(context);
JSONObject newJSONObject = JSONParser.loginMemberWithRefreshToken(refreshToken, Integer.toString(memberId));
if(newJSONObject != null) {
if(newJSONObject.getString(Fields.JSON_ERROR).equalsIgnoreCase(Fields.ERROR_ACCESS_DENIED)) {
return Fields.ERROR_ACCESS_DENIED;
} else {
return Fields.JSON_SUCCESS;
}
} else
return Fields.ERROR_ACCESS_DENIED;
} else {
return Fields.JSON_ERROR;
}
} catch (JSONException e) {
e.printStackTrace();
return Fields.JSON_ERROR;
}
}
return Fields.JSON_ERROR;
}
#Override
protected void onPostExecute(String result) {
super.onPostExecute(result);
objIBaseApi.apiResponseProcessing(result,mPosition);
}
}
Firstly in my opinion adapter should not care about network request. But
giving an answer in substance, you can try pass anonymous class for your apiResponseProcessing in same manner as you create OnClickListener for your button. It can look like this:
holder.mAddToCartButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if(InternetConnection.checkConnection(mContext)) {
new BackgroundAsyncTask(
mContext,
new ApiResponse() {
#Override
public void apiResponseProcessing(String response) {
Log.i(TAG,"Api Response : "+response);
if(response.equals(Fields.JSON_SUCCESS)) {
// Here you can access you holder till it final
}
}
},
mMemberId,
photo.getId()).execute();
} else {
DailyStudio.noInternetConnectionToast(mContext);
}
}
});
But code like this looks messy and spaghetti. As i say at the beginning there are exist at least one different approach to handle changes for buttons inside listview/recivleview. I use method, where adapter only care about building interface with given data and delegate buttons clicks to someone else (in most cases activity that contains listview). An easy way notify activity about button click is Bus messaging pattern. I use Otto event library. When delegate receive notification about button click, it can initiate data changing according current task and then initiate listview reloading or partial update only required rows.
Additional comments
Try to write beautiful code. Constructor AlbumPhotoDetailAdapter has different syntax to assign instance variables. One with this keyword and other without. Usually you should use one way.
public AlbumPhotoDetailAdapter(Activity context, ArrayList<Photo> items) {
this.values = items;
this.context = context;
this.memberId = MemberPreference.getMemberId(context);
}
album instance variable have no access modifiers indication. You should know, that in java programming language omitting access specifiers is not the same as private modifier.
I have three images stored in a table class called: "events" and table column called: "image" on Parse.com
I used two queries 1 to handle the displaying of the images and one to get another table's information (Those are all Strings)
THE PROBLEM IS:
The query that i used to get all the images only displays one of the three images in the RecyclerView instead of all three.
How can i display all three images from Parse.com inside a RecyclerView?
MY MAIN ACTIVITY:
public class MainActivity extends Activity {
//Defining Variables
protected Toolbar toolbar;
protected NavigationView navigationView;
private DrawerLayout drawerLayout;
protected Button mButtonHeader;
protected TextView mDayOfTheWeek;
protected TextView mDate;
//protected Context context;
//private long pageId = 137317903012386L;
private RecyclerView mRecyclerView;
//New Variables
private CustomAdapter mAdapter;
//Weather variables
//private ImageView weatherIconImageView;
private TextView temperatureTextView;
private TextView conditionTextView;
private TextView locationTextView;
private ProgressDialog dialog;
private ProgressDialog progressDialog;
final List<Information> data = new ArrayList<>();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//RecyclerView with Parse
mRecyclerView = (RecyclerView) findViewById(R.id.recycler_view_layout);
mRecyclerView.setLayoutManager(new LinearLayoutManager(this));
mAdapter = new CustomAdapter(getApplicationContext(), data);
//The Query i used to get the three images
ParseQuery<ParseObject> queryImgs = new ParseQuery<ParseObject> ("events");
//queryImgs.orderByAscending("order");
//queryImgs.setLimit(10);
queryImgs.findInBackground(new FindCallback<ParseObject>() {
#Override
public void done(final List<ParseObject> objects, ParseException e) {
//for (ParseObject obj_food : objects) {
//if (obj_food.getInt("order") == order) {
for (int i = 0; i < objects.size(); i++) {
//final ParseFile file = obj_food.getParseFile("image");
//Information information = new Information();
//information.mEventsPhotoID = objects.get(i).getParseFile("image");
final ParseFile file = objects.get(i).getParseFile("image");
//bitmap
file.getDataInBackground(new GetDataCallback() {
public void done(byte[] data, ParseException e) {
if (e == null) {
Bitmap bmp = BitmapFactory
.decodeByteArray(
data, 0,
data.length);
// Get the ImageView from
// main.xml
mEventsPhotoID = (ParseImageView) findViewById(R.id.eventsPhotoID);
//mEventsPhotoIDTwo = (ParseImageView)findViewById(R.id.eventsPhotoID);
// Set the Bitmap into the
// ImageView
mEventsPhotoID.setImageBitmap(bmp);
//mEventsPhotoIDTwo.setImageBitmap(bmp);
}
}
});
//}
//order++;
}
mRecyclerView.setAdapter(mAdapter);
}
});
//Query to load String data into the card view/recycler view
ParseQuery<ParseObject> query = ParseQuery.getQuery("events");
query.findInBackground(new FindCallback<ParseObject>() {
#Override
public void done(List<ParseObject> objects, ParseException e) {
if (e == null) {
for (int i = 0; i < objects.size(); i++) {
Information information = new Information();
information.mNewstTitle = objects.get(i).getString("name");
information.mNewsStory = objects.get(i).getString("shortinfo");
//information.partyCost = parseObject.getString("partyName");
String url=objects.get(i).getParseFile("image").getUrl();
//information.mEventsPhotoID = objects.getParseFile("partyFlyerImage");
//information.mEventsPhotoID = objects.get(i).getParseFile("image");
//information.mNewsPhotoIcon = R.drawable.newsitem));
//Initialize ImageView
ParseImageView imageViewPicasso = (ParseImageView) findViewById(R.id.eventsPhotoID);
//Loading image from below url into imageView
Picasso.with(MainActivity.this)
.load(url)
.into(imageViewPicasso);
data.add(information);
}
} else {
// something went wrong
}
//adapter.notifyItemRangeInserted(startPosition, imageUrls.length);
mRecyclerView.setAdapter(mAdapter);
}
});
}//END onCreate
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
drawerLayout.openDrawer(GravityCompat.START);
return true;
}
return super.onOptionsItemSelected(item);
}
}//End Main Activity
MY ADAPTER CLASS:
public class CustomAdapter extends RecyclerView.Adapter<CustomAdapter.MyViewHolder> {
//private List<String> imageUrls = new ArrayList<>();
List<Information> data = Collections.emptyList();
private LayoutInflater inflater;
private Context context;
/*public CustomAdapter (Context context,List<Information>data){
this.context=context;
inflater=LayoutInflater.from(context);
this.data= data;
}*/
public CustomAdapter (Context context,List<Information>data){
this.context=context;
inflater=LayoutInflater.from(context);
this.data= data;
}
#Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType){
View view= inflater.inflate(R.layout.cardview_upcomingshows, parent, false);
MyViewHolder holder = new MyViewHolder(view);
return holder;
}
#Override
public void onBindViewHolder(MyViewHolder holder, int position){
Information current= data.get(position);
//holder.mEventsPhotoID.setImageResource(current.mEventsPhotoID);
holder.mNewstTitle.setText(current.mNewstTitle);
holder.mNewsStory.setText(current.mNewsStory);
holder.mEventsPhotoID.setParseFile(current.mEventsPhotoID);
//holder.mEventsPhotoIDTwo.setParseFile(current.mEventsPhotoIDTwo);
}
#Override
public int getItemCount(){
return data.size();
}
class MyViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
//ImageView mEventsPhotoID;
TextView mNewstTitle;
TextView mNewsStory;
ParseImageView mEventsPhotoID;
//ParseImageView mEventsPhotoIDTwo;
public MyViewHolder(View itemView) {
super(itemView);
//promoterImage = (ParseImageView) itemView.findViewById(R.id.promoterPicImage);
mEventsPhotoID = (ParseImageView) itemView.findViewById(R.id.eventsPhotoID);
//mEventsPhotoIDTwo = (ParseImageView) itemView.findViewById(R.id.eventsPhotoIDTwo);
mNewstTitle = (TextView) itemView.findViewById(R.id.newsTitle);
mNewsStory = (TextView) itemView.findViewById(R.id.newsStory);
mNewstTitle.setOnClickListener(this);
mNewsStory.setOnClickListener(this);
itemView.setOnClickListener(this);
}
#Override
public void onClick(View v) {
Toast.makeText(context, "Recycle Click" + getLayoutPosition(), Toast.LENGTH_SHORT).show();
if(getLayoutPosition()==0){
Intent intentEventsWebView = new Intent(itemView.getContext(), EventsWebViewActivity.class);
//intentIndependenceDay.putExtra("MyClass", myclass);
intentEventsWebView.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
itemView.getContext().startActivity(intentEventsWebView);
}
if(getLayoutPosition()==1){
Intent intentIndependenceDay = new Intent(itemView.getContext(), NextActivity.class);
//intentIndependenceDay.putExtra("MyClass", myclass);
intentIndependenceDay.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
itemView.getContext().startActivity(intentIndependenceDay);
}
if(getLayoutPosition()==2){
Intent intentShelleyMaxwellDance = new Intent(itemView.getContext(), OtherActivity.class);
//intentIndependenceDay.putExtra("MyClass", myclass);
intentShelleyMaxwellDance.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
itemView.getContext().startActivity(intentShelleyMaxwellDance);
}
}
}
}
MY DATA MODEL CLASS(CONTAINING DATA FOR THE RECYCLER VIEW):
public class Information {
String mNewstTitle;
String mNewsStory;
ParseFile mEventsPhotoID;
}
instead of reading the ParseFile yourself, try using the Url approach mentioned here:
Displaying ParseFile Containing Images Using Their Urls In A RecyclerView
I am trying to get the image string from the recyclerview, that is already populated, so that I can display the image on the imageview of another activity. Here, I get the path(url) of image using jsoup:
org.jsoup.nodes.Document document = Jsoup.connect(URL).get();
for(Element e : document.select("img[src]"))
{
Elements imgScr = e.select("img[src]");
String elements = imgScr.attr("src");
String text = imgScr.attr("alt");
String desc = imgScr.attr("title");
arrayList.add(new FeedItem(text, elements, desc));
}
into elements variable and then storing it into arraylist. I want to get that path(url) of image(stored in elements) so that I can display that image in another activity. I tried to retrieve that url from the arrayList using this method:
public String getImageUrl(int pos)
{
return arrayList.get(pos).getThumb();
}
but a IndexOutOfBound exception is thrown, saying that the index(pos) is invalid and size of arrayList is 0. I don't know why it is saying that the list has size 0, while the Recyclerview gets pouplated and shows the data which I parsed using jsoup. Please help me out guys, I am stuck on this for three days.
Okay the complete code is here:
This the main activity which shows the recyclerview
public class RestaurantsAndCafesActivity extends Activity {
public static final String URL = "http://192.168.8.102:80/jay.html";
private RecyclerView mRecyclerView;
private RCRecyclerAdapter adapter;
public String imgUrl;
//public List<FeedItem> feedItemList;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.reyclerview_layout);
/* Initialize RecyclerView */
mRecyclerView = (RecyclerView) findViewById(R.id.recycler_view);
mRecyclerView.setLayoutManager(new LinearLayoutManager(this));
//parseResult();
new getDataAsyncTask().execute();
final GestureDetector mGestureDetector = new GestureDetector(RestaurantsAndCafesActivity.this, new GestureDetector.SimpleOnGestureListener() {
#Override public boolean onSingleTapUp(MotionEvent e) {
return true;
}
});
mRecyclerView.addOnItemTouchListener(new RecyclerView.OnItemTouchListener() {
#Override
public boolean onInterceptTouchEvent(RecyclerView recyclerView, MotionEvent motionEvent) {
View child = recyclerView.findChildViewUnder(motionEvent.getX(),motionEvent.getY());
if(child!=null && mGestureDetector.onTouchEvent(motionEvent)){
Toast.makeText(RestaurantsAndCafesActivity.this,"Clicked Number "+recyclerView.getChildPosition(child), Toast.LENGTH_SHORT).show();
imgUrl = new getDataAsyncTask().getImageUrl(recyclerView.getChildPosition(child));
Intent intent = new Intent(RestaurantsAndCafesActivity.this, GetReviewActivity.class);
intent.putExtra("Imgurl" ,imgUrl);
startActivity(intent);
return true;
}
return false;
}
#Override
public void onTouchEvent(RecyclerView recyclerView, MotionEvent motionEvent) {
}
});
}
public class getDataAsyncTask extends AsyncTask<Void,Void,Void>{
ArrayList<FeedItem> arrayList = new ArrayList<>();
public String getImageUrl(int pos)
{
return arrayList.get(pos).getThumb();
}
#Override
protected Void doInBackground(Void... params) {
try {
org.jsoup.nodes.Document document = Jsoup.connect(URL).get();
for(Element e : document.select("img[src]"))
{
Elements imgScr = e.select("img[src]");
String elements = imgScr.attr("src");
String text = imgScr.attr("alt");
String desc = imgScr.attr("title");
arrayList.add(new FeedItem(text, elements, desc));
}
}
catch(IOException e)
{
e.printStackTrace();
}
return null;
}
ProgressDialog progressDialog;
#Override
protected void onPreExecute()
{
progressDialog = ProgressDialog.show(RestaurantsAndCafesActivity.this,"Loading","Please Wait",true,false);
}
#Override
protected void onPostExecute(Void aVoid) {
progressDialog.dismiss();
adapter = new RCRecyclerAdapter(getApplicationContext(),arrayList);
mRecyclerView.setAdapter(adapter);
}
}
}
These are the adapter, viewholder and data classes:
public class RCRecyclerAdapter extends RecyclerView.Adapter<RCRecyclerViewListRowHolder> {
private List<FeedItem> feedItemList;
private Context mContext;
public RCRecyclerAdapter(Context context, List<FeedItem> feedItemList) {
this.feedItemList = feedItemList;
this.mContext = context;
}
#Override
public RCRecyclerViewListRowHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
View v = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.restaurants_cafes_layout_card, null);
RCRecyclerViewListRowHolder mh = new RCRecyclerViewListRowHolder(v);
return mh;
}
#Override
public void onBindViewHolder(RCRecyclerViewListRowHolder RCRecyclerViewListRowHolder, int i){
FeedItem feedItem = feedItemList.get(i);
Picasso.with(mContext).load(feedItem.getThumb()
).error(R.drawable.placeholder).placeholder(R.drawable.placeholder).into(RCRecyclerViewListRowHolder.thumbnail);
RCRecyclerViewListRowHolder.title.setText(feedItemList.get(i).title);
RCRecyclerViewListRowHolder.desc.setText(feedItemList.get(i).desc);
}
#Override
public int getItemCount() {
return (null != feedItemList ? feedItemList.size() : 0);
}
}
viewholder:
public class RCRecyclerViewListRowHolder extends RecyclerView.ViewHolder {
public ImageView thumbnail;
public TextView title;
public TextView desc;
//Context context;
public RCRecyclerViewListRowHolder(View view) {
super(view);
this.thumbnail = (ImageView) view.findViewById(R.id.thumbnail);
this.title = (TextView) view.findViewById(R.id.title);
this.desc = (TextView) view.findViewById(R.id.desc);
}
}
data:
public class FeedItem {
public String title;
public String thumb;
public String desc;
public FeedItem(String title, String thumb , String desc) {
this.title = title;
this.thumb = thumb;
this.desc = desc;
}
public String getThumb() {
return thumb;
}
}
Here is the culprit:
imgUrl = new getDataAsyncTask().getImageUrl(recyclerView.getChildPosition(child));
You're actually creating a new AsyncTask - if you try to get an element from the arrayList inside that new AsyncTask it's obvious the list is empty, because task populates the list within its doInBackground() method, and it hasn't been executed.
Solution:
In your onCreate method, create your getDataAsyncTask and keep a reference to it in a member variable.
Then, when the task finishes its execution and calls onPostExecute(Void aVoid) set a flag indicating that fact.
Next, in your onClickListener, reference the same task, but execute the code only if the asyncTaskFinished flag is set to true:
public class RestaurantsAndCafesActivity extends Activity {
public static final String URL = "http://192.168.8.102:80/jay.html";
private RecyclerView mRecyclerView;
private RCRecyclerAdapter adapter;
public String imgUrl;
//public List<FeedItem> feedItemList;
private getDataAsyncTask myAsyncTask;
private volatile boolean asyncTaskFinished = false;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.reyclerview_layout);
/* Initialize RecyclerView */
mRecyclerView = (RecyclerView) findViewById(R.id.recycler_view);
mRecyclerView.setLayoutManager(new LinearLayoutManager(this));
//parseResult();
myAsyncTask = new getDataAsyncTask();
myAsyncTask.execute();
...
mRecyclerView.addOnItemTouchListener(new RecyclerView.OnItemTouchListener() {
#Override
public boolean onInterceptTouchEvent(RecyclerView recyclerView, MotionEvent motionEvent) {
View child = recyclerView.findChildViewUnder(motionEvent.getX(),motionEvent.getY());
if(child!=null && mGestureDetector.onTouchEvent(motionEvent)){
if(asyncTaskFinished) {
Toast.makeText(RestaurantsAndCafesActivity.this,"Clicked Number "+recyclerView.getChildPosition(child), Toast.LENGTH_SHORT).show();
imgUrl = myAsyncTask.getImageUrl(recyclerView.getChildPosition(child));
Intent intent = new Intent(RestaurantsAndCafesActivity.this, GetReviewActivity.class);
intent.putExtra("Imgurl" ,imgUrl);
startActivity(intent);
return true;
}
return false;
}
}
In AsyncTask:
#Override
protected void onPostExecute(Void aVoid) {
progressDialog.dismiss();
adapter = new RCRecyclerAdapter(getApplicationContext(),arrayList);
mRecyclerView.setAdapter(adapter);
asyncTaskFinished = true;
}
Please note that it is a solution that makes minimal changes in your existing code, however i would suggest a different approach - keeping the list in AsyncTask is kinda ugly, better way is to return it from doInBackground, and within onPostExecute, pass it to adapter (while not keeping a class-scope reference to it in the task), and when you need to access an element fromn the list, just reference the adapter, not your AsyncTask:
imgUrl = adapter.getList().get(recyclerView.getChildPosition(child)).getThumb();
I have a problem with a ViewPager. My ViewPager must shows images from Parse.com. Each item of ViewPager is a fragment, the same fragment, and it shows different images depending the item.
My problem is for example: if i have three pages, the first page shows nothing, the second one, shows the correct image, and the third one the correct one too. When I return to the first page then the image loads, but only when i return to it, not the first time.
This is my code:
My Activity:
public class FolletosActivity extends FragmentActivity {
public static final String QUERY = "query";
String selec;
ViewPager viewPager;
private PagerAdapter mPagerAdapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_carta_menu);
Intent intent = getIntent();
selec = intent.getStringExtra(QUERY);
viewPager = (ViewPager) findViewById(R.id.pager);
mPagerAdapter = new FolletosPagerAdapter(getSupportFragmentManager());
viewPager.setAdapter(mPagerAdapter);
}
The PagerAdapter:
public class FolletosPagerAdapter extends FragmentPagerAdapter {
int numPages;
public FolletosPagerAdapter(FragmentManager fm) {
super(fm);
ParseQuery<ParseObject> query = ParseQuery.getQuery("folletos_app");
query.whereGreaterThanOrEqualTo("num_pag", 0); //busco todos los objetos de parse
List<ParseObject> promosParse = null;
try {
promosParse = query.find();
numPages = promosParse.size();
} catch (ParseException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
#Override
public Fragment getItem(int position) {
return new PaginaFolletoFragment(position);
}
#Override
public int getCount() {
return numPages;
}
}
And the Fragment:
public class PaginaFolletoFragment extends Fragment {
public static final String QUERY = "query";
ParseImageView imageView;
String selec;
int position_;
public PaginaFolletoFragment(int position) {
// TODO Auto-generated constructor stub
position_ = position;
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onActivityCreated(savedInstanceState);
String filepath = "/sdcard/Android/data/package/cache/uil-images/"+"folleto_"+selec+"_"+"numpage_"+position_;
File file = new File(filepath);
if(file.exists()){
Bitmap bmp = BitmapFactory.decodeFile(filepath);
imageView.setImageBitmap(bmp);
}
else{
if(ImageLoader.getInstance().isInited())
ImageLoader.getInstance().destroy();
//Create image options.
DisplayImageOptions options = new DisplayImageOptions.Builder()
.cacheInMemory(true)
.cacheOnDisc(true)
.build();
//Create a config with those options.
ImageLoaderConfiguration config = new ImageLoaderConfiguration.Builder(getActivity().getApplicationContext())
.defaultDisplayImageOptions(options)
.discCacheFileNameGenerator(new FileNameGenerator() {
#Override
public String generate(String imageUri) {
return "folleto_"+selec+"_"+"numpage_"+position_;
}
})
.memoryCacheSize(41943040)
.discCacheSize(104857600)
.threadPoolSize(10)
.build();
ImageLoader.getInstance().init(config);
ParseQuery<ParseObject> query = ParseQuery.getQuery("folletos_app");
query.whereEqualTo("num_pag", position_);
List<ParseObject> promosParse;
try {
promosParse = query.find();
for(final ParseObject dealsObject : promosParse) {
final ParseFile image = dealsObject.getParseFile("pagina");
imageView.loadInBackground(new GetDataCallback() {
public void done(byte[] data, ParseException e) {
// The image is loaded and displayed!
int oldHeight = imageView.getHeight();
int oldWidth = imageView.getWidth();
ImageLoader imageLoader = ImageLoader.getInstance();
imageLoader.displayImage(image.getUrl(), imageView);
}
});
}
} catch (ParseException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
} //los meto en una lista
}
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_pagina_menu, container, false);
imageView = (ParseImageView) view.findViewById(R.id.imagePage);
Intent intent = getActivity().getIntent();
selec = intent.getStringExtra(QUERY);
return view;
}
}
Sorry if this is late but this is what you wanna do..
//Get the image from your ParseObject
ParseFile file = (ParseFile) dealsObject.getParseFile("pagina");
//Set the imageview to show the content of your ParseFile
imageView.setParseFile(file);
//Load the image in the background and display ones loaded
imageView.loadInBackground(new GetDataCallback() {
#Override
public void done(byte[] bytes, ParseException e) {
if (e != null) {
}
}
}