Google Play: update prices from IInAppBillingService - android

I created a class for working with subscriptions in the store.
In the beginning I receive from the server the list of subscriptions with the prices
The code is working and on most devices there is no problem.
But some users do not recive prices. It's like there's no response from the server. I've studied examples of implementation in Google documentation, but I can not understand where I can have problems in the code.
Part of my code:
public class BillingActivity extends AppCompatActivity {
RelativeLayout imageLayout;
View payButton;
// WebView payWebView;
// TextView useCodeButton;
ProgressBar progress1;
ProgressBar progress2;
ProgressBar progress3;
IInAppBillingService inAppBillingService;
#Override
public void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_billing_subscription);
price_1monthTextView = (TextView) findViewById(R.id.price_1monthTextView);
relative_1month = (RelativeLayout) findViewById(R.id.relative_1month);
relative_1month.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (MainActivity.myAccount == null) return;
if (MainActivity.myAccount.getUniqid() == null) return;
if (subscription1m != null) {
try {
Log.d("my", "purchase..." + subscription1m.storeName);
purchaseProduct(subscription1m);
} catch (Exception e) {
e.printStackTrace();
Log.d("my", "purchase error = " + e.toString());
}
}
}
});
progress1 = (ProgressBar) findViewById(R.id.progress1);
startGoogleBilling();
}
private void startGoogleBilling() {
if (serviceConnection != null) {
unbindService(serviceConnection);
}
progress1.setVisibility(View.VISIBLE);
serviceConnection = new ServiceConnection() {
#Override
public void onServiceConnected(ComponentName name, IBinder service) {
inAppBillingService = IInAppBillingService.Stub.asInterface(service);
getSubscribtionsList();
}
#Override
public void onServiceDisconnected(ComponentName name) {
inAppBillingService = null;
}
};
Intent serviceIntent =
new Intent("com.android.vending.billing.InAppBillingService.BIND");
serviceIntent.setPackage("com.android.vending");
bindService(serviceIntent, serviceConnection, Context.BIND_AUTO_CREATE);
}
private static final int PR_CNT = 3;
List<InAppProduct> subscriptions = null;
InAppProduct subscription1m = null;
InAppProduct subscription3m = null;
InAppProduct subscription1y = null;
String[] productIds = {"eq.subscription.1m", "eq.subscription.3m.2", "eq.subscription.1y"};
private void getSubscribtionsList() {
mSwipeRefreshLayout.setRefreshing(false);
progress1.setVisibility(View.GONE);
try {
subscriptions =
getInAppPurchases("subs", productIds[0], productIds[1], productIds[2]);
if (subscriptions.size() == PR_CNT) {
for (InAppProduct inAppProduct : subscriptions) {
String productId = inAppProduct.productId;
Log.d("my", "productId= " + productId);
if (productId.contains(productIds[0])) subscription1m = inAppProduct;
if (productId.contains(productIds[1])) subscription3m = inAppProduct;
if (productId.contains(productIds[2])) subscription1y = inAppProduct;
}
Log.d("my", "1m= " + subscription1m.storeName + " pr=" + subscription1m.price + "\\n\\r " +
"3m= " + subscription3m.storeName + " pr=" + subscription3m.price + "\\n\\r " +
"1y= " + subscription1y.storeName + " pr=" + subscription1y.price + "\\n\\r ");
///----------------------!!!!
// purchaseProduct(inAppProduct);
}
updatePrices();
} catch (Exception e) {
Log.d("my", "exc = " + e.toString());
if (e.toString().contains("Attempt to invoke interface method 'android.os.Bundle com.android.vending.billing.IInAppBillingService.getSkuDetails")) {
if (attempt < 4) {
//getSubscribtionsList();
// startGoogleBilling();
} else {
}
}
// Toast.makeText(this, "Google inApp connection error", Toast.LENGTH_SHORT).show();
// refreshButton.setVisibility(View.VISIBLE);
startGoogleBilling();
}
}
private int attempt = 0;
#Override
public void onDestroy() {
super.onDestroy();
if (serviceConnection != null) {
unbindService(serviceConnection);
}
}
class InAppProduct {
public String productId;
public String storeName;
public String storeDescription;
public String price;
public boolean isSubscription;
public int priceAmountMicros;
public String currencyIsoCode;
public String getSku() {
return productId;
}
String getType() {
return isSubscription ? "subs" : "inapp";
}
}
List<InAppProduct> getInAppPurchases(String type, String... productIds) throws Exception {
ArrayList<String> skuList = new ArrayList<>(Arrays.asList(productIds));
Bundle query = new Bundle();
query.putStringArrayList("ITEM_ID_LIST", skuList);
Bundle skuDetails = inAppBillingService.getSkuDetails(
3, getPackageName(), type, query);
ArrayList<String> responseList = skuDetails.getStringArrayList("DETAILS_LIST");
List<InAppProduct> result = new ArrayList<>();
for (String responseItem : responseList) {
JSONObject jsonObject = new JSONObject(responseItem);
InAppProduct product = new InAppProduct();
// "com.example.myapp_testing_inapp1"
product.productId = jsonObject.getString("productId");
// Покупка
product.storeName = jsonObject.getString("title");
// Детали покупки
product.storeDescription = jsonObject.getString("description");
// "0.99USD"
product.price = jsonObject.getString("price");
// "true/false"
product.isSubscription = jsonObject.getString("type").equals("subs");
// "990000" = цена x 1000000
product.priceAmountMicros =
Integer.parseInt(jsonObject.getString("price_amount_micros"));
// USD
product.currencyIsoCode = jsonObject.getString("price_currency_code");
result.add(product);
}
return result;
}
private void updatePrices() {
if (subscriptions.size() == PR_CNT) {
price_1monthTextView.setText(subscription1m.price);
price_3monthTextView.setText(subscription3m.price);
price_1yearTextView.setText(subscription1y.price);
}
}
}

