this getItemViewType()
public int getItemViewType(int position) {
boolean type = _arr_GameList.get(position).isFirstComment();
if (type) {
return 0;
} else {
return 1;
}
}
After that set the view holder type wise but not display data . i used one arraylist but i want to two arraylist position first parent and second chhailed position
public void onBindViewHolder(#NonNull final MyViewHolder holder, int position) {
object = _arr_GameList.get(position);
if (object != null) {
if (object.isFirstComment()) {
setData(holder, position);
} else {
setData(holder, position);
}
}
}
After that set the view holder type wise but not display data . i used one arraylist but i want to two arraylist position first parent and second chhailed position
private void ReplyCommentServiceCall(final MyViewHolder holder, int position, String comment_id, String comment_body) {
Call<ResponseBody> call;
call = LaravelRetrofite.addgetClient().AddreplyComment("Bearer " + preferencesUtility.getAccessToken(), "Application/json", article_id, comment_id, comment_body);
call.enqueue(new Callback<ResponseBody>() {
#Override
public void onResponse(Call<ResponseBody> call, retrofit2.Response<ResponseBody> response) {
try {
if (response.isSuccessful()) {
Log.v("Articalereplycomment", response.toString());
Log.v("replygetposition", "" + position);
boolean type = _arr_GameList.get(position).isFirstComment();
Log.v("layouttype", "" + type);
object = _arr_GameList.get(position);
ArticleCommentsModel articleCommentsModel = _arr_GameList.get(position + 1);
articleCommentsModel.setComment_body(comment_body);
articleCommentsModel.setDeleteCommentOption("1");
articleCommentsModel.setFirstComment(false);
_arr_GameList.add(articleCommentsModel);
setData(holder, position + 1);
notifyDataSetChanged();
} else {
// error case
switch (response.code()) {
case 404:
NetworkUtility.ToastFunction(mActivity, "not found");
break;
case 500:
NetworkUtility.ToastFunction(mActivity, "server broken");
break;
default:
NetworkUtility.ToastFunction(mActivity, "unknown error");
break;
}
}
} catch (Exception e) {
String message = e.getMessage().replace("java.lang.Throwable: ", "");
}
}
#Override
public void onFailure(Call<ResponseBody> call, Throwable t) {
Log.v("Upload", t.getMessage());
String message = t.getMessage().replace("java.lang.Throwable: ", "");
}
});
}
are you sure you got the method right?
right now it seems that this if is useless.
both cases are the same.
if (object.isFirstComment()) {
setData(holder, position);
} else {
setData(holder, position);
}
Related
i checked a lot of questions to fix my issue but no success also this will fix a 3 issues for me, a big ones!
I'm parsing my YouTube videos using Gson and Retrofit and it showed successfully but after last results it returns the same items over and over.
Here i call my function used to parse videos..
// NestedScrollView used instead of using
// RecyclerView as NestedScrollView disables
// scroll listeners of recycler so, we use nested.
NestedScrollView nestedScrollView = findViewById(R.id.nested_scrollview);
nestedScrollView.setOnScrollChangeListener((NestedScrollView.OnScrollChangeListener) (v, scrollX, scrollY, oldScrollX, oldScrollY) -> {
if ((scrollY >= (v.getChildAt(v.getChildCount() - 1).getMeasuredHeight() - v.getMeasuredHeight())) && scrollY > oldScrollY) {
getJson();
}
});
if (videoList.size() == 0) {
getJson();
}
}
And here is my getJson which parse my videos...
// Get Json Data
private void getJson() {
shimmer.setVisibility(View.VISIBLE);
// Parsed Url
String url = YoutubeAPI.BASE_URL + YoutubeAPI.SEARCH + YoutubeAPI.KEY + YoutubeAPI.CHANNNEL_ID + YoutubeAPI.ORDER + YoutubeAPI.MAX_RESULTS + YoutubeAPI.PART;
if (!nextPageToken.equals("")) {
// Add page token to new url
url += (YoutubeAPI.NEXT_PAGE_TOKEN + nextPageToken);
shimmer.setVisibility(View.GONE);
}
if (nextPageToken == null) {
return;
}
Call<YoutubeMain> data = YoutubeAPI.getMainVideo().getYoutube(url);
data.enqueue(new Callback<YoutubeMain>() {
#Override
public void onResponse(Call<YoutubeMain> call, Response<YoutubeMain> response) {
if (response.errorBody() != null) {
Log.v("TAG", "onResponse: " + response.errorBody());
shimmer.setVisibility(View.GONE);
// Print error code
Toast.makeText(YoutubeActivity.this, response.errorBody().toString(), Toast.LENGTH_SHORT).show();
} else {
YoutubeMain youtubeMain = response.body();
assert youtubeMain != null;
videoList.addAll(youtubeMain.getItems());
adapter.notifyDataSetChanged();
shimmer.setVisibility(View.GONE);
// Get nextPageToken to assign it to new url
if (youtubeMain.getNextPageToken() != null) {
nextPageToken = youtubeMain.getNextPageToken();
}
// Get creatorName to assign it to author
if (youtubeMain.getItems().get(0).getSnippet().getChannelTitle() != null) {
author.setText(youtubeMain.getItems().get(0).getSnippet().getChannelTitle());
}
}
}
#Override
public void onFailure(Call<YoutubeMain> call, Throwable t) {
shimmer.setVisibility(View.GONE);
// Print error code
Toast.makeText(YoutubeActivity.this, t.getMessage(), Toast.LENGTH_SHORT).show();
}
});
}
this is my adapter...
public class YoutubeMainAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private List<YoutubeVideo> videoList;
private final OnYoutubeItemClickListener listener;
private String formatted_date;
public YoutubeMainAdapter(Context context, List<YoutubeVideo> videoList, OnYoutubeItemClickListener listener) {
this.videoList = videoList;
this.listener = listener;
}
class YoutubeHolder extends RecyclerView.ViewHolder {
ImageView thumbnail;
TextView title, description, publishedAt;
YoutubeHolder(#NonNull View itemView) {
super(itemView);
thumbnail = itemView.findViewById(R.id.ImageThumb);
title = itemView.findViewById(R.id.textViewTitle);
description = itemView.findViewById(R.id.textViewDes);
publishedAt = itemView.findViewById(R.id.textViewDate);
}
public void setData(YoutubeVideo data) {
String getTitle = data.getSnippet().getTitle();
String getDescription = data.getSnippet().getDescription();
String getPublishedAt = format_date(data.getSnippet().getPublishedAt());
String getThumbnail = data.getSnippet().getThumbnails().getHigh().getUrl();
title.setText(getTitle);
description.setText(getDescription);
publishedAt.setText(getPublishedAt);
Picasso.get()
.load(getThumbnail)
.into(thumbnail);
}
void bind(final YoutubeVideo item, final OnYoutubeItemClickListener listener) {
itemView.setOnClickListener(v -> listener.onItemClick(item));
}
}
#NonNull
#Override
public RecyclerView.ViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.activity_youtube_listitem, parent, false);
return new YoutubeHolder(view);
}
#Override
public void onBindViewHolder(#NonNull RecyclerView.ViewHolder holder, int position) {
YoutubeVideo youtubeVideo = videoList.get(position);
YoutubeHolder youtubeHolder = (YoutubeHolder) holder;
youtubeHolder.setData(youtubeVideo);
youtubeHolder.bind(videoList.get(position), listener);
}
private String format_date(String publishedAt) {
try {
DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", Locale.getDefault());
#SuppressLint("SimpleDateFormat") SimpleDateFormat format = new SimpleDateFormat("dd, MMM yyyy • hh:mm a");
Date date = dateFormat.parse(publishedAt);
assert date != null;
formatted_date = format.format(date);
} catch (ParseException e) {
e.printStackTrace();
}
return formatted_date;
}
#Override
public int getItemCount() {
return videoList.size();
}
}
I tried many times to fix it but no success and after checking some questions related to this issues, all answers was for (for loop) with regular Json parsing and no Gson. thanks in advance and i appreciate help.
Your adapter is correct.
Since you noted: after last results it returns the same items over and over. thats because nextPageToken will return null in the last time and you keep the last reference if (youtubeMain.getNextPageToken() != null) nextPageToken = youtubeMain.getNextPageToken();
You need a condition to stop requesting new pages
I have three fragments in a FragmentPagerAdapter, and each of them would fetch a list of frames/data from a server using Volley. This data would later be used to update the Fragment's RecyclerView Adapter as a Cursor.
VolleyRestClientUtils.get(getString(R.string.PATH_SHOP), LOG_TAG, params, true, false, new JsonHttpResponseHandler() {
public void onSuccess(JSONObject response) {
Log.d(LOG_TAG, "request Response : " + response.toString());
try {
String status = response.getString("status");
if (RestClientUtils.STATUS_OK.equals(status)) {
final JSONArray frames = response.getJSONArray("items");
Log.d(LOG_TAG, "request Response : " + frames.length());
if (frames != null && frames.length() > 0) {
new AsyncTask<Void, Void, Boolean>() {
#Override
protected Boolean doInBackground(Void... voids) {
List<ContentValues> listShopFrame = ShopFrame.fromJSONArray(frames, sort);
if (listShopFrame.size() > 0 && isActivityActive()) {
ContentResolver cr = getActivity().getContentResolver();
if (!isRequestMore) {
cr.delete(ShopFrame.CONTENT_URI, ShopFrame.COLUMN_CATEGORY + "=?",
new String[]{sort});
paramSkip = frames.length();
} else {
paramSkip += frames.length();
}
ArrayList<ContentProviderOperation> operations = new ArrayList<>();
String log = listShopFrame.size()+" ";
for (int i = 0; i < listShopFrame.size(); i++) {
operations.add(ContentProviderOperation
.newInsert(ShopFrame.CONTENT_URI)
.withValues(listShopFrame.get(i))
.build());
log += listShopFrame.get(i).toString()+"\n";
}
Log.i("loader_callback_"+sort, log);
//cr.applyBatch(ShopFrame.CONTENT_AUTHORITY, operations);
ContentValues[] opsAsArray = new ContentValues[listShopFrame.size()];
listShopFrame.toArray(opsAsArray);
cr.bulkInsert(ShopFrame.CONTENT_URI, opsAsArray);
//return true;
}
return true;
}
#Override
protected void onPostExecute(Boolean result) {
dataRefreshed = true;
Log.i("loader_callback_"+sort, "response post execute");
if (result) {
loadSucceed();
PicMixApp.getInstance().setRefreshed(ShopFrameFragment.this.getClass().getName());
} else {
loadFailed(null);
}
}
}.execute();
} else {
//TODO
//Handle error
loadFailed(getString(R.string.err_load_s, getString(R.string.frame)));
}
} else if (VolleyRestClientUtils.STATUS_RESOURCE_NOT_FOUND.equals(status)) {
hasMore = false;
loadSucceed();
} else {
loadFailed(getString(R.string.err_load_s, getString(R.string.frame)));
}
} catch (Exception e) {
Log.e(LOG_TAG, "Exception:" + e.getMessage());
loadFailed(getString(R.string.err_load_s, getString(R.string.frame)));
}
}
#Override
public void onJSONError(String responseString) {
loadFailed(getString(R.string.err_load_s, getString(R.string.frame)));
}
#Override
public void onFailure(String errMessage, int statusCode, Map<String, String> headers, byte[] responseBytes) {
loadFailed(getString(R.string.err_load_s, getString(R.string.frame)));
}
});
Whereas loadSucceed() has this following code:
if (this.recyclerView != null) {
final RecyclerView.Adapter adapter = recyclerView.getAdapter();
if (adapter != null) {
adapter.registerAdapterDataObserver(new RecyclerView.AdapterDataObserver() {
#Override
public void onChanged() {
super.onChanged();
Log.i(DefaultRecyclerFragment.this.getClass().getName(), "onChanged");
adapter.unregisterAdapterDataObserver(this);
isLoading = false;
}
public void onItemRangeRemoved(int positionStart, int itemCount) {
Log.i(DefaultRecyclerFragment.this.getClass().getName(), "onItemRangeRemoved:" + positionStart + ", itemcount:" + itemCount);
adapter.unregisterAdapterDataObserver(this);
isLoading = false;
}
});
if (adapter instanceof CursorRecyclerAdapter && loadMoreView != null) {
((CursorRecyclerAdapter) adapter).removeFooter(loadMoreView);
}
}
}
I've put the code to initialize the loader in the onResume() method of each fragment:
int id = 100+Integer.valueOf(sort);
Loader l = getLoaderManager().getLoader(id);
Log.i("loader_callback_"+sort, "success loading volley "+l);
if(l == null) {
getLoaderManager().restartLoader(id, null, this);
}
My problem is that there seems to be some sort of race condition happening, that the currently viewed fragment's adapter seem to be updated twice, and sometimes thrice. The initial cursor fetched by the Fragment's Loader has 10 rows, sure, but after the update, most of the time it only has 7 of the 21 rows expected to be put in.
I thought all the ContentResolvers' operations are synchronous (can only be done one after another, not simultaneously). What's going on here?
EDIT: Should I just put the loader init code in the loadSuccess() callback?
EDIT2: I should note that these Fragments extend android.support.v4.app.Fragment, and I'm using the version 27.1.1 of the Support Library.
I am new to android development.I have a recyclerview with Viewholder for displaying photo.I have implement like feature in my app but only problem that I am facing is when I add a like on the photo the like does not show on photo I liked instead it is showing like on another photo that is down below,when I see in firebase database it looks fine but it does not display in the right position in recycler view.
I think it is not updating position how can I solve this?
this is my adapter class
#Override
public void onBindViewHolder(#NonNull final RecyclerView.ViewHolder holder, final int position) {
// mHolder = holder;
photo = moviesList.get(position);
// final VideoHolder viewHolder2 = (VideoHolder)holder;
int viewType = getItemViewType(holder.getAdapterPosition());
switch ( viewType ) {
case IMAGE_TYPE:
PhotoHolder photoview = (PhotoHolder) holder;
mPhotoHolder = photoview;
getCurrentUsername();
getLikesPhotoString();
final ImageLoader imageLoader = ImageLoader.getInstance();
imageLoader.displayImage(getItem(position).getImage_path(),photoview.image);
photoview.mHeart.setOnLikeListener(new OnLikeListener() {
#Override
public void liked(LikeButton likeButton) {
addNewPhotolike(mPhotoHolder);
}
#Override
public void unLiked(LikeButton likeButton) {
removePhotolike(mPhotoHolder);
}
});
photoview.Star.setOnLikeListener(new OnLikeListener() {
#Override
public void liked(LikeButton likeButton) {
}
#Override
public void unLiked(LikeButton likeButton) {
}
});
break;
case VIDEO_TYPE:
final VideoHolder viewHolder2 = (VideoHolder)holder;
mVideoHolder = viewHolder2;
break;
}
}
#Override
public int getItemCount() {
return moviesList.size();
}
public Photo getItem(int position) {
return moviesList.get(position);
}
#Override
public int getItemViewType ( int position ) {
int viewType;
if (moviesList.get(position).getType_post().contains("Photo")) {
viewType = IMAGE_TYPE;
} else{
viewType = VIDEO_TYPE;
}
return viewType;
}
this is were photo like is added to firebase
private void addNewPhotolike(TestAdapter.PhotoHolder holder, final int position){
Log.d(TAG, "addNewlike: adding new like ");
String newLikeID = mReference.push().getKey();
Likes likes = new Likes();
likes.setUser_id(FirebaseAuth.getInstance().getCurrentUser().getUid());
mReference.child(mContext.getString(R.string.dbname_photos))
.child(getItem(position).getPhoto_id())
.child(mContext.getString(R.string.field_likes))
.child(newLikeID)
.setValue(likes);
mReference.child(mContext.getString(R.string.dbname_user_photos))
.child(getItem(position).getUser_id())
.child(getItem(position).getPhoto_id())
.child(mContext.getString(R.string.field_likes))
.child(newLikeID)
.setValue(likes);
holder.mHeartPhoto.setLiked(true);
HashMap<String ,String> notificationData = new HashMap<>();
notificationData.put("from",FirebaseAuth.getInstance().getCurrentUser().getUid());
notificationData.put("type","likes");
notificationData.put("photo_desc",getItem(position).getDescription());
holder.mNotification.child(getItem(position).getUser_id()).push().setValue(notificationData).addOnSuccessListener(new OnSuccessListener<Void>() {
#Override
public void onSuccess(Void aVoid) {
// getLikesString(mHolder);
getLikesPhotoString(mPhotoHolder,position);
}
}).addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
// getLikesString(mHolder);
getLikesPhotoString(mPhotoHolder,position);
}
});
}
This is my code where like is retrieved from firebase and shown in text.
private void getLikesPhotoString(final TestAdapter.PhotoHolder holder, final int postion){
Log.d(TAG, "getLikesString: getting likes string");
try{
DatabaseReference reference = FirebaseDatabase.getInstance().getReference();
reference.keepSynced(true);
Query query = reference
.child(mContext.getString(R.string.dbname_photos))
.child(getItem(postion).getPhoto_id())
.child(mContext.getString(R.string.field_likes));
query.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
holder.usersPhoto = new StringBuilder();
for(DataSnapshot singleSnapshot : dataSnapshot.getChildren()){
DatabaseReference reference = FirebaseDatabase.getInstance().getReference();
Query query = reference
.child(mContext.getString(R.string.dbname_users))
.orderByChild(mContext.getString(R.string.field_user_id))
.equalTo(singleSnapshot.getValue(Likes.class).getUser_id());
query.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for(DataSnapshot singleSnapshot : dataSnapshot.getChildren()){
Log.d(TAG, "onDataChange: found like: " +
singleSnapshot.getValue(User.class).getUsername());
holder.usersPhoto.append(singleSnapshot.getValue(User.class).getUsername());
holder.usersPhoto.append(",");
}
String[] splitUsers = holder.usersPhoto.toString().split(",");
if( holder.usersPhoto.toString().contains(currentUsername + ",")){
holder.likephotobycurrentUser = true;
}else{
holder.likephotobycurrentUser = false;
}
Log.d(TAG, "onDataChange: likes string: " + holder.mLIkePhotoString);
// setupwidjets();
int length = splitUsers.length;
if(length == 1){
holder.mLIkePhotoString = "Liked by " + splitUsers[0];
}
else if(length == 2){
holder.mLIkePhotoString = "Liked by " + splitUsers[0]
+ " and " + splitUsers[1];
}
else if(length == 3){
holder.mLIkePhotoString = "Liked by " + splitUsers[0]
+ ", " + splitUsers[1]
+ " and " + splitUsers[2];
}
else if(length == 4){
holder.mLIkePhotoString = "Liked by " + splitUsers[0]
+ ", " + splitUsers[1]
+ ", " + splitUsers[2]
+ " and " + splitUsers[3];
}
else if(length > 4){
holder.mLIkePhotoString = "Liked by " + splitUsers[0]
+ ", " + splitUsers[1]
+ ", " + splitUsers[2]
+ " and " + (splitUsers.length - 3) + " others";
}
Log.d(TAG, "onDataChange: likes string: " + holder.mLIkePhotoString);
//setup likes string
// setupLikePhotostring(holder, holder.mLIkePhotoString);
holder.mHeartPhoto.setLiked(true);
if (holder.likephotobycurrentUser){
holder.mHeartPhoto.setLiked(true);
}else {
holder.mHeartPhoto.setLiked(false);
}
holder.likes.setText(holder.mLIkePhotoString);
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
}
if(!dataSnapshot.exists()){
holder.mLIkePhotoString = "";
holder.likephotobycurrentUser = false;
//setupwidjets();
// setupLikePhotostring(holder,holder.mLIkePhotoString);
if (holder.likephotobycurrentUser){
holder.mHeartPhoto.setLiked(true);
}else {
holder.mHeartPhoto.setLiked(false);
}
holder.likes.setText(holder.mLIkePhotoString);
holder.mHeartPhoto.setLiked(false);
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
}catch (NullPointerException e){
Log.e(TAG, "removeStar: NullPointer"+e.getMessage());
holder.mLIkePhotoString = "";
holder.likephotobycurrentUser = false;
// setupLikePhotostring(mPhotoHolder,holder.mLIkePhotoString);
if (holder.likephotobycurrentUser){
holder.mHeartPhoto.setLiked(true);
}else {
holder.mHeartPhoto.setLiked(false);
}
holder.likes.setText(holder.mLIkePhotoString);
}
}
Change this line
photo = moviesList.get(holder.getAdapterPosition());
to
photo = moviesList.get(position);
where position variable is same as we got in below function
public void onBindViewHolder(#NonNull final RecyclerView.ViewHolder holder, final int position);
And also change holder.getAdapterPosition() to position in onBindViewHolder(...) function.
In my android project, I am using RecyclerView. At run time I need to add files to it so that it will upload those files to my Server. And there will be a ProgressBar on each item to show upload progress. My problem is whenever I want to upload more files at a time, a progress of one item is showing on another Item. This is happening only on currently running uploads as I hide completed ProgressBar. And it is also happening whenever I scroll up and down. I have tried to store the upload progress in hashMap and retrieve it whenever an Item appears, but it did not work. I know this is the natural behavior of RecyclerView compare to a listview. I want to know how this can be achieved. I used as s3 to upload files. And Glide to show thumbnails of files if the file is an image.
CODE:
#Override
public void onBindChildViewHolder(final MyChildViewHolder holder, final int groupPosition, final int childPosition, int viewType) {
final MyChildItem child = Items.get(groupPosition).children.get(childPosition);
Context ctx = holder.imageView.getContext();
final String status = Smap.get(child.fileInfo.unique_id);
Log.d("STATUS", status);
switch (status) {
case Constants.UNKNOWN:
case Constants.RESUMED_WAITING:
case Constants.PAUSED:
case Constants.FAILED:
case Constants.CANCELED:
holder.upload_cancel.setVisibility(View.VISIBLE);
holder.resume_pause_select.setVisibility(View.VISIBLE);
holder.resume_pause_select.setImageResource(R.drawable.ic_action_ic_refresh_white_24dp);
holder.fileprogressbar.setVisibility(View.INVISIBLE);
holder.file_name.setVisibility(View.INVISIBLE);
break;
case Constants.PENDING_CANCEL:
case Constants.PENDING_NETWORK_DISCONNECT:
case Constants.PART_COMPLETED:
case Constants.PENDING_PAUSE:
case Constants.WAITING_FOR_NETWORK:
case Constants.IN_PROGRESS:
case Constants.WAITING:
holder.upload_cancel.setVisibility(View.VISIBLE);
holder.fileprogressbar.setIndeterminate(true);
holder.resume_pause_select.setVisibility(View.VISIBLE);
holder.resume_pause_select.setImageResource(R.drawable.ic_action_ic_pause_white_24dp);
holder.fileprogressbar.setVisibility(View.VISIBLE);
holder.file_name.setVisibility(View.INVISIBLE);
try {
file file = new file(null, child.fileInfo.unique_id, child.fileInfo.localpath, child.fileInfo.remotepath, status, child.fileInfo.privacy, child.fileInfo.file_size, "UPLOAD", Umap.get(child.fileInfo.unique_id), child.fileInfo.pond_id, Constants.getLastTimeOpened());
fileDao.insert(file);
Log.d("new file", "Inserted");
} catch (SQLException e) {
Log.d("ERROR", "Not Inserted");
}
Integer prevprogress = Pmap.get(child.fileInfo.unique_id);
if(prevprogress!=null){
holder.fileprogressbar.setIndeterminate(false);
holder.fileprogressbar.setProgress(prevprogress);
}
transferObserver = Util.getTransferUtility(getContext()).getTransferById(Integer.parseInt(Umap.get(child.fileInfo.unique_id)));
if (transferObserver != null) {
transferObserver.setTransferListener(new TransferListener() {
#Override
public void onStateChanged(int i, TransferState transferState) {
if (child.fileInfo.unique_id != null && !child.fileInfo.unique_id.isEmpty()) {
Umap.put(child.fileInfo.unique_id, String.valueOf(i));
Smap.put(child.fileInfo.unique_id, transferState.toString());
}
holder.fileprogressbar.setIndeterminate(true);
if (transferState.toString().equals(Constants.COMPLETED)) {
com.ficean.android.ficean.File.File.fileStore(getContext(), phonenumber, "UPLOAD", child.fileInfo, new com.ficean.android.ficean.File.File.Call() {
#Override
public void onSuccess(boolean result) {
if (result) {
}
}
});
}
List<file> files = fileDao.queryBuilder().where(com.ficean.android.ficean.db.fileDao.Properties.File_unique_id.eq(child.fileInfo.unique_id)).limit(1).build().list();
for (file file : files) {
file.setFile_status(transferState.toString());
file.setU_id(String.valueOf(i));
fileDao.update(file);
}
expMgr.notifyChildItemChanged(groupPosition,childPosition);
}
#Override
public void onProgressChanged(int i, long l, long l1) {
int value = Constants.percentage(l, l1);
holder.fileprogressbar.setIndeterminate(false);
holder.fileprogressbar.setProgress(value);
Pmap.put(child.fileInfo.unique_id,value);
}
#Override
public void onError(int i, Exception e) {
}
});
}
break;
default:
String link = SaveUtil.getEncryptedPreferences(getContext()).getString(child.fileInfo.unique_id, Constants.NOTHING);
Glide.with(getContext()).load(link).skipMemoryCache(true).diskCacheStrategy(DiskCacheStrategy.SOURCE).crossFade().placeholder(R.drawable.image_icon).listener(new CustomRequestListener(new CustomRequestListener.requestCallBack() {
#Override
public void onSuccess(boolean isSuccess) {
if (!isSuccess) {
String remotePath;
if (Opener.isFileVideo(child.fileInfo.localpath)) {
remotePath = phonenumber.concat("/").concat("thumbnails").concat("/").concat(FilenameUtils.removeExtension(new File(child.fileInfo.localpath).getName())).concat(".png");
} else {
remotePath = child.fileInfo.remotepath;
}
LoginCredentials.getSignedUrl(getContext(), remotePath, new LoginCredentials.UrlCallback() {
#Override
public void onSuccess(final URL url) {
if (url != null) {
Glide.with(getContext()).load(url.toString()).skipMemoryCache(true).diskCacheStrategy(DiskCacheStrategy.SOURCE).crossFade().placeholder(R.drawable.image_icon).listener(new CustomRequestListener(new CustomRequestListener.requestCallBack() {
#Override
public void onSuccess(boolean isSuccess) {
if (isSuccess) {
SaveUtil.getEncryptedEditor(getContext()).putString(child.fileInfo.unique_id, url.toString()).apply();
}
}
})).error(R.drawable.image_icon).into(holder.imageView);
}
}
});
}
}
})).error(R.drawable.image_icon).into(holder.imageView);
holder.resume_pause_select.setVisibility(View.INVISIBLE);
holder.fileprogressbar.setVisibility(View.INVISIBLE);
holder.upload_cancel.setVisibility(View.INVISIBLE);
break;
}
}
I am trying to communicate with a remote device via WHTTP. I send a request and the device responds. It does not always respond immediately which is why I use AsyncTask.
Here is some trimmed down code to explain better:
private class CameraSettings extends AsyncTask<AvailableCameraSettings, Void, AvailableCameraSettings> {
private final String INNER_TAG = CameraSettings.class.getSimpleName();
AvailableCameraSettings availableCameraSettings = new AvailableCameraSettings();
#Override
protected void onPostExecute(AvailableCameraSettings availableCameraSettings) {
if(availableCameraSettings==null){
Log.e(INNER_TAG, "NULL");
return;
}
if (availableCameraSettings.getSetting().equals(SettingType.APERTURE) ) {
apertureSettings = availableCameraSettings;
ArrayAdapter<String> apertureAdapter = new ArrayAdapter<String>(getContext(), android.R.layout.simple_spinner_item);
apertureAdapter.addAll(apertureSettings.getAvailableSettings());
apertureSpinner.setAdapter(apertureAdapter);
apertureSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
#Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
String itemAtPosition = ((String) parent.getItemAtPosition(position));
mCameraIO.setAperture(itemAtPosition);
}
#Override
public void onNothingSelected(AdapterView<?> parent) {
}
});
apertureSpinner.setEnabled(true);
} else if (availableCameraSettings.getSetting().equals(SettingType.ISO)) {
isoSettings = availableCameraSettings;
ArrayAdapter<String> isoSpeedAdapter = new ArrayAdapter<String>(getContext(), android.R.layout.simple_spinner_item);
isoSpeedAdapter.addAll(isoSettings.getAvailableSettings());
isoSpinner.setAdapter(isoSpeedAdapter);
isoSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
#Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
String itemAtPosition = ((String) parent.getItemAtPosition(position));
mCameraIO.setIsoSpeed(itemAtPosition);
}
#Override
public void onNothingSelected(AdapterView<?> parent) {
}
});
isoSpinner.setEnabled(true);
}
}
#Override
protected AvailableCameraSettings doInBackground(AvailableCameraSettings... params) {
AvailableCameraSettings parameter = params[0];
if (parameter != null) {
Log.d(INNER_TAG, "***** Entered doInBackground method for setting " + parameter.getSetting().getName());
}else{
return null;
}
if (parameter.getSetting().equals(SettingType.APERTURE)) {
mCameraIO.getApertures(new CameraListener() {
#Override
public void onResult(JSONArray response) {
if (response == null) {
Log.d(INNER_TAG, " Response is Null");
return;
}
try {
Log.d(INNER_TAG, "Response is: " + response.toString(4));
extractAvailableSettings(response, apertureSettings);
} catch (JSONException e) {
Log.e(TAG, e.getMessage());
}
}
#Override
public void onError(CameraIO.ResponseCode responseCode, String responseMsg) {
}
});
return apertureSettings;
} else if (parameter.getSetting().equals(SettingType.ISO)) {
mCameraIO.getIsoSpeedRates(new CameraListener() {
#Override
public void onResult(JSONArray response) {
if (response == null) {
Log.d(INNER_TAG, " Response is Null");
return;
}
try {
Log.d(INNER_TAG, "Response is: " + response.toString(4));
extractAvailableSettings(response, isoSettings);
} catch (JSONException e) {
Log.e(TAG, e.getMessage());
}
}
#Override
public void onError(CameraIO.ResponseCode responseCode, String responseMsg) {
}
});
}
return null;
}
}
the error produced is:
java.lang.NullPointerException: Attempt to invoke interface method 'java.lang.Object[] java.util.Collection.toArray()' on a null object reference
at java.util.ArrayList.addAll(ArrayList.java:188)
at android.widget.ArrayAdapter.addAll(ArrayAdapter.java:210)
at com.thibaudperso.sonycamera.timelapse.fragments.CameraSettingsFragment$CameraSettings.onPostExecute(CameraSettingsFragment.java:311)
at com.thibaudperso.sonycamera.timelapse.fragments.CameraSettingsFragment$CameraSettings.onPostExecute(CameraSettingsFragment.java:297)
at android.os.AsyncTask.finish(AsyncTask.java:651)
at android.os.AsyncTask.access$500(AsyncTask.java:180)
at android.os.AsyncTask$InternalHandler.handleMessage(AsyncTask.java:668)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:148)
at android.app.ActivityThread.main(ActivityThread.java:5468)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)
Line 311 is:
apertureAdapter.addAll(apertureSettings.getAvailableSettings());
I understand a null List<String> gets there, but I don't understand why doInBackground() doesn't wait until it gets the response, then return the newly populated object.
The calls to getApertures() and getIsoSpeedRates() take in a callback (CameraListener) which means it already waits for a response without needing to use an AsyncTask.
What's happening is this case is it's getting to the onResponse after doInBackground completes, because it's essentially another asynchronous task, being called from your CameraSettings AsyncTask.
I suggest removing the AsyncTask altogether, and creating similar methods to the following. Note the call to updateAdapter is called from onResult - because it's at that point you actually have the result. The onResult is essentially the same as onPostExecute of an AsyncTask, so you need to handle your functionality in there.
public void getCameraSettings(AvailableCameraSettings parameter) {
if (parameter != null) {
Log.d(INNER_TAG, "***** Entered doInBackground method for setting " + parameter.getSetting().getName());
}else{
return null;
}
if (parameter.getSetting().equals(SettingType.APERTURE)) {
mCameraIO.getApertures(new CameraListener() {
#Override
public void onResult(JSONArray response) {
if (response == null) {
Log.d(INNER_TAG, " Response is Null");
return;
}
try {
Log.d(INNER_TAG, "Response is: " + response.toString(4));
extractAvailableSettings(response, apertureSettings);
updateAdapter(SettingType.APERTURE);
} catch (JSONException e) {
Log.e(TAG, e.getMessage());
}
}
#Override
public void onError(CameraIO.ResponseCode responseCode, String responseMsg) {
}
});
return apertureSettings;
} else if (parameter.getSetting().equals(SettingType.ISO)) {
mCameraIO.getIsoSpeedRates(new CameraListener() {
#Override
public void onResult(JSONArray response) {
if (response == null) {
Log.d(INNER_TAG, " Response is Null");
return;
}
try {
Log.d(INNER_TAG, "Response is: " + response.toString(4));
extractAvailableSettings(response, isoSettings);
updateAdapter(SettingType.ISO);
} catch (JSONException e) {
Log.e(TAG, e.getMessage());
}
}
#Override
public void onError(CameraIO.ResponseCode responseCode, String responseMsg) {
}
});
}
return null;
}
Then add a method as follows. It's essentially the same as what you had in onPostExecute. It looks like isoSettings and apertureSettings were member variables so I trust you have access here, but if not, add them as a parameter to be passed to this method.
protected void updateAdapter(String settingType) {
if(availableCameraSettings==null){
Log.e(INNER_TAG, "NULL");
return;
}
if (settingType.equals(SettingType.APERTURE) ) {
apertureSettings = availableCameraSettings;
ArrayAdapter<String> apertureAdapter = new ArrayAdapter<String>(getContext(), android.R.layout.simple_spinner_item);
apertureAdapter.addAll(apertureSettings.getAvailableSettings());
apertureSpinner.setAdapter(apertureAdapter);
apertureSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
#Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
String itemAtPosition = ((String) parent.getItemAtPosition(position));
mCameraIO.setAperture(itemAtPosition);
}
#Override
public void onNothingSelected(AdapterView<?> parent) {
}
});
apertureSpinner.setEnabled(true);
} else if (settingType.equals(SettingType.ISO)) {
isoSettings = availableCameraSettings;
ArrayAdapter<String> isoSpeedAdapter = new ArrayAdapter<String>(getContext(), android.R.layout.simple_spinner_item);
isoSpeedAdapter.addAll(isoSettings.getAvailableSettings());
isoSpinner.setAdapter(isoSpeedAdapter);
isoSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
#Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
String itemAtPosition = ((String) parent.getItemAtPosition(position));
mCameraIO.setIsoSpeed(itemAtPosition);
}
#Override
public void onNothingSelected(AdapterView<?> parent) {
}
});
isoSpinner.setEnabled(true);
}
}
Note: If there's a strong reason I'm missing that you have to use an AsyncTask - you can achieve the same by simply calling your new updateAdapter method from within the onResult within the doInBackground, but I think it's unnecessary.