We are creating a chat application using openfire, smack. In that there is a chatscreen where users can send and receive messages and media files. For storing messages we are using Realm as local db. I want to show the progress of files during upload of files.
My Upload file code is :
public void firebasestorageMeth(final String msg, final String path, final String filetype, final String mykey, final String otheruserkey, final String username) {
StorageReference riversRef = STORAGE_REFERENCE.child(mykey).child("files").child(GetTimeStamp.timeStampDate());
final String timestampdate = GetTimeStamp.timeStampDate();
final String timestamptime = GetTimeStamp.timeStampTime();
final long id = GetTimeStamp.Id();
ChatMessageRealm cmr = new ChatMessageRealm(mykey + otheruserkey, otheruserkey, msg, mykey, timestamptime, timestampdate, filetype, String.valueOf(id), "0", "",path);
ChatHelper.addChatMesgRealmMedia1(cmr, this, mykey, otheruserkey);
sendBroadcast(new Intent().putExtra("reloadchatmediastatus", MEDIA_STARTING).putExtra("reloadchatmediaid", String.valueOf(id)).putExtra("reloadchatmedialocalurl", path).setAction("reloadchataction"));
Log.d(TAG, cmr.getChatref()+cmr.getMsgid()+cmr.getMsgstring()+"file path extension upload file" + path);
riversRef.putFile(Uri.fromFile(new File(path)))
.addOnSuccessListener(new OnSuccessListener<UploadTask.TaskSnapshot>() {
#Override
public void onSuccess(UploadTask.TaskSnapshot taskSnapshot) {
umpref.setUri(String.valueOf(id), path);
Uri downloadUrl = taskSnapshot.getDownloadUrl();
Log.d(TAG, "file uploaded" + downloadUrl);
ChatMessageRealm cmr = new ChatMessageRealm(mykey + otheruserkey, otheruserkey, msg, mykey, timestamptime, timestampdate, filetype, String.valueOf(id), "1", String.valueOf(downloadUrl),path);
ChatHelper.addChatMesgRealmMedia1(cmr, getApplicationContext(), mykey, otheruserkey);
sendBroadcast(new Intent().putExtra("reloadchatmediastatus", MEDIA_SUCCESS).putExtra("reloadchatmediaid", String.valueOf(id)).putExtra("reloadchatmediaurl", String.valueOf(downloadUrl)).putExtra("reloadchatmedialocalurl", path).setAction("reloadchataction"));
Toast.makeText(getApplicationContext(), "File Uploaded ", Toast.LENGTH_LONG).show();
}
})
.addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception exception) {
sendBroadcast(new Intent().putExtra("reloadchatmediastatus", MEDIA_FAILED).putExtra("reloadchatmediaid", String.valueOf(id)).putExtra("reloadchatmedialocalurl", path).setAction("reloadchataction"));
exception.printStackTrace();
}
})
.addOnProgressListener(new OnProgressListener<UploadTask.TaskSnapshot>() {
#Override
public void onProgress(UploadTask.TaskSnapshot taskSnapshot) {
int progress = (int) ((100.0 * taskSnapshot.getBytesTransferred()) / taskSnapshot.getTotalByteCount());
sendBroadcast(new Intent().putExtra("reloadchatmediastatus", progress + " ").putExtra("reloadchatmediaid", String.valueOf(id)).putExtra("reloadchatmedialocalurl", path).setAction("reloadchataction"));
}
});
}
The chatadapter code is :
public class ChatAdapter1 extends RecyclerView.Adapter<ChatAdapter1.MyViewHolder> {
ArrayList<ChatMessageRealm> mList = new ArrayList<>();
private Context context;
private UserSession session;
public static final int SENDER = 0;
public static final int RECIPIENT = 1;
String TAG = "ChatAdapter1";
public ChatAdapter1(ArrayList<ChatMessageRealm> list, Context context) {
this.mList = list;
this.context = context;
session = new UserSession(context);
}
#Override
public int getItemViewType(int position) {
if (mList.get(position).getSenderjid().matches(session.getUserKey())) {
return SENDER;
} else {
return RECIPIENT;
}
}
#Override
public int getItemCount() {
return mList.size();
}
#Override
public MyViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) {
RecyclerView.ViewHolder viewHolder = null;
LayoutInflater inflater = LayoutInflater.from(viewGroup.getContext());
switch (viewType) {
case SENDER:
View viewSender = inflater.inflate(R.layout.row_chats_sender, viewGroup, false);
viewHolder = new MyViewHolder(viewSender);
break;
case RECIPIENT:
View viewRecipient = inflater.inflate(R.layout.row_chats_receiver, viewGroup, false);
viewHolder = new MyViewHolder(viewRecipient);
break;
}
return (MyViewHolder) viewHolder;
}
#Override
public void onBindViewHolder(final ChatAdapter1.MyViewHolder holder, int position) {
final ChatMessageRealm comment = mList.get(position);
holder.setIsRecyclable(false);
// holder.otherSender_sender.setText(comment.getSenderjid());
holder.otherSender_Timestamp.setText(comment.getSendertime() + "," + comment.getSenderdate());
// holder.status.setVisibility(View.GONE);
switch (comment.getMsgtype()) {
case "text":
// holder.btndown.setVisibility(View.GONE);
String decryptedmsg = comment.getMsgstring();
holder.commentString.setText(decryptedmsg);
// holder.photo.setVisibility(View.GONE);
break;
case "photo":
Glide.clear(holder.imgchat);
holder.imgchat.setVisibility(View.VISIBLE);
holder.progress.setVisibility(View.VISIBLE);
if (getItemViewType(position) == SENDER) {
// holder.btndown.setVisibility(View.GONE);
// holder.btnopen.setVisibility(View.VISIBLE);
try {
Glide.with(context).load(comment.getMsglocalurl()).into(holder.imgchat);
}catch (Exception e){
e.printStackTrace();
}
}
break;
}
}
public class MyViewHolder extends RecyclerView.ViewHolder {
public TextView otherSender_Timestamp, commentString,progress;
public ImageView imgchat;
public Button btndown, btnopen;
public MyViewHolder(View itemView) {
super(itemView);
otherSender_Timestamp = (TextView) itemView.findViewById(R.id.meSender_TimeStamp);
commentString = (TextView) itemView.findViewById(R.id.commentString);
progress = (TextView) itemView.findViewById(R.id.mediaprogress);
imgchat = (ImageView) itemView.findViewById(R.id.imgchat);
btndown = (Button) itemView.findViewById(R.id.btndown);
btnopen = (Button) itemView.findViewById(R.id.btnopen);
}
}
}
ChatActivity code is:
public class ChatActivity extends ToadoBaseActivity {
private EditText typeComment;
private ImageButton sendButton, attachment, takephoto;
Intent intent;
private RecyclerView recyclerView;
DatabaseReference dbChat;
private String otheruserkey;
LinearLayoutManager linearLayoutManager;
private MarshmallowPermissions marshmallowPermissions;
private ArrayList<String> mResults = new ArrayList<>();
private ActionMode actionMode;
UploadFileService uploadFileService;
boolean mServiceBound = false;
SimpleDateFormat formatter = new SimpleDateFormat("dd-MMM-yyyy hh:mm aa");
private ChatAdapter1 mAdapter;
LinkedHashSet<ChatMessageRealm> uniqueStrings = new LinkedHashSet<ChatMessageRealm>();
private ArrayList<ChatMessageRealm> chatList = new ArrayList<>();
private ArrayList<String> chatListIds = new ArrayList<>();
String username, mykey;
private UserSession session;
String receiverToken = "nil";
boolean clicked;
LinearLayout layoutToAdd;
LinearLayout commentView;
private ChildEventListener dbChatlistener;
ImageButton photoattach, videoattach;
Uri videoUri;
public String dbTableKey;
EncryptUtils encryptUtils = new EncryptUtils();
private ImageButton imgdocattach;
private ImageButton locattach;
private LinearLayout spamView;
TextView tvTitle;
ImageView imgprof;
private ArrayList<String> imagesPathList;
private final int PICK_IMAGE_MULTIPLE = 199;
private ProgressBar progressBar;
UserMediaPrefs umprefs;
private Boolean mBounded;
private String TAG = "ChatActivity";
// AbstractXMPPConnection connection;
Realm mRealm;
Boolean chatexists;
private String otherusername;
private String profpic;
private MyXMPP2 myxinstance;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_chat1);
session = new UserSession(this);
mykey = session.getUserKey();
// connection = MyXMPP2.getInstance(this,).getConn();
mRealm = Realm.getDefaultInstance();
checkChatRef(otheruserkey);
clicked = false;
layoutToAdd = (LinearLayout) findViewById(R.id.attachmentpopup);
marshmallowPermissions = new MarshmallowPermissions(this);
spamView = (LinearLayout) findViewById(R.id.spamView);
umprefs = new UserMediaPrefs(this);
//get these 2 things from notifications also
intent = getIntent();
otheruserkey = intent.getStringExtra("otheruserkey");
otherusername = intent.getStringExtra("otherusername");
profpic = intent.getStringExtra("profpic");
System.out.println("recevier token chat act oncreate" + otheruserkey);
imgprof = (ImageView) findViewById(R.id.icon_profile);
tvTitle = (TextView) findViewById(R.id.tvTitle);
tvTitle.setText(otherusername);
commentView = (LinearLayout) findViewById(R.id.commentView);
progressBar = (ProgressBar) findViewById(R.id.progress);
typeComment = (EditText) findViewById(R.id.typeComment);
sendButton = (ImageButton) findViewById(R.id.sendButton);
attachment = (ImageButton) findViewById(R.id.attachment);
takephoto = (ImageButton) findViewById(R.id.takephoto);
photoattach = (ImageButton) findViewById(R.id.photoattach);
imgdocattach = (ImageButton) findViewById(R.id.docattach);
videoattach = (ImageButton) findViewById(R.id.videoattach);
locattach = (ImageButton) findViewById(R.id.locationattach);
myxinstance = MyXMPP2.getInstance(ChatActivity.this, getString(R.string.server), mykey);
mAdapter = new ChatAdapter1(chatList, this);
recyclerView = (RecyclerView) findViewById(R.id.my_recycler_view);
linearLayoutManager = new LinearLayoutManager(this);
recyclerView.setLayoutManager(linearLayoutManager);
recyclerView.setAdapter(mAdapter);
sendButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
System.out.println(mykey + " chat created " + otheruserkey);
ChatMessageRealm cm = null;
if (!typeComment.getText().toString().matches("")) {
cm = new ChatMessageRealm(mykey + otheruserkey, otheruserkey, typeComment.getText().toString(), mykey, GetTimeStamp.timeStampTime(), GetTimeStamp.timeStampDate(), "text", String.valueOf(GetTimeStamp.Id()), "1");
}
if (cm != null)
myxinstance.sendMessage(cm);
loadData();
typeComment.setText("");
}
});
attachment.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (layoutToAdd.getVisibility() == View.VISIBLE)
layoutToAdd.setVisibility(View.GONE);
else
layoutToAdd.setVisibility(View.VISIBLE);
}
});
takephoto.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
try {
dispatchTakePictureIntent();
} catch (ActivityNotFoundException anfe) {
anfe.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
});
}
#Override
protected void onResume() {
super.onResume();
mykey = session.getUserKey();
username = session.getUsername();
loadData();
}
private void loadData() {
Sort sort[] = {Sort.ASCENDING};
String[] fieldNames = {"msgid"};
RealmResults<ChatMessageRealm> shows = mRealm.where(ChatMessageRealm.class).equalTo("chatref", mykey + otheruserkey).findAllSorted(fieldNames, sort);
if (shows.size() > 0) {
Log.d(TAG, shows.size() + "LOAD DATA CALLED " + shows.get(shows.size() - 1).getMsgstring());
for (ChatMessageRealm cm : shows) {
if (!chatList.contains(cm)) {
chatList.add(cm);
}
if (!chatListIds.contains(cm.getMsgid())) {
chatListIds.add(cm.getMsgid());
}
mAdapter.notifyDataSetChanged();
}
mAdapter.notifyDataSetChanged();
recyclerView.scrollToPosition(chatList.size() - 1);
}
}
private void checkChatRef(String otheruserkey) {
RealmQuery<ActiveChats> query = mRealm.where(ActiveChats.class);
query.equalTo("otherkey", otheruserkey);
RealmResults<ActiveChats> result1 = query.findAll();
if (result1.size() == 0) {
chatexists = false;
} else {
chatexists = true;
}
System.out.println(result1.size() + "chat exists chatactivity" + chatexists);
}
#Override
protected void onStart() {
super.onStart();
registerReceiver(this.reloadData, new IntentFilter("reloadchataction"));
}
#Override
protected void onStop() {
super.onStop();
if (reloadData != null)
unregisterReceiver(reloadData);
}
private void dispatchTakePictureIntent() throws IOException {
CropImage.activity()
.setGuidelines(CropImageView.Guidelines.ON)
.setMultiTouchEnabled(true)
.start(this);
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
Log.d(TAG, "request code chatactivity" + requestCode);
super.onActivityResult(requestCode, resultCode, data);
if (resultCode == RESULT_OK) {
if (data != null) {
if (requestCode == CropImage.CROP_IMAGE_ACTIVITY_REQUEST_CODE) {
Log.d(TAG, "crop activity");
CropImage.ActivityResult result = CropImage.getActivityResult(data);
if (resultCode == RESULT_OK) {
final String imguri = result.getUri().toString();
try {
final File file = createImageFile();
new AsyncTask<Void, Void, Void>() {
#Override
protected Void doInBackground(Void... params) {
final int chunkSize = 1024; // We'll read in one kB at a time
byte[] imageData = new byte[chunkSize];
InputStream in = null;
OutputStream out = null;
try {
in = getContentResolver().openInputStream(Uri.parse(imguri));
out = new FileOutputStream(file);
int bytesRead;
while ((bytesRead = in.read(imageData)) > 0) {
out.write(Arrays.copyOfRange(imageData, 0, Math.max(0, bytesRead)));
}
String s = file.getAbsolutePath();
Log.d(TAG, "image cropped uri chatact22" + file.getAbsolutePath());
Intent intent = new Intent(ChatActivity.this, ImageComment.class);
intent.putExtra("URI", s);
intent.putExtra("comment_type", "photo");
startImageComment(intent);
} catch (Exception ex) {
Log.e("Something went wrong.", ex.toString());
} finally {
try {
in.close();
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return null;
}
}.execute();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
}
private File createImageFile() throws IOException {
// Create an image file name
String imageFileName = "pic-" + GetTimeStamp.timeStamp() + ".jpg";
File image = OpenFile.createFile(this, imageFileName);
// Save a file: path for use with ACTION_VIEW intents
Log.d(TAG, "file createimagefile: " + image.getAbsolutePath());
return image;
}
private void startImageComment(Intent intent) {
Log.d(TAG, "image comment sending" + intent.getStringExtra("URI"));
intent.putExtra("username", username);
intent.putExtra("otheruserkey", otheruserkey);
intent.putExtra("receiverToken", receiverToken);
intent.putExtra("mykey", mykey);
startActivity(intent);
}
BroadcastReceiver reloadData = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
if (intent.getStringExtra("reloadchat") != null) {
Log.d(TAG, " reloading data broadcast receiver" + intent.getStringExtra("reloadchat"));
loadData();
mAdapter.notifyDataSetChanged();
} else if (intent.getStringExtra("reloadchatmediastatus") != null) {
if (intent.getStringExtra("reloadchatmediastatus").matches(MEDIA_STARTING))
loadData();
Log.d(TAG, " reloading data status " + intent.getStringExtra("reloadchatmediastatus"));
Log.d(TAG, " reloading data media id " + intent.getStringExtra("reloadchatmediaid"));
if (!intent.getStringExtra("reloadchatmediastatus").matches(MEDIA_FAILED)) {
final String msgid = intent.getStringExtra("reloadchatmediaid");
String fileprogress = intent.getStringExtra("reloadchatmediastatus");
int ind1 = chatListIds.indexOf(msgid);
Log.d(TAG, ind1 + "chat list broadcast progress " + fileprogress);
Log.d(TAG, "chat list broadcast" + chatListIds.size());
try {
// View ve = linearLayoutManager.findViewByPosition(ind1);
// View v = recyclerView.findViewHolderForAdapterPosition(ind1).itemView;
View v = recyclerView.findViewHolderForLayoutPosition(ind1).itemView;
ChatAdapter1.MyViewHolder holder = (ChatAdapter1.MyViewHolder) recyclerView.getChildViewHolder(v);
holder.commentString.setVisibility(View.VISIBLE);
holder.commentString.setText("file prog " + fileprogress);
mAdapter.notifyDataSetChanged();
Log.d(TAG, holder.getItemViewType() + "," + holder.getLayoutPosition() + "," + holder.commentString.getText().toString() + " VIEW HOLDER? " + v);
} catch (Exception e) {
e.printStackTrace();
}
}
}
if (intent.getStringExtra("reloadchatmediaurl") != null)
Log.d(TAG, " reloading data media url " + intent.getStringExtra("reloadchatmediaurl"));
}
};
}
I am trying to update my recyclerview dynamically in the broadcast receiver- reloadData in ChatActivity.
My logs tell me that i am receiving correct data from the sendbroadcast in the UploadFileService, the problem is in following code inside the broadcast receiver on ChatActivity, it is getting correct data but the data is not showing on the recycler view:
try {
View v = recyclerView.findViewHolderForLayoutPosition(ind1).itemView;
ChatAdapter1.MyViewHolder holder = (ChatAdapter1.MyViewHolder) recyclerView.getChildViewHolder(v);
holder.commentString.setVisibility(View.VISIBLE);
holder.commentString.setText("file prog " + fileprogress);
mAdapter.notifyDataSetChanged();
Log.d(TAG, holder.getItemViewType() + "," + holder.getLayoutPosition() + "," + holder.commentString.getText().toString() + " VIEW HOLDER? " + v);
} catch (Exception e) {
e.printStackTrace();
}
I get correct values , such as:
08-03 19:31:25.240 705-705/com.app.toado D/ChatActivity: 0,30,file prog 34 VIEW HOLDER? android.widget.LinearLayout{ff24ae0 V.E...... ......I. 0,621-660,1380 #7f1100f2 app:id/message_container}
08-03 19:31:26.346 705-705/com.app.toado D/ChatActivity: 0,30,file prog 100 VIEW HOLDER? android.widget.LinearLayout{e8a33ce V.E...... ......I. 0,621-660,1380 #7f1100f2 app:id/message_container}
08-03 19:31:26.347 705-705/com.app.toado D/ChatActivity: 0,30,file prog upload success VIEW HOLDER? android.widget.LinearLayout{e8a33ce V.E...... ......I. 0,621-660,1380 #7f1100f2 app:id/message_container}
I have tried using View ve = linearLayoutManager.findViewByPosition(ind1); and View v = recyclerView.findViewHolderForAdapterPosition(ind1).itemView; but they are also not working. Also tried adding notifydatasetchanged to it.
The try catch is also not throwing any error in the logs.
Can someone please help in figuring out why are the changes not showing on the recycler view but are showing in logs?
Are you sure you're updating the RecyclerView's Adapter from the UI Thread? Whenever you try to update the ViewHolder, you have to be certain you're doing so on the UI or it will not behave as expected.
When the modification to the ViewHolder is changed, check that Looper.myLooper().equals(Looper.getMainLooper());. If it returns false, it means you aren't updating on the UI Thread, the necessary place for all graphical updates to be made.
If this is the case, you just need to make sure that you can synchronize your changes on the UI, using Activity.runOnUiThread(Runnable r);.
Related
when i select first video then async task send coreect file name with correct progress value but when select video one by one then async task send ambigous filename. i.e. second video comes with first video filename and first video progressor count, third video comes with first or second video filename and first or second video progressor count and so on, why?
MainActivity.java
-------------------
public class MainActivity extends AppCompatActivity {
private static final int REQUEST_CODE_SELECT_VIDEO = 0x100;
private ArrayList<UploadModel> uploadModels;
private LinearLayoutManager mLinearLayoutManager;
private UploadAdapter uploadAdapter;
private Activity activity;
private List<String> mPath;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
activity = this;
uploadModels = new ArrayList<>();
RecyclerView recyclerView = findViewById(R.id.recycler_view);
mLinearLayoutManager = new LinearLayoutManager(this);
mLinearLayoutManager.setStackFromEnd(true); // put adding from bottom
recyclerView.setLayoutManager(mLinearLayoutManager);
uploadAdapter = new UploadAdapter(uploadModels);
recyclerView.setAdapter(uploadAdapter);
FloatingActionButton fab = findViewById(R.id.fab);
fab.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
startActivityFromGallery();
}
});
}
private void startActivityFromGallery() {
Intent photoPickerIntent = new Intent(Intent.ACTION_PICK);
photoPickerIntent.setType("video/*");
startActivityForResult(photoPickerIntent, REQUEST_CODE_SELECT_VIDEO);
startActivityForResult(Intent.createChooser(photoPickerIntent, "Select Picture"), REQUEST_CODE_SELECT_VIDEO);
}
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
Log.d(TAG, "onActivityResult() called with: requestCode = [" + requestCode + "], resultCode = [" + resultCode + "], data = [" + data + "]");
if (requestCode == REQUEST_CODE_SELECT_VIDEO && resultCode == RESULT_OK) {
mPath = new ArrayList<>();
Uri uri = data.getData();
mPath.add(getVideoPath(uri, MainActivity.this));
loadVideo();
}
}
private void loadVideo() {
Log.d(TAG, "loadImage: " + mPath.size());
if (mPath != null && mPath.size() > 0) {
UploadModel messageModel = new UploadModelurl, mPath.get(0), UploadModel.STATUS_UPLOAD);
uploadAdapter.updateMessage(messageModel);
}
}
public static String getVideoPath(final Uri uri, final Activity activity) {
String[] projection = {MediaStore.Images.Media.DATA};
Cursor cursor = activity.managedQuery(uri, projection, null, null, null);
if (cursor != null) {
int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
cursor.moveToFirst();
return cursor.getString(column_index);
} else
return null;
}
}
UploadAdapter.java
-----------------------
public class UploadAdapter extends RecyclerView.Adapter<UploadAdapter.ViewHolder> {
private final List<UploadModel> mValues;
public UploadAdapter(List<UploadModel> items) {
mValues = items;
}
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.fragment_upload, parent, false);
return new ViewHolder(view);
}
#Override
public void onBindViewHolder(final ViewHolder holder, int position) {
holder.mItem = mValues.get(position);
if(holder.mItem.getStatus() == UploadModel.STATUS_UPLOADING) {
holder.mProgressBar.setVisibility(View.VISIBLE);
File file = new File(holder.mItem.getLocalUrl());
holder.mIdView.setText(file.getName());
}
if(holder.mItem.getStatus() == UploadModel.STATUS_UPLOAD) {
holder.mItem.setStatus(UploadModel.STATUS_UPLOADING);
holder.mProgressBar.setVisibility(View.VISIBLE);
File file = new File(holder.mItem.getLocalUrl());
MessageUpload.convertVideo(holder.mItem, new MessageUpload.ProgressListener() {
#Override
public void onStart() {
holder.mIdView.setText(file.getName() + " Wait.........");
}
#Override
public void onFinish(boolean result) {
holder.mProgressBar.setVisibility(View.GONE);
holder.mIdView.setText(file.getName() + " finished ");
}
#Override
public void onProgress(float progress, String filename) {
holder.mIdView.setText(file.getName() + " " + progress + " %");
}
});
}else if(holder.mItem.getStatus() == UploadModel.STATUS_UPLOADED) {
holder.mIdView.setText(file.getName() + " finished ");
}
}
#Override
public int getItemCount() {
return mValues.size();
}
public class ViewHolder extends RecyclerView.ViewHolder {
public final View mView;
public final TextView mIdView;
private final ProgressBar mProgressBar; // Resolve Issue #52
public UploadModel mItem;
public ViewHolder(View view) {
super(view);
mView = view;
mProgressBar = (ProgressBar) view.findViewById(R.id.progress);
mIdView = (TextView) view.findViewById(R.id.textview);
}
}
public void updateMessage(UploadModel message) {
List<UploadModel> messageList = mValues;
int messagePosition = messageList.indexOf(message);
if (messagePosition >= 0 && messagePosition < messageList.size()) {
messageList.set(messagePosition, message);
} else {
messageList.add(message);
}
notifyDataSetChanged();
}
}
MessageUpload.java
-------------------------
public class MessageUpload {
public UploadMessage convertVideo(UploadModel messageModel, ProgressListener listener) {
UploadMessage task = new UploadMessage(listener);
task.execute(messageModel);
return task;
}
public interface ProgressListener {
void onStart();
void onFinish(boolean result);
void onProgress(float progress, String filename);
}
}
UploadMessage.java
-------------------------
public class UploadMessage extends AsyncTask<UploadModel, Integer, String> {
private final MessageUpload.ProgressListener mListener;
private UploadModel messageModel;
private String filename;
private long totalSize = 0;
public UploadMessage(MessageUpload.ProgressListener listener) {
this.mListener = listener;
}
#Override
protected void onPreExecute() {
super.onPreExecute();
mListener.onStart();
}
#Override
protected void onProgressUpdate(Integer... progress) {
mListener.onProgress(progress[0], filename);
}
#Override
protected String doInBackground(UploadModel... params) {
messageModel = params[0];
File file = new File(messageModel.getLocalUrl());
filename = file.getName();
return uploadFile();
}
#SuppressWarnings("deprecation")
private String uploadFile() {
String responseString = null;
HttpClient httpclient = new DefaultHttpClient();
HttpPost httppost = new HttpPost(messageModel.getUrl());
try {
AndroidMultiPartEntity entity = new AndroidMultiPartEntity(
new AndroidMultiPartEntity.ProgressListener() {
#Override
public void transferred(long num) {
publishProgress((int) ((num / (float) totalSize) * 100));
}
});
File sourceFile = new File(messageModel.getLocalUrl());
// Adding file data to http body
entity.addPart("file", new FileBody(sourceFile));
totalSize = entity.getContentLength();
httppost.setEntity(entity);
// Making server call
HttpResponse response = httpclient.execute(httppost);
HttpEntity r_entity = response.getEntity();
int statusCode = response.getStatusLine().getStatusCode();
if (statusCode == 200) {
// Server responsetext
responseString = EntityUtils.toString(r_entity);
} else {
responseString = "Error occurred! Http Status Code: " + statusCode;
}
} catch (ClientProtocolException e) {
responseString = e.toString();
} catch (IOException e) {
responseString = e.toString();
}
return responseString;
}
#Override
protected void onPostExecute(String result) {
super.onPostExecute(result);
mListener.onFinish(true);
}
}
I have three activities, I capture all data but one from DetailActivity upon button click and save in database using Room; My intention is to insert all these data into the database and start ReviewActivity so as to get the arraylist of reviews and also insert it in the database. Everything seems to work fine until when I want to view review offline because I believe it has been saved, reviews does not get loaded.
This is my DetailActivity,
TextView overview_tv; ImageView image_tv; TextView name_tv; TextView ratings; Context context; TextView release_date; ImageView backdrop_poster; private ExpandableHeightListView trailers; public static ArrayList<Youtube> youtube; public static ArrayList<Review> reviews; TrailerViewAdapter adapter; public static DataObject data; DataObject dataObject; ArrayList<Review> savedReview; private static final String IMAGE_URL = "http://image.tmdb.org/t/p/w185/"; private static final String THE_MOVIEDB_URL2 = "https://api.themoviedb.org/3/movie/"; private static final String MOVIE_QUERY2 = "api_key"; private static final String API_KEY2 = "6cc4f47bd4a64e0117e157b79072ae37"; private static String SEARCH_QUERY2 = "videos"; public static int movieId; Button viewReviews; Button favourite; String movieRating; private static final int YOUTUBE_SEARCH_LOADER = 23; private static final int REVIEW_SEARCH_LOADER = 24; File file; String name; String overview; String releaseDate; int switcher; public static ArrayList<Review> favouriteReviews; TextView trev; AppDatabase mDb; //Navigation arrow on the action bar #Override public boolean onOptionsItemSelected(MenuItem item) { int id = item.getItemId(); if (id == android.R.id.home) { NavUtils.navigateUpFromSameTask(this); } return super.onOptionsItemSelected(item); } #Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_detail); mDb = AppDatabase.getInstance(getApplicationContext()); youtube = new ArrayList<Youtube>(); reviews = new ArrayList<Review>(); adapter = new TrailerViewAdapter(this, youtube); //Credit to Paolorotolo #github trailers = findViewById(R.id.expandable_list); trailers.setAdapter(adapter); trailers.setExpanded(true); //Navigation arrow on the acton bar; check also override onOptionsItemSelected ActionBar actionBar = this.getSupportActionBar(); if (actionBar != null) { actionBar.setDisplayHomeAsUpEnabled(true); } context = getApplicationContext(); Intent intent = getIntent(); if (intent == null) { closeOnError(); } switcher = getIntent().getIntExtra("switch", 3); overview_tv = findViewById(R.id.overview); image_tv = findViewById(R.id.image); name_tv = findViewById(R.id.name); ratings = findViewById(R.id.ratings); release_date = findViewById(R.id.release_date); backdrop_poster = findViewById(R.id.backdrop_poster); trev = findViewById(R.id.review_show); viewReviews = findViewById(R.id.review_button); favourite = findViewById(R.id.favourite_button); addListenerOnRatingBar(ratings); if (switcher != 2) { favourite.setVisibility(View.INVISIBLE); dataObject = (DataObject) getIntent().getParcelableExtra("array"); final String favouriteName = dataObject.getName(); final String favouriteOverview = dataObject.getOverview(); final String favouriteReleaseDate = dataObject.getReleaseDate(); ArrayList<Youtube> savedTrailer = dataObject.getTrailers(); savedReview = dataObject.getMovieReviews(); movieRating = dataObject.getRating(); name_tv.setText(favouriteName); overview_tv.setText(favouriteOverview); ratings.setText("Rating: " + movieRating); release_date.setText("Release Date: " + favouriteReleaseDate);// Toast.makeText(this, "Testing Reviews " + savedReview.get(0).getAuthor(), Toast.LENGTH_SHORT).show(); String imagePath = name_tv.getText().toString() + "0i"; String backdropPath = name_tv.getText().toString() + "1b"; try { DataObjectAdapter.downloadImage(imagePath, image_tv, this); } catch (Exception e) { e.printStackTrace(); } try { DataObjectAdapter.downloadImage(backdropPath, backdrop_poster, context); } catch (Exception e) { e.printStackTrace(); } if (savedTrailer != null) { TrailerViewAdapter lv = new TrailerViewAdapter(DetailActivity.this, savedTrailer); trailers.setAdapter(lv); switcher = 3; } } else { name = getIntent().getStringExtra("Name"); overview = getIntent().getStringExtra("Overview"); final String image = getIntent().getStringExtra("Image"); movieId = getIntent().getIntExtra("movieId", 1); final String backdrop = getIntent().getStringExtra("backdrop"); releaseDate = getIntent().getStringExtra("releaseDate"); movieRating = getIntent().getStringExtra("rating"); Log.i("this", "switch " + switcher); name_tv.setText(name); overview_tv.setText(overview); ratings.setText("Rating: " + movieRating); release_date.setText("Release Date: " + releaseDate); //load backdrop poster Picasso.with(context) .load(IMAGE_URL + backdrop) .fit() .placeholder(R.drawable.placeholder_image) .error(R.drawable.placeholder_image) .into(backdrop_poster); Picasso.with(context) .load(IMAGE_URL + image) .fit() .placeholder(R.drawable.placeholder_image) .error(R.drawable.placeholder_image) .into(image_tv); getSupportLoaderManager().initLoader(YOUTUBE_SEARCH_LOADER, null, this); //getSupportLoaderManager().initLoader(REVIEW_SEARCH_LOADER, null, this); //loadTrailers(); //loadReviews(); //populateKeys(); } /** * Here manages the views(list) for reviews */ viewReviews.setOnClickListener(new View.OnClickListener() { #Override public void onClick(View v) { if (switcher == 3) { startActivity(new Intent(DetailActivity.this, ReviewActivity.class) .putExtra("switch", 3)); } else { Log.i("this", "I am from initial" + switcher); startActivity(new Intent(DetailActivity.this, ReviewActivity.class).putExtra("id", movieId)); } } } ); favourite.setOnClickListener(new View.OnClickListener() { #Override public void onClick(View v) { data = new DataObject(); data.setName(name); data.setOverview(overview); data.setRating(movieRating); data.setReleaseDate(releaseDate); data.setTrailers(youtube);// data.setMovieReviews(reviews); try { saveImage(name_tv.getText().toString() + "0i", image_tv); saveImage(name_tv.getText().toString() + "1b", backdrop_poster); } catch (IOException e) { e.printStackTrace(); } Toast.makeText(context, "The movie is saved as a favourite", Toast.LENGTH_LONG).show(); AppExecutors.getInstance().diskIO().execute(new Runnable() { #Override public void run() { mDb.dataDao().insertData(data); } }); startActivity(new Intent(DetailActivity.this, ReviewActivity.class).putExtra("id", movieId) .putExtra(ReviewActivity.EXTRA_DATA_ID, 20)); } } ); }
And my ReviewActivity
public class ReviewActivity extends AppCompatActivity implements LoaderManager.LoaderCallbacks<ArrayList<Review>>{ public static ArrayList<Review> reviews; public static List<DataObject> favouriteReviews; public static RecyclerView reviewList; ArrayList<Review> r; private static final int REVIEW_SEARCH_LOADER = 24; private static final String MOVIE_QUERY3 = "api_key"; private static final String API_KEY3 = "6cc4f47bd4a64e0117e157b79072ae37"; private static String SEARCH_QUERY3 = "reviews"; private static final String THE_MOVIEDB_URL3 = "https://api.themoviedb.org/3/movie/"; private static int movId; public static final String EXTRA_DATA_ID = "extraDataId"; private static final int DEFAULT_TASK_ID = -1; private int mTaskId = DEFAULT_TASK_ID; DataObject data1; AppDatabase mDb; ReviewAdapter revAdapter; int loaderSwitch; #Override protected void onResume() { super.onResume(); } #Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_review); mDb = AppDatabase.getInstance(getApplicationContext()); reviews = new ArrayList<Review>(); favouriteReviews = new ArrayList<DataObject>(); reviewList = findViewById(R.id.review_list); LinearLayoutManager layoutManager = new LinearLayoutManager(getApplicationContext()); reviewList.setLayoutManager(layoutManager); reviewList.setHasFixedSize(true); int switcher = getIntent().getIntExtra("switch", 1); Intent intent = getIntent(); if (intent == null) { finish(); } Log.i("this", "swithcer " + switcher); Log.i("this loader", "Loader " + loaderSwitch); if (switcher == 3){ DataObject dataObject = (DataObject) getIntent().getParcelableExtra("ArrayOfReviews"); if (dataObject != null){ ArrayList<Review> movieReviews = dataObject.getMovieReviews(); Toast.makeText(this, "There are reviews saved", Toast.LENGTH_LONG).show(); revAdapter = new ReviewAdapter(this, movieReviews ); reviewList.setAdapter(revAdapter); } } else { movId = getIntent().getIntExtra("id", 20); revAdapter = new ReviewAdapter(this, reviews); reviewList.setAdapter(revAdapter); loadReviews(); //populateReview(); } DividerItemDecoration decoration = new DividerItemDecoration(this, VERTICAL); reviewList.addItemDecoration(decoration); } #Override protected void onStart() { super.onStart(); //loadReviews(); } public static URL buildUrl3(String stringUrl) { Uri uri = Uri.parse(THE_MOVIEDB_URL3).buildUpon() .appendPath(stringUrl) .appendPath(SEARCH_QUERY3) .appendQueryParameter(MOVIE_QUERY3, API_KEY3) .build(); URL url = null; try { url = new URL(uri.toString()); } catch (MalformedURLException exception) { Log.e(TAG, "Error creating URL", exception); } return url; } public void loadReviews(){ // COMPLETED (19) Create a bundle called queryBundle Bundle queryBundle = new Bundle(); // COMPLETED (20) Use putString with SEARCH_QUERY_URL_EXTRA as the key and the String value of the URL as the value// queryBundle.putString(SEARCH_QUERY_URL_EXTRA, url.toString()); // COMPLETED (21) Call getSupportLoaderManager and store it in a LoaderManager variable LoaderManager loaderManager = getSupportLoaderManager(); // COMPLETED (22) Get our Loader by calling getLoader and passing the ID we specified Loader<ArrayList<Review>> movieReviews = loaderManager.getLoader(REVIEW_SEARCH_LOADER); // COMPLETED (23) If the Loader was null, initialize it. Else, restart it. if (movieReviews == null) { loaderManager.initLoader(REVIEW_SEARCH_LOADER, queryBundle, this); } else { loaderManager.restartLoader(REVIEW_SEARCH_LOADER, queryBundle, this); } } #Override public Loader<ArrayList<Review>> onCreateLoader(int id, Bundle args) { return new AsyncTaskLoader<ArrayList<Review>>(this) { #Override protected void onStartLoading() { super.onStartLoading(); forceLoad(); } #Override public ArrayList<Review> loadInBackground() { String g = String.valueOf(movId); // Create URL object URL url = buildUrl3(g); // Perform HTTP request on the URL and receive a JSON response back String jsonResponse = ""; try { jsonResponse = getResponseFromHttpUrl(url); } catch (Exception e) { e.printStackTrace(); } reviews = MovieJsonUtils.parseReview(jsonResponse); return reviews; } }; } #Override public void onLoadFinished(Loader<ArrayList<Review>> loader, ArrayList<Review> dat) { if (reviews != null) { Intent intent = getIntent(); if (intent != null && intent.hasExtra(EXTRA_DATA_ID)) { //mButton.setText(R.string.update_button); if (mTaskId == DEFAULT_TASK_ID) { mTaskId = intent.getIntExtra(EXTRA_DATA_ID, DEFAULT_TASK_ID); AppExecutors.getInstance().diskIO().execute(new Runnable() { #Override public void run() { data.setMovieReviews(reviews); mDb.dataDao().updateData(data); //mDb.dataDao().insertData(data); final List<DataObject> task = mDb.dataDao().loadById(mTaskId); runOnUiThread(new Runnable() { #Override public void run() { populateUI(task); } }); } }); } } else { ReviewAdapter lv = new ReviewAdapter(ReviewActivity.this, reviews); reviewList.setAdapter(lv); } } } #Override public void onLoaderReset(Loader<ArrayList<Review>> loader) { }
Data gets loaded from MainActivity, the saved data is passed on to other activities as a parcellable bundle via intent, the passed data is displayed in DetailActivity but not in ReviewActivity.
Alternatively, if I can load reviews alongside YouTube keys from DetailActivity, I believe I can handle the database issue from there, but two Loaders wouldn't just work together, the app crashes; I am aware two AsyncTasks concurrently run together solved this problem, but I prefer to use Loaders because of performance on configuration change
I'm developing my app, in which storing quotes.
Data about quotes I download from my server.
I want in order to user downloading 10 quotes (at that time data add to local database), and if he scrolled this 10 quotes, new data will be download (again 10).
For example, as in facebook tape (with adding data to local db).
But I also need sync local db with server db.
I do not understand how to combine all this.
Download data - Here I pass the id from which to download from the id from server db.
class DownloadAndParseJson extends AsyncTask<Integer, Void, ArrayList<QuoteObject>> {
interface AsyncResponse {
void processFinish(ArrayList<QuoteObject> output);
}
private AsyncResponse delegate = null;
DownloadAndParseJson(AsyncResponse delegate){
this.delegate = delegate;
}
private static final String TAG = "###" + "DownloadAndParseJson";
#Override
protected ArrayList<QuoteObject> doInBackground(Integer... params) {
Log.i(TAG, "Starting download quotes from " + params[0] + " id");
if (params.length == 0) {
return null;
}
int id = params[0];
HttpURLConnection urlConnection = null;
BufferedReader reader = null;
String countriesJsonStr = null;
try {
final String BASIC_URL = "http://*******.com";
final String ID_PARAM = "id";
Uri builtUri = Uri.parse(BASIC_URL).buildUpon()
.appendQueryParameter(ID_PARAM, Integer.toString(id))
.build();
URL url = new URL(builtUri.toString());
urlConnection = (HttpURLConnection) url.openConnection();
urlConnection.setRequestMethod("GET");
urlConnection.connect();
InputStream inputStream = urlConnection.getInputStream();
StringBuffer buffer = new StringBuffer();
if (inputStream == null) {
return null;
}
reader = new BufferedReader(new InputStreamReader(inputStream));
String line;
while ((line = reader.readLine()) != null) {
buffer.append(line + "\n");
}
if (buffer.length() == 0) {
return null;
}
countriesJsonStr = buffer.toString();
Log.v(TAG, "download end");
} catch (IOException e) {
Log.e(TAG, "Error", e);
return null;
} finally {
if (urlConnection != null) {
urlConnection.disconnect();
}
if (reader != null) {
try {
reader.close();
} catch (final IOException e) {
Log.e(TAG, "Error", e);
}
}
}
Log.i(TAG, "End download quotes");
return getArrayParsedJson(countriesJsonStr);
}
#Override
protected void onPostExecute(ArrayList<QuoteObject> result) {
Log.i(TAG, "Downloaded " + result.size() + " quotes");
delegate.processFinish(result);
}
private ArrayList<QuoteObject> getArrayParsedJson(String jsonStr){
Gson gson = new Gson();
Type collectionType = new TypeToken<ArrayList<QuoteObject>>(){}.getType();
return gson.fromJson(jsonStr, collectionType);
}
}
Working with the database - here Im store Quote objects
public class RealmHelper {
private static final String TAG = "###" + "RealmHelper";
Context context;
public RealmHelper(Context context) {
this.context = context;
}
public void write(ArrayList<QuoteObject> quoteObjectArrayList) {
Realm.init(context);
Realm realm = Realm.getDefaultInstance();
realm.beginTransaction();
for (QuoteObject quoteObject : quoteObjectArrayList){
realm.copyToRealm(quoteObject);
}
realm.commitTransaction();
}
public ArrayList<QuoteObject> read() {
Realm.init(context);
Realm realm = Realm.getDefaultInstance();
return new ArrayList<>(realm.where(QuoteObject.class).findAll());
}
public void delete() {
Realm.init(context);
Realm realm = Realm.getDefaultInstance();
final RealmResults<QuoteObject> countries = realm.where(QuoteObject.class).findAll();
realm.executeTransaction(new Realm.Transaction() {
#Override
public void execute(Realm realm) {
countries.deleteAllFromRealm();
Log.i(TAG, "size = " + countries.size());
}
});
}
}
MainActivity
public class MainActivity extends AppCompatActivity
implements DownloadAndParseJson.AsyncResponse{
.
.
RVAdapter adapter;
private ArrayList<QuoteObject> quoteObjectArrayList;
.
.
protected void onCreate(){
.
.
.
RecyclerView recyclerView = (RecyclerView) findViewById(R.id.recyclerView);
recyclerView.setHasFixedSize(true);
LinearLayoutManager layoutManager = new LinearLayoutManager(this);
recyclerView.setLayoutManager(layoutManager);
adapter = new RVAdapter(this, quoteObjectArrayList);
recyclerView.setAdapter(adapter);
}
#Override
public void processFinish(ArrayList<QuoteObject> output) {
if (output.size() != 0) {
quoteObjectArrayList = output;
Log.i(TAG, "processFinish() returned outputArray size " + output.size());
} else
Toast.makeText(this, "Not found quotes", Toast.LENGTH_SHORT).show();
}
RecyclerView.Adapter - To display quotes Im using card view.
class RVAdapter extends RecyclerView.Adapter<RVAdapter.PersonViewHolder>
implements DownloadAndParseJson.AsyncResponse{
private static final String TAG = "###" + "RVAdapter";
private Context context;
private boolean hasMoreItems;
private ArrayList<QuoteObject> quoteObjectArrayList;
RVAdapter(Context context, ArrayList<QuoteObject> quoteObjectArrayList){
this.context = context;
this.hasMoreItems = true;
this.quoteObjectArrayList = quoteObjectArrayList;
Log.i(TAG, "quoteObjectArrayList = " + quoteObjectArrayList.size());
}
private void notifyNoMoreItems(){
hasMoreItems = false;
Toast.makeText(context, "No More Items", Toast.LENGTH_SHORT).show();
}
#Override
public RVAdapter.PersonViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) {
View view = LayoutInflater.from(viewGroup.getContext())
.inflate(R.layout.card_of_quote, viewGroup, false);
return new PersonViewHolder(view);
}
#Override
public void onBindViewHolder(final RVAdapter.PersonViewHolder holder, int position) {
Log.i(TAG, "Card position = " + position);
if (position == quoteObjectArrayList.size() && hasMoreItems){
new DownloadAndParseJson(this).execute(Integer.parseInt(quoteObjectArrayList.get(position).getId()));
}
holder.contentOfQuote.setText(quoteObjectArrayList.get(position).getQuote());
holder.authorQuote.setText(quoteObjectArrayList.get(position).getAuthor());
holder.ratingBar.setOnRatingChangeListener(new MaterialRatingBar.OnRatingChangeListener() {
#Override
public void onRatingChanged(MaterialRatingBar ratingBar, float rating) {
//ratingBar.setRight(Integer.parseInt(quoteObjectArrayList.get(position).getId()));
}
});
holder.btnShareQuote.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent sendIntent = new Intent();
sendIntent.setAction(Intent.ACTION_SEND);
sendIntent.putExtra(Intent.EXTRA_TEXT, holder.contentOfQuote.getText()
+ "\n" + holder.authorQuote.getText() );
sendIntent.setType("text/plain");
context.startActivity(sendIntent);
}
});
holder.btnViewComment.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
//View Comments
}
});
}
#Override
public int getItemCount() {
return quoteObjectArrayList.size();
}
#Override
public void processFinish(ArrayList<QuoteObject> output) {
if (output.size() != 0) {
quoteObjectArrayList.addAll(output);
Log.i(TAG, "Total quoteArray Size = " + quoteObjectArrayList.size());
new RealmHelper(context).write(output); // NEED separate throw
} else notifyNoMoreItems();
}
static class PersonViewHolder extends RecyclerView.ViewHolder {
CardView cardView;
TextView contentOfQuote, authorQuote;
MaterialRatingBar ratingBar;
ImageButton btnViewComment, btnShareQuote;
TextView rating;
public PersonViewHolder(View itemView) {
super(itemView);
this.cardView = (CardView) itemView.findViewById(R.id.cardView);
this.contentOfQuote = (TextView) itemView.findViewById(R.id.contentOfQuote);
this.authorQuote = (TextView) itemView.findViewById(R.id.authorQuote);
this.btnViewComment = (ImageButton) itemView.findViewById(R.id.btnViewComment);
this.btnShareQuote = (ImageButton) itemView.findViewById(R.id.btnShareQuote);
this.ratingBar = (MaterialRatingBar) itemView.findViewById(R.id.ratingBar);
this.rating = (TextView) itemView.findViewById(R.id.txtRating);
}
}
}
Now I need to combine all this.
It should turn out:
To start with the data from local db.
If there is no data - download new (10 quotes).
Else take data from local db until they run out
Download 10 quotes from server bd, add to local and display they.
Or If there is no data Print out about it.
Sync local bd with server.
Help me please.
Thanks.
This would be much easier if you used RealmResults as intended along with RealmChangeListener and Realm's notification system. See the official documentation.
class DownloadAndParseJson extends AsyncTask<Integer, Void, Void> {
DownloadAndParseJson(){
}
private static final String TAG = "###" + "DownloadAndParseJson";
#Override
protected Void doInBackground(Integer... params) {
Log.i(TAG, "Starting download quotes from " + params[0] + " id");
if (params.length == 0) {
return null;
}
int id = params[0];
try {
final List<QuoteObject> quotes = retrofitService.getQuotes(id).execute().body();
if(quotes == null) {
throw new RuntimeException("Download failed");
}
try(Realm realm = Realm.getDefaultInstance()) {
realm.executeTransaction(new Realm.Transaction() {
#Override
public void execute(Realm realm) {
realm.insert(quotes);
}
});
}
} catch (Exception e) {
Log.e(TAG, "Error", e);
return null;
}
Log.i(TAG, "End download quotes");
return null;
}
#Override
protected void onPostExecute(Void ignored) {
}
}
And
class RVAdapter extends RealmRecyclerViewAdapter<QuoteObject, RVAdapter.PersonViewHolder> {
private static final String TAG = "###" + "RVAdapter";
RVAdapter(OrderedRealmCollection<QuoteObject> quotes) {
super(quotes, true);
}
// onCreateViewHolder
// onBindViewHolder
// view holder
}
And
RecyclerView recyclerView = (RecyclerView) findViewById(R.id.recyclerView);
recyclerView.setHasFixedSize(true);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
adapter = new RVAdapter(realm.where(QuotesObject.class).findAll()); // <-- RealmResults
recyclerView.setAdapter(adapter);
and some "did download all" kind of logic, although that needs a bit smarter error handling; and "is data being downloaded" so that you don't spam requests when you scrolled down.
I'm trying to update all my Items in a Recyclerview with the SwipeRefreshlayout,
but unfortunately will only the last item be updated, the others remain unchanged.
Here is my relevant code:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//LeakCanary.install(this.getApplication());
setContentView(R.layout.activity_main);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
Window window = getWindow();
window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
window.setStatusBarColor(ContextCompat.getColor(this, R.color.colorPrimaryDark));
}
handleArrayList(getApplicationContext(), 0);
Log.d("Arraylist", "" + intentNumber2.size());
recyclerView = (RecyclerView) findViewById(R.id.rv);
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this);
linearLayoutManager.setOrientation(LinearLayoutManager.VERTICAL);
recyclerView.setLayoutManager(linearLayoutManager);
recyclerView.setItemAnimator(null);
recyclerView.setHasFixedSize(true);
SimpleAdapter adapter = new SimpleAdapter();
recyclerView.addItemDecoration(new SimpleDividerItemDecoration(this));
recyclerView.setAdapter(adapter);
FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
fab.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Intent intent = new Intent(getBaseContext(), AddReminder.class);
startActivity(intent);
}
});
adapter.notifyItemInserted(cards.size() - 1);
refreshLayout = (SwipeRefreshLayout) findViewById(R.id.swipeRefreshLayout);
updateRemainingTime();
refreshLayout.setOnRefreshListener(this);
}
#Override
public void onRefresh() {
updateRemainingTime();
}
//refresh the time remaining on the cards
private void updateRemainingTime() {
if (!cards.isEmpty()) {
for (int i = cards.size()-1; i >= 0; i--) {
Card card = cards.get(i);
String time = card.getCardTime();
String date = card.getCardDate();
Date now = new Date();
Date then = null;
try {
then = sdtf.parse(date + " " + time);
} catch (ParseException e) {
Log.d("PARSEEXCEPTION:", " " + e);
}
String remainingTime = calculate.calcTimeDiff(then.getTime(), now.getTime());
Log.d("Card","Card updated " + remainingTime);
card.cardRemainingTime(remainingTime);
recyclerView.getAdapter().notifyItemChanged(i);
}
refreshLayout.setRefreshing(false);
} else {
refreshLayout.setRefreshing(false);
}
}
My Adapter:
public class SimpleAdapter extends RecyclerView.Adapter<SimpleAdapter.ViewHolder> implements RemoveItem {
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
LayoutInflater inflater = LayoutInflater.from(parent.getContext());
View itemView = inflater.inflate(R.layout.item_main, parent, false);
return new ViewHolder(itemView, this);
}
#Override
public void onBindViewHolder(ViewHolder holder, int position) {
Card card = cards.get(position);
holder.setReminderText(card.getCardText());
card_tv2.setText(card.getCardRemainingTime());
holder.setSelectable(true);
}
#Override
public int getItemCount() {
return cards.size();
}
#Override
public void remove(int position) {
cards.remove(position);
Log.d("Main", "removed " + position);
notifyItemRemoved(position);
notifyItemRangeChanged(position, cards.size());
AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
Intent intent1 = new Intent(getBaseContext(), AlarmReceiver.class);
int intentNumber = intentNumber2.get(position);
intentNumber2.remove(position);
Log.d("IntentNumber", "" + intentNumber);
PendingIntent alarmIntent = PendingIntent.getBroadcast(getApplicationContext(), intentNumber, intent1, PendingIntent.FLAG_CANCEL_CURRENT);
alarmIntent.cancel();
alarmManager.cancel(alarmIntent);
File dir = getFilesDir();
File file = new File(dir, "Reminder" + " " + position);
boolean deleted = file.delete();
MainActivity.handleArrayList(getApplicationContext(), 1);
}
public class ViewHolder extends SwappingHolder implements View.OnClickListener, View.OnLongClickListener {
public final LinearLayout background;
public ViewHolder(View itemView, RemoveItem removeItem1) {
super(itemView, multiSelector);
itemView.setOnClickListener(this);
itemView.setOnLongClickListener(this);
itemView.setLongClickable(true);
removeItem = removeItem1;
card_tv = (TextView) itemView.findViewById(R.id.card_tv);
card_tv2 = (TextView) itemView.findViewById(R.id.card_tv2);
card_th = (ImageView) itemView.findViewById(R.id.thumbnail);
card_check = (ImageView) itemView.findViewById(R.id.card_check);
background = (LinearLayout) itemView.findViewById(R.id.background);
}
#Override
public void onClick(View view) {
if (multiSelector.tapSelection(this)) {
background.setSelected(true);
} else {
int position = getAdapterPosition();
String text = "error";
String time = "error";
String date = "error";
String repeat;
boolean repeat2 = false;
String quantity = "error";
String mode = "error";
try {
InputStream inputStream = openFileInput("Reminder" + " " + position);
InputStreamReader inputStreamReader = new InputStreamReader(inputStream);
BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
text = bufferedReader.readLine();
time = bufferedReader.readLine();
date = bufferedReader.readLine();
repeat = bufferedReader.readLine();
repeat2 = repeat.equals("true");
quantity = bufferedReader.readLine();
mode = bufferedReader.readLine();
inputStreamReader.close();
bufferedReader.close();
inputStream.close();
} catch (Exception e) {
e.printStackTrace();
}
Intent intent2 = new Intent(getBaseContext(), ChangeReminder.class);
intent2.putExtra("POSITION", position);
intent2.putExtra("TIME", time);
intent2.putExtra("DATE", date);
intent2.putExtra("TEXT", text);
intent2.putExtra("REPEAT", repeat2);
intent2.putExtra("QUANTITY", quantity);
intent2.putExtra("MODE", mode);
startActivity(intent2);
}
}
#Override
public boolean onLongClick(View view) {
AppCompatActivity activity = MainActivity.this;
activity.startSupportActionMode(mDeleteMode);
multiSelector.setSelectable(true);
multiSelector.setSelected(this, true);
background.setSelected(true);
return true;
}
public void setReminderText(String cardText) {
card_tv.setText(cardText);
ColorGenerator colorGenerator = ColorGenerator.MATERIAL;
TextDrawable drawableBuilder;
String letter = "A";
if (cardText != null && !cardText.isEmpty()) {
letter = cardText.substring(0, 1);
}
int color = colorGenerator.getRandomColor();
drawableBuilder = TextDrawable.builder()
.buildRound(letter, color);
card_th.setImageDrawable(drawableBuilder);
}
}
}
}
Card class:
public class Card implements Serializable {
public int drawable;
private String cardText;
private String cardDate;
private String cardTime;
private String cardRemainingTime;
public void cardText(String cardText) {
this.cardText = cardText;
}
public void cardDate(String cardDate) {
this.cardDate = cardDate;
}
public void cardTime(String cardTime) {
this.cardTime = cardTime;
}
public void cardRemainingTime(String cardRemainingTime) {
this.cardRemainingTime = cardRemainingTime;
}
public String getCardText() {
return cardText;
}
public String getCardDate() {
return cardDate;
}
public String getCardTime() {
return cardTime;
}
public String getCardRemainingTime() {
return cardRemainingTime;
}
}
Edit:
I found out that when I reopen the app, the time correctly updates on all items.
This means there has to be a difference between calling updateRemainingTime from onRefresh and onCreate, but I don't know which. Any help would be appreciated.
Make a change in updateRemainingTime method.
if (!cards.isEmpty()) {
for (int i = cards.size() - 1; i >= 0; i--) {
Card card = cards.get(i);
String time = card.getCardTime();
String date = card.getCardDate();
Date now = new Date();
Date then = null;
try {
then = sdtf.parse(date + " " + time);
} catch (ParseException e) {
Log.d("PARSEEXCEPTION:", " " + e);
}
String remainingTime = calculate.calcTimeDiff(then.getTime(), now.getTime());
Log.d("Card", "Card updated " + remainingTime);
//card.cardRemainingTime(remainingTime);
//replaces to
cards.get(i).cardRemainingTime(remainingTime);
}
List<Card> cardTemp = new ArrayList<>();
cardTemp = cards;
cards.clear();
cards.addAll(cardTemp);
recyclerView.notifyDataSetChanged();
}
I know that the purpose of the AsyncTask is to run asynchronously with other tasks of the app and finish in the background, but apparently I need to do this, I need to start an activity from AsyncTask and since I cant extend an activity in this class I can not use startactivityforresult, so how can I wait till my activity finishes?
Here is my code:
public class ListSpdFiles extends AsyncTask<Void, Void, String[]> {
public AsyncResponse delegate = null;
private static final String TAG = "ListSpdFiles: ";
Context applicationContext;
ContentResolver spdappliationcontext;
public final CountDownLatch setSignal= new CountDownLatch(1);
private final ReentrantLock lock = new ReentrantLock();
String username = "";
/**
* Status code returned by the SPD on operation success.
*/
private static final int SUCCESS = 4;
private boolean createbutt;
private boolean deletebutt;
private String initiator;
private String path;
private String pass;
private String url;
private SecureApp pcas;
private boolean isConnected = false; // connected to PCAS service?
private String CurrentURL = null;
private PcasConnection pcasConnection = new PcasConnection() {
#Override
public void onPcasServiceConnected() {
Log.d(TAG, "pcasServiceConnected");
latch.countDown();
}
#Override
public void onPcasServiceDisconnected() {
Log.d(TAG, "pcasServiceDisconnected");
}
};
private CountDownLatch latch = new CountDownLatch(1);
public ListSpdFiles(boolean createbutt, boolean deletebutt, String url, String pass, Context context, String initiator, String path, AsyncResponse asyncResponse) {
this.initiator = initiator;
this.path = path;
this.pass= pass;
this.url= url;
this.createbutt= createbutt;
this.deletebutt=deletebutt;
applicationContext = context.getApplicationContext();
spdappliationcontext = context.getContentResolver();
delegate = asyncResponse;
}
private void init() {
Log.d(TAG, "starting task");
pcas = new AndroidNode(applicationContext, pcasConnection);
isConnected = pcas.connect();
}
private void term() {
Log.d(TAG, "terminating task");
if (pcas != null) {
pcas.disconnect();
pcas = null;
isConnected = false;
}
}
#Override
protected void onPreExecute() {
super.onPreExecute();
init();
}
#Override
protected String[] doInBackground(Void... params) {
CurrentURL = getLastAccessedBrowserPage();
// check if connected to PCAS Service
if (!isConnected) {
Log.v(TAG, "not connected, terminating task");
return null;
}
// wait until connection with SPD is up
try {
if (!latch.await(20, TimeUnit.SECONDS)) {
Log.v(TAG, "unable to connected within allotted time, terminating task");
return null;
}
} catch (InterruptedException e) {
Log.v(TAG, "interrupted while waiting for connection in lsdir task");
return null;
}
// perform operation (this is where the actual operation is called)
try {
return lsdir();
} catch (DeadServiceException e) {
Log.i(TAG, "service boom", e);
return null;
} catch (DeadDeviceException e) {
Log.i(TAG, "device boom", e);
return null;
}
}
#Override
protected void onPostExecute(String[] listOfFiles) {
super.onPostExecute(listOfFiles);
if (listOfFiles == null) {
Log.i(TAG, "task concluded with null list of files");
} else {
Log.i(TAG, "task concluded with the following list of files: "
+ Arrays.toString(listOfFiles));
}
term();
delegate.processFinish(username);
}
#Override
protected void onCancelled(String[] listOfFiles) {
super.onCancelled(listOfFiles);
Log.i(TAG, "lsdir was canceled");
term();
}
/**
* Returns an array of strings containing the files available at the given path, or
* {#code null} on failure.
*/
private String[] lsdir() throws DeadDeviceException, DeadServiceException {
Result<List<String>> result = pcas.lsdir(initiator, path); // the lsdir call to the
boolean crtbut = createbutt;
boolean dlbut= deletebutt;
ArrayList<String> mylist = new ArrayList<String>();
final Global globalVariable = (Global) applicationContext;
if (crtbut==false && dlbut == false){
if ( globalVariable.getPasswordButt()==false ) {
final boolean isusername = globalVariable.getIsUsername();
if (isusername == true) {
Log.i(TAG, "current url: " + CurrentURL);
if (Arrays.toString(result.getValue().toArray(new String[0])).contains(CurrentURL)) {
String sharareh = Arrays.toString(result.getValue().toArray(new String[0]));
String[] items = sharareh.split(", ");
for (String item : items) {
String trimmed;
if (item.startsWith("[" + CurrentURL + ".")) {
trimmed = item.replace("[" + CurrentURL + ".", "");
if (trimmed.endsWith(".txt]")) {
trimmed = trimmed.replace(".txt]", "");
mylist.add(trimmed.replace(".txt]", ""));
} else if (trimmed.endsWith(".txt")) {
trimmed = trimmed.replace(".txt", "");
mylist.add(trimmed.replace(".txt", ""));
}
Log.i(TAG, "list of files sharareh: " + trimmed);
} else if (item.startsWith(CurrentURL + ".")) {
trimmed = item.replace(CurrentURL + ".", "");
if (trimmed.endsWith(".txt]")) {
trimmed = trimmed.replace(".txt]", "");
mylist.add(trimmed.replace(".txt]", ""));
} else if (trimmed.endsWith(".txt")) {
trimmed = trimmed.replace(".txt", "");
mylist.add(trimmed.replace(".txt", ""));
}
Log.i(TAG, "list of files sharareh: " + trimmed);
}
}
}
globalVariable.setPopupdone(false);
Intent i = new Intent(applicationContext, PopUp.class);
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
i.putExtra("EXTRA_SESSION_ID", mylist);
applicationContext.startActivity(i);
username = globalVariable.getUsername();
}
else if (isusername == false)
Log.i(TAG, "Wrong Input Type For Username.");
}
if (result.getState() != SUCCESS) {
Log.v(TAG, "operation failed");
return null;
}
if (result.getValue() == null) {
Log.v(TAG, "operation succeeded but operation returned null list");
return null;
}
return result.getValue().toArray(new String[0]);
}
//}
if (result.getState() != SUCCESS) {
Log.v(TAG, "operation failed");
return null;
}
if (result.getValue() == null) {
Log.v(TAG, "operation succeeded but operation returned null list");
return null;
}
return result.getValue().toArray(new String[0]);
}
public String getLastAccessedBrowserPage() {
String Domain = null;
Cursor webLinksCursor = spdappliationcontext.query(Browser.BOOKMARKS_URI, Browser.HISTORY_PROJECTION, null, null, Browser.BookmarkColumns.DATE + " DESC");
int row_count = webLinksCursor.getCount();
int title_column_index = webLinksCursor.getColumnIndexOrThrow(Browser.BookmarkColumns.TITLE);
int url_column_index = webLinksCursor.getColumnIndexOrThrow(Browser.BookmarkColumns.URL);
if ((title_column_index > -1) && (url_column_index > -1) && (row_count > 0)) {
webLinksCursor.moveToFirst();
while (webLinksCursor.isAfterLast() == false) {
if (webLinksCursor.getInt(Browser.HISTORY_PROJECTION_BOOKMARK_INDEX) != 1) {
if (!webLinksCursor.isNull(url_column_index)) {
Log.i("History", "Last page browsed " + webLinksCursor.getString(url_column_index));
try {
Domain = getDomainName(webLinksCursor.getString(url_column_index));
Log.i("Domain", "Last page browsed " + Domain);
return Domain;
} catch (URISyntaxException e) {
e.printStackTrace();
}
break;
}
}
webLinksCursor.moveToNext();
}
}
webLinksCursor.close();
return null;
}
public String getDomainName(String url) throws URISyntaxException {
URI uri = new URI(url);
String domain = uri.getHost();
return domain.startsWith("www.") ? domain.substring(4) : domain;
}}
My Activity class:
public class PopUp extends Activity {
private static final String TAG = "PopUp";
ArrayList<String> value = null;
ArrayList<String> usernames;
#Override
protected void onCreate(Bundle savedInstanceState) {
final Global globalVariable = (Global) getApplicationContext();
globalVariable.setUsername("");
Bundle extras = getIntent().getExtras();
if (extras != null) {
value = extras.getStringArrayList("EXTRA_SESSION_ID");
}
usernames = value;
super.onCreate(savedInstanceState);
setContentView(R.layout.popupactivity);
final Button btnOpenPopup = (Button) findViewById(R.id.openpopup);
btnOpenPopup.setOnClickListener(new Button.OnClickListener() {
#Override
public void onClick(View arg0) {
LayoutInflater layoutInflater = (LayoutInflater) getBaseContext().getSystemService(LAYOUT_INFLATER_SERVICE);
View popupView = layoutInflater.inflate(R.layout.popup, null);
final PopupWindow popupWindow = new PopupWindow(popupView, LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
Button btnSelect = (Button) popupView.findViewById(R.id.select);
Spinner popupSpinner = (Spinner) popupView.findViewById(R.id.popupspinner);
ArrayAdapter<String> adapter = new ArrayAdapter<String>(PopUp.this, android.R.layout.simple_spinner_item, usernames);
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
popupSpinner.setAdapter(adapter);
popupSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
#Override
public void onItemSelected(AdapterView<?> arg0, View arg1, int arg2, long arg3) {
globalVariable.setUsername(usernames.get(arg2));
}
#Override
public void onNothingSelected(AdapterView<?> arg0) {
}
});
btnSelect.setOnClickListener(new Button.OnClickListener() {
#Override
public void onClick(View v) {
globalVariable.setPopupdone(true);
popupWindow.dismiss();
finish();
}
}
);
popupWindow.showAsDropDown(btnOpenPopup, 50, -30);
}
});
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.poupup_menu, menu);
return true;
}}