my problem was the bit depth of the X variable priceAmountMicros
The price from playmarket is multiplied by a 1000000 , and Kazakh tenge has exchange rate = 1 USD= 331,3 KZT.
And if i have price 18 000 KTZ and * 1000 000.
For price variable I must use long type

Related

I want to save data in SecondActivity from FirstActivity using Room

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

Updating recyclerview using findViewHolderForLayoutPosition

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);.

Downloading data from server and add this data to local database with sync

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.

How to wait for an activity to finish in asynctask

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;
}}

List ImageView repeating same image when shared

I have a listView that is supposed to accept a shared message and image where the image is placed within the ImageView. This feature works for just the first message, but once an image is shared, each message received after that initial one becomes a copy of that same image even though the blank image placeholder was already set, which is just a one pixel black png:
holder.sharedSpecial.setImageResource(R.drawable.image_share_empty_holder);
An example is below:
The green textbox is the recipient. They have recieved a shared image from the yellow textbox. The yellow textbox then simply sends a normal message and I have set another image as a placeholder for normal messages: holder.sharedSpecial.setImageResource(R.drawable.image_share_empty_holder);
The same previously shared image takes precedence. I have used notifyDataSetChanged() so as to allow for the updating the adapter so that it would recognize not to use the same image, but to no avail.
How can I reformulate this class so that the image shared is only displayed with the proper message and not copied into each subsequent message?
The ArrayAdapter class:
public class DiscussArrayAdapter extends ArrayAdapter<OneComment> {
class ViewHolder {
TextView countryName;
ImageView sharedSpecial;
LinearLayout wrapper;
}
private TextView countryName;
private ImageView sharedSpecial;
private MapView locationMap;
private GoogleMap map;
private List<OneComment> countries = new ArrayList<OneComment>();
private LinearLayout wrapper;
private JSONObject resultObject;
private JSONObject imageObject;
String getSharedSpecialURL = null;
String getSharedSpecialWithLocationURL = null;
String specialsActionURL = "http://" + Global.getIpAddress()
+ ":3000/getSharedSpecial/";
String specialsLocationActionURL = "http://" + Global.getIpAddress()
+ ":3000/getSharedSpecialWithLocation/";
String JSON = ".json";
#Override
public void add(OneComment object) {
countries.add(object);
super.add(object);
}
public DiscussArrayAdapter(Context context, int textViewResourceId) {
super(context, textViewResourceId);
}
public int getCount() {
return this.countries.size();
}
private OneComment comment = null;
public OneComment getItem(int index) {
return this.countries.get(index);
}
public View getView(int position, View convertView, ViewGroup parent) {
final ViewHolder holder;
View row = convertView;
if (row == null) {
LayoutInflater inflater = (LayoutInflater) this.getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
row = inflater.inflate(R.layout.message_list_item, parent, false);
holder = new ViewHolder();
holder.wrapper = (LinearLayout) row.findViewById(R.id.wrapper);
holder.countryName = (TextView) row.findViewById(R.id.comment);
holder.sharedSpecial = (ImageView) row.findViewById(R.id.sharedSpecial);
// Store the ViewHolder as a tag.
row.setTag(holder);
} else {
holder = (ViewHolder) row.getTag();
}
Log.v("COMMENTING","Comment is " + countries.get(position).comment);
//OneComment comment = getItem(position);
holder.countryName.setText(countries.get(position).comment);
// Initiating Volley
final RequestQueue requestQueue = VolleySingleton.getsInstance().getRequestQueue();
// Check if message has campaign or campaign/location attached
if (countries.get(position).campaign_id == "0" && countries.get(position).location_id == "0") {
holder.sharedSpecial.setImageResource(R.drawable.image_share_empty_holder);
Log.v("TESTING", "It is working");
} else if (countries.get(position).campaign_id != "0" && countries.get(position).location_id != "0") {
// If both were shared
getSharedSpecialWithLocationURL = specialsLocationActionURL + countries.get(position).campaign_id + "/" + countries.get(position).location_id + JSON;
// Test Campaign id = 41
// Location id = 104
// GET JSON data and parse
JsonObjectRequest getCampaignLocationData = new JsonObjectRequest(Request.Method.GET, getSharedSpecialWithLocationURL, null,
new Response.Listener<JSONObject>() {
#Override
public void onResponse(JSONObject response) {
// Parse the JSON:
try {
resultObject = response.getJSONObject("shared");
} catch (JSONException e) {
e.printStackTrace();
}
// Get and set image
Picasso.with(getContext()).load("http://" + Global.getIpAddress() + ":3000" + adImageURL).into(holder.sharedSpecial);
}
},
new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
Log.d("Error.Response", error.toString());
}
}
);
requestQueue.add(getCampaignLocationData);
} else if (countries.get(position).campaign_id != "0" && countries.get(position).location_id == "0") {
// Just the campaign is shared
getSharedSpecialURL = specialsActionURL + countries.get(position).campaign_id + JSON;
// Test Campaign id = 41
// GET JSON data and parse
JsonObjectRequest getCampaignData = new JsonObjectRequest(Request.Method.GET, getSharedSpecialURL, null,
new Response.Listener<JSONObject>() {
#Override
public void onResponse(JSONObject response) {
// Parse the JSON:
try {
resultObject = response.getJSONObject("shared");
} catch (JSONException e) {
e.printStackTrace();
}
// Get and set image
Picasso.with(getContext()).load("http://" + Global.getIpAddress() + ":3000" + adImageURL).into(holder.sharedSpecial);
}
},
new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
Log.d("Error.Response", error.toString());
}
}
);
requestQueue.add(getCampaignData);
// Location set to empty
}
// If left is true, then yellow, if not then set to green bubble
holder.countryName.setBackgroundResource(countries.get(position).left ? R.drawable.bubble_yellow : R.drawable.bubble_green);
holder.wrapper.setGravity(countries.get(position).left ? Gravity.LEFT : Gravity.RIGHT);
return row;
}
}
The messaging class that sends normal messages only but can receive image messages and set to the adapter:
public class GroupMessaging extends Activity {
private static final int MESSAGE_CANNOT_BE_SENT = 0;
public String username;
public String groupname;
private Button sendMessageButton;
private Manager imService;
private InfoOfGroup group = new InfoOfGroup();
private InfoOfGroupMessage groupMsg = new InfoOfGroupMessage();
private StorageManipulater localstoragehandler;
private Cursor dbCursor;
private com.example.feastapp.ChatBoxUi.DiscussArrayAdapter adapter;
private ListView lv;
private EditText editText1;
private ServiceConnection mConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className, IBinder service) {
imService = ((MessagingService.IMBinder) service).getService();
}
public void onServiceDisconnected(ComponentName className) {
imService = null;
Toast.makeText(GroupMessaging.this, R.string.local_service_stopped,
Toast.LENGTH_SHORT).show();
}
};
#Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.message_activity);
lv = (ListView) findViewById(R.id.listView1);
adapter = new DiscussArrayAdapter(getApplicationContext(), R.layout.message_list_item);
lv.setAdapter(adapter);
editText1 = (EditText) findViewById(R.id.editText1);
sendMessageButton = (Button) findViewById(R.id.sendMessageButton);
Bundle extras = this.getIntent().getExtras();
group.userName = extras.getString(InfoOfGroupMessage.FROM_USER);
group.groupName = extras.getString(InfoOfGroup.GROUPNAME);
group.groupId = extras.getString(InfoOfGroup.GROUPID);
String msg = extras.getString(InfoOfGroupMessage.GROUP_MESSAGE_TEXT);
setTitle("Group: " + group.groupName);
// Retrieve the information
localstoragehandler = new StorageManipulater(this);
dbCursor = localstoragehandler.groupGet(group.groupName);
if (dbCursor.getCount() > 0) {
// Probably where the magic happens, and keeps pulling the same
// thing
int noOfScorer = 0;
dbCursor.moveToFirst();
while ((!dbCursor.isAfterLast())
&& noOfScorer < dbCursor.getCount()) {
noOfScorer++;
}
}
localstoragehandler.close();
if (msg != null) {
// Then friends username and message, not equal to null, recieved
adapter.add(new OneComment(true, group.groupId + ": " + msg, "0", "0"));
adapter.notifyDataSetChanged();
((NotificationManager) getSystemService(NOTIFICATION_SERVICE))
.cancel((group.groupId + msg).hashCode());
}
// The send button
sendMessageButton.setOnClickListener(new OnClickListener() {
CharSequence message;
Handler handler = new Handler();
public void onClick(View arg0) {
message = editText1.getText();
if (message.length() > 0) {
// When general texting, the campaign and location will always be "0"
// Only through specials sharing is the user permitted to change the campaign and location to another value
adapter.add(new OneComment(false, imService.getUsername() + ": " + message.toString(), "0", "0"));
adapter.notifyDataSetChanged();
localstoragehandler.groupInsert(imService.getUsername(), group.groupName,
group.groupId, message.toString(), "0", "0");
// as msg sent, will blank out the text box so can write in
// again
editText1.setText("");
Thread thread = new Thread() {
public void run() {
try {
// JUST PUTTING "0" AS A PLACEHOLDER FOR CAMPAIGN AND LOCATION
// IN FUTURE WILL ACTUALLY ALLOW USER TO SHARE CAMPAIGNS
if (imService.sendGroupMessage(group.groupId,
group.groupName, message.toString(), "0", "0") == null) {
handler.post(new Runnable() {
public void run() {
Toast.makeText(
getApplicationContext(),
R.string.message_cannot_be_sent,
Toast.LENGTH_LONG).show();
// showDialog(MESSAGE_CANNOT_BE_SENT);
}
});
}
} catch (UnsupportedEncodingException e) {
Toast.makeText(getApplicationContext(),
R.string.message_cannot_be_sent,
Toast.LENGTH_LONG).show();
e.printStackTrace();
}
}
};
thread.start();
}
}
});
}
#Override
protected Dialog onCreateDialog(int id) {
int message = -1;
switch (id) {
case MESSAGE_CANNOT_BE_SENT:
message = R.string.message_cannot_be_sent;
break;
}
if (message == -1) {
return null;
} else {
return new AlertDialog.Builder(GroupMessaging.this)
.setMessage(message)
.setPositiveButton(R.string.OK,
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog,
int whichButton) {
/* User clicked OK so do some stuff */
}
}).create();
}
}
#Override
protected void onPause() {
super.onPause();
unregisterReceiver(groupMessageReceiver);
unbindService(mConnection);
ControllerOfGroup.setActiveGroup(null);
}
#Override
protected void onResume() {
super.onResume();
bindService(new Intent(GroupMessaging.this, MessagingService.class),
mConnection, Context.BIND_AUTO_CREATE);
IntentFilter i = new IntentFilter();
i.addAction(MessagingService.TAKE_GROUP_MESSAGE);
registerReceiver(groupMessageReceiver, i);
ControllerOfGroup.setActiveGroup(group.groupName);
}
// For receiving messages form other users...
public class GroupMessageReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
Bundle extra = intent.getExtras();
//Log.i("GroupMessaging Receiver ", "received group message");
String username = extra.getString(InfoOfGroupMessage.FROM_USER);
String groupRId = extra.getString(InfoOfGroupMessage.TO_GROUP_ID);
String message = extra
.getString(InfoOfGroupMessage.GROUP_MESSAGE_TEXT);
// NEED TO PLACE INTO THE MESSAGE VIEW!!
String received_campaign_id = extra.getString(InfoOfGroupMessage.CAMPAIGN_SHARED);
String received_location_id = extra.getString(InfoOfGroupMessage.LOCATION_SHARED);
// NEED TO INTEGRATE THIS INTO LOGIC ABOVE, SO IT MAKES SENSE
if (username != null && message != null) {
if (group.groupId.equals(groupRId)) {
adapter.add(new OneComment(true, username + ": " + message, received_campaign_id, received_location_id));
localstoragehandler
.groupInsert(username, groupname, groupRId, message, received_campaign_id, received_location_id);
Toast.makeText(getApplicationContext(), "received_campaign: " + received_campaign_id +
" received_location:" + received_location_id, Toast.LENGTH_LONG).show();
received_campaign_id = "0";
received_location_id = "0";
} else {
if (message.length() > 15) {
message = message.substring(0, 15);
}
Toast.makeText(GroupMessaging.this,
username + " says '" + message + "'",
Toast.LENGTH_SHORT).show();
}
}
}
}
;
// Build receiver object to accept messages
public GroupMessageReceiver groupMessageReceiver = new GroupMessageReceiver();
#Override
protected void onDestroy() {
super.onDestroy();
if (localstoragehandler != null) {
localstoragehandler.close();
}
if (dbCursor != null) {
dbCursor.close();
}
}
}
I have gone through your code and this is common problem with listview that images starts repeating itself. In your case I think you have assigned image to Imageview every if and else if condition but if none of the condition satisfy it uses the previous image.
I would suggest to debug the getview method and put break points on the setImageResource. I use volley for these image loading and it has a method called defaultImage so that if no url is there the image is going to get the default one. So add that default case and see if it works.
If any of the above point is not clear feel free to comment.

Categories

Resources