my app is fairly simple and always works IF my IOT device is up.
i need to load a popup and show the ReScan button on the toolbar if the device cannot be found.
the app preloads IPaddress="-" and loads 2 asyncTask(s)
one uses NsdManager.DiscoveryListener to find the mDNS name and loads the IP into IPaddress
this task watches to see IPaddress change and gets the presets from the device by JSON and sets up the UI or pops up the error dialog with instructions if not found.
MY PROBLEM:
when counter >= 15 , i show the "Rescan" Button on the toolbar with setMenuVisible() then popup the error dialog but when the button in the dialog is pressed to close the dialog, the "Rescan" Button disappears again.
Also times out in about 5 seconds.
how do i get the "Rescan" Button to stay?
.
private class getSettingsFromClock extends AsyncTask<Void, Void, Void> {
#Override
protected Void doInBackground(Void... params) {
String mlooper = IPaddress;
Log.i(TAG, "LOG getSettingsFromClock doInBackground started ");
int counter = 0;
while ( mlooper.equals("-") ) {
mlooper = IPaddress;
try {
Thread.sleep(600);
} catch (InterruptedException e) {
e.printStackTrace();
}
counter++;
if (counter >= 15) // in normal operation counter never goes above 3
{
Log.i(TAG, "LOG getSettingsFromClock - NO IP Found, count= " + counter );
runOnUiThread(new Runnable() {
#Override
public void run() {
setMenuVisible( true, R.id.action_rescan); // show rescan button on toolbar
try { // delay is debugging only
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
//scanning failed Popup Dialog
final Dialog dialog = new Dialog(context );
dialog.setContentView(R.layout.popup);
dialog.setTitle("Scan Error");
Button button = dialog.findViewById(R.id.Button01);
button.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View view) {
dialog.dismiss();
}
});
dialog.show();
Toast.makeText(getApplicationContext(),
"Could Not get presets from clock. \n check Clock is on and on WiFi\n and reload app.",
Toast.LENGTH_LONG).show();
}
});
break;
}
}
if( IPaddress != "-" )
{
// gets JSON here
} else
{
// add popup - IOT Not found
}
// JSON starts here
if (JSON_return != null) {
try {
// loads presets from JSON to UI here
} catch (final JSONException e) {
Log.e(TAG, "LOG, JSON parsing error: " + e.getMessage());
}
} else
{
Log.e(TAG, "LOG, Could Not get JSON from Clock.");
}
return null;
}
} // end asyncTask class
// remember to run on main thread
// NOTE; private Menu option_Menu; declared in MainActivity
// ie; setMenuVisible( true, R.id.action_rescan);
public void setMenuVisible(boolean visible, int id) {
if (option_Menu != null) {
option_Menu.findItem(id).setVisible(visible);
}
}
Mike M. had it, Thank You Mike
added onPrepareOptionsMenu()
added showRescan = visible; and invalidateOptionsMenu(); to setMenuVisible()
all work perfectly now.
#Override
public boolean onPrepareOptionsMenu(Menu menu) {
super.onPrepareOptionsMenu(menu);
try {
if( showRescan )
{
option_Menu.findItem(R.id.action_rescan).setVisible( true );
} else
{
option_Menu.findItem(R.id.action_rescan).setVisible( false );
}
}
catch(Exception e) {
Log.e(TAG, "onPrepareOptionsMenu error");
}
return true;
}
// when task is completed you can show your menu just by calling this method
// remember to run on main thread
// ie; setMenuVisible( true, R.id.action_rescan);
public void setMenuVisible(boolean visible, int id) {
if (option_Menu != null) {
option_Menu.findItem(id).setVisible(visible);
showRescan = visible;
invalidateOptionsMenu();
}
}
Related
Not sure how should I phrase it, but In my app sometimes a single button click generates multiple events and hence it ends up sending multiple similar transactions to the server which is causing data integrity problem. Here is the code flow, Do note that this code runs on users phone which may have weaker connections at times, hence I store the data in SQLite and there is a separate sync service which sends data (fetching from SQLite tables) to Server when Internet is connected.
This is where the click is captured and event is posted for Main Activity (Landing Page)
#OnClick(R.id.btn_add_attempt)
public void onAttemptClick() {
try{
btnAddAttempt.setEnabled(false);
EventBus.getDefault().post(new ExampleActionEvent());
moveToHomePage();
} catch (Exception e){
e.printStackTrace();
Crashlytics.logException(e);
}
}
Here is the Event subscription from my main Activity.
#Subscribe()
public void onExampleAction(ExampleActionEvent exampleActionEvent)
{
if(application == null) application = (ExApplication) getApplication();
final Thread thread = new Thread(new Runnable() {
#Override
public void run() {
ArrayList<Something> somethings = application.getArray().getsomethings();
if (!ExUtils.validatesomethings(somethings)){
runOnUiThread(new Runnable() {
#Override
public void run() {
RiderUtils.showSimplePopup(
MainLandingActivity.this,
getString(R.string.title_alert),
getString(R.string.alert_message),
getString(R.string.done),
null,
false,
new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
showPendingSomething();
ExUtils.moveToPending(MainLandingActivity.this);
}
},
null,
false);
}
});
return;
}
status = application.getArray().getStatus();
imageLocalPath = application.getArray().getsomethings().get(0).getPhotoPath();
Log.d(Const.TAG, "image path is: "+imageLocalPath);
try {
ExUtils.pushExampleActionEvent(application.getArray(), MainLandingActivity.this, xyz, abc);
} catch (Exception e) {
e.printStackTrace();
}
FileWriteEvent fileWriteEvent = null;
String currentTimestamp = application.getArray().getTimestamp();
switch (status) {
case Const.UPDATE_SUCCESS:
fileWriteEvent = new FileWriteEvent(Const.EVENT_CSV_FILE_SUCCESS_VALUE, application.getArray(), "",
cachedLocation, currentTimestamp, null);
break;
case Const.UPDATE_ATTEMPTED:
fileWriteEvent = new FileWriteEvent(Const.EVENT_CSV_FILE_ATTEMPTED_VALUE, riderApplication.getBulkArray(), "",
cachedLocation, currentTimestamp, null);
ExUtils.showSnackbar(holder, getString(R.string.Example), Snackbar.LENGTH_LONG);
break;
}
if(fileWriteEvent != null)
{
EventBus.getDefault().post(fileWriteEvent);
}
createAll(); //SQLite DB call for Inserting some data
runOnUiThread(new Runnable() {
#Override
public void run() {
try {
switch (status) {
case Const.UPDATE_SUCCESS:
RiderUtils.showSnackbar(holder, getString(R.string.Success), Snackbar.LENGTH_LONG);
break;
case Const.UPDATE_ATTEMPTED:
RiderUtils.showSnackbar(holder, getString(R.string.Failed), Snackbar.LENGTH_LONG);
break;
}
}catch (Exception e) {
e.printStackTrace();
}
}
});
}
});
thread.start();
}
I am not able to figure out why is it misbehaving sometimes randomly otherwise it runs smoothly, Hence I am not able to regenrate the issue while debugging.
So after sometimes I looked at the problem again and found out the developer who worked before me had not declared the Main Activity as SingleInstance and hence Every time if the app was opened from Notification Drawer as we were showing it in Notification drawer if app is running, then it was creating a new Activity hence registering on EventBus which was causing the issue by creating duplicate events.
Here is my code:
automaticCountryButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
progressBar.setVisibility(View.VISIBLE);
if (ContextCompat.checkSelfPermission(HomeActivity.this,
Manifest.permission.ACCESS_FINE_LOCATION)
!= PackageManager.PERMISSION_GRANTED){
setUpLocationPermission();
return;
}
Log.d(TAG, String.valueOf(gps.canGetLocation()));
Log.d(TAG, String.valueOf(gps.getLocation()));
Log.d(TAG, String.valueOf(gps.getLatitude()));
Log.d(TAG, String.valueOf(gps.getLongitude()));
Geocoder myLocation = new Geocoder(HomeActivity.this);
try
{
myList = myLocation.getFromLocation(gps.getLatitude(), gps.getLongitude(), 1);
}
catch (Exception e)
{
Log.d(TAG, "unable");
e.printStackTrace();
}
if(myList != null) {
try {
String country = myList.get(0).getCountryName();
Log.d(TAG, country);
findCountryInArrayList(country);
}
catch (Exception e)
{
Toast.makeText(HomeActivity.this, "Didn't manage to automatically detect location.", Toast.LENGTH_SHORT).show();
e.printStackTrace();
}
}
}
});
}
I want that immediately after the view is clicked the progressbar will become visible. However, it donesn't become visable until all the code is finished, which is against the whole point.
WHy is this not happening right at the beginning of the click? I have put progressBar.setVisibility(View.VISIBLE) at the top, why is it only executed after all the code is done, which sometimes takes a few seconds.
Thanks very much.
This is because you are trying to do your work on the UI thread - the UI will not actually be updated at all until this method finishes.
Try changing up your call to this:
public void onClick(View view) {
progressBar.setVisibility(View.VISIBLE);
progressBar.post( new Runnable() {
public void run() {
// long running code that has UI interactions
}
});
}
This will show the view immediately, and submit the runnable - long running task - to the message queue; this task will be run on a background thread that can still manipulate the UI, but will not cause it to hang.
i am trying to display a Toast on the screen and when Toast fades off then move to the next question. I have tried with Thread but cannot seem to manage.
My code:
next.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (getUserSelection()){
position = position + 3;
if (position < questionsArray.size()) {
curName = questionsArray.get(position).getName();
curArray = questionsArray.get(position).getAnswers();
curIscorrect = questionsArray.get(position).getIscorrect();
setupQuestionView(curName, curArray, curIscorrect);
} else {
StringGenerator.showToast(QuestionsActivity.this, "Your score : " + score + "/" + (questionsArray.size() / 3));
}
}else {
StringGenerator.showToast(QuestionsActivity.this, getString(R.string.noanswerselected));
}
}
});
and the getUserSelectionMethod:
private boolean getUserSelection() {
correct = (RadioButton)findViewById(group.getCheckedRadioButtonId());
if (correct == null){
return false;
}else {
correctAnswerText = correct.getText().toString();
if (map.get(correctAnswerText).equals(Constants.CORRECTANSWER)) {
score++;
setCorrectMessage();
return true;
} else {
setWrongMessage();
return true;
}
}
}
private void setCorrectMessage() {
correctToast = new Toast(QuestionsActivity.this);
correctToastView = getLayoutInflater().inflate(R.layout.correct, (ViewGroup) findViewById(R.id.correctRootLayout));
correctText = (TextView)correctToastView.findViewById(R.id.correctTextView);
correctText.setText(getString(R.string.correctAnswer));
correctToast.setDuration(Toast.LENGTH_SHORT);
correctToast.setView(correctToastView);
correctToast.show();
correctThread = new Thread(new Runnable() {
#Override
public void run() {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
correctToast.cancel();
}
});
correctThread.start();
}
private void setWrongMessage() {
wrongToast = new Toast(QuestionsActivity.this);
wrongToastView = getLayoutInflater().inflate(R.layout.wrong, (ViewGroup) findViewById(R.id.wrongRootLayout));
wrongText = (TextView)wrongToastView.findViewById(R.id.wrongTextView);
wrongText.setText(getString(R.string.wrongAnswer));
wrongToast.setDuration(Toast.LENGTH_SHORT);
wrongToast.setView(wrongToastView);
wrongToast.show();
wrongThread = new Thread(new Runnable() {
#Override
public void run() {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
wrongToast.cancel();
}
});
wrongThread.start();
}
Any suggestion on how to do this?
You can determine the toast visibility:
toast.getView().getWindowToken()
If the result is null, than your toast isn't visible anymore, and than you can run any code you want.
as stated in this answer you can start a thread that waits the duration of the Toast:
Thread thread = new Thread(){
#Override
public void run() {
try {
Thread.sleep(3500); // 3.5seconds!
// Do the stuff you want to be done after the Toast disappeared
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
Toast.LENGTH_SHORT and Toast.LENGTH_LONG are only flags so you have to either hard code the duration or keep them in a constant. The durations are 3.5s (long) and 2s (short).
If you want to manipulate some of your views, you cannot do this in another thread than the "main" UI thread. So you have to implement a kind of callback/polling mechanism to get notified when the SleepThread has finished.
Check this answer to read about a couple of ways to do this. Probably the easiest of them to understand and implement is this:
After you started your Thread you can check if it is still alive and running by calling thread.isAlive(). In this way you can do a while loop that runs while the thread is running:
// start your thread
while(thread.isAlive()){}
// continue the work. The other thread has finished.
Please note that this is NOT the most elegant way to do this! Check the other possibilities in the answer I've mentioned above for more elegant solutions (especially the last one with the listeners is very interesting and worth reading!)
That's because the Thread class is purely executed in the background and you need to manipulate the view in the Main thread. To solve your issue just replace the Thread with AsynTask.
AsyncTask<Void,Void,Void> a = new AsyncTask<Void, Void, Void>() {
#Override
protected Void doInBackground(Void... params) {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
return null;
}
#Override
protected void onPostExecute(Void aVoid) {
super.onPostExecute(aVoid);
correctToast.cancel();
}
};
a.execute();
If you look at my code you can see my onPostExecute, this method is called in the Main Thread.
My Error was because i was trying to acess UI Elements through another Thread so modifying the code like this:
Thread thread = new Thread(new Runnable() {
#Override
public void run() {
try {
Thread.sleep(500);
QuestionsActivity.this.runOnUiThread(new Runnable() {
#Override
public void run() {
moveToNextQuestion();
}
});
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
thread.start();
did the trick. I hope my answer helps someone!!!
I have two objects, a establishment object that belongs to a deal object that can be voted upon. If I up/down vote the same deal multiple times, the seventh time I vote the query just sits and does not do anything. The app does not crash, but it also does not save. If I go into another activity that requires a parse.com query that query also will not work. Here is my up vote logic (down voting is identical).
Assume all vars used are initialized before onCreate().
Are my queries getting backed up in a pipe somewhere?
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
upVoteButton = (Button) findViewById(R.id.deal_up_vote_button);
upVoteButton.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View arg0) {
new UpVoteTask().execute();
}
});
}
// visually changes buttons if they are selected
private void setButtons(Boolean queryDb) {
if (queryDb == true) {
queryParse();
}
// if deal found correctly
if (deal != null) {
// if user found correctly
if (dealVoteUser != null) {
if (dealVoteUser.get("vote").toString().equals("0")) {
upVoteButton.setPressed(false);
downVoteButton.setPressed(true);
} else if (dealVoteUser.get("vote").toString().equals("1")) {
upVoteButton.setPressed(true);
downVoteButton.setPressed(false);
} else if (dealVoteUser.get("vote").toString().equals("2")) {
upVoteButton.setPressed(false);
downVoteButton.setPressed(false);
}
}
}
}
// queries parse and populates vars
private void queryParse(){
ParseQuery<ParseObject> queryDeal = ParseQuery.getQuery("Deal");
queryDeal.whereEqualTo("objectId", deal_id);
try {
deal = queryDeal.getFirst();
} catch (ParseException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
ParseQuery<ParseObject> queryDealVoteUser = ParseQuery
.getQuery("deal_vote_users");
queryDealVoteUser.whereEqualTo("deal", deal).whereEqualTo("user",
ParseUser.getCurrentUser());
try {
dealVoteUser = queryDealVoteUser.getFirst();
} catch (ParseException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
// UpVoteTask AsyncTask
private class UpVoteTask extends AsyncTask<Void, Void, Void> {
#Override
protected void onPreExecute() {
super.onPreExecute();
// Create a progressdialog
if(upVoteProgressDialog != null){
upVoteProgressDialog.dismiss();
upVoteProgressDialog = null;
}
upVoteProgressDialog = new ProgressDialog(DealsDetailsActivity.this);
// Set progressdialog message
upVoteProgressDialog.setMessage("Saving...");
upVoteProgressDialog.setIndeterminate(false);
// Show progressdialog
upVoteProgressDialog.show();
}
#Override
protected Void doInBackground(Void... params) {
queryParse();
// if deal found correctly
if (deal != null) {
// if user has not voted yet
if (dealVoteUser == null) {
// create new and assign vote to 1
dealVoteUser = new ParseObject("deal_vote_users");
dealVoteUser.put("deal", deal);
dealVoteUser.put("user", ParseUser.getCurrentUser());
dealVoteUser.put("vote", 1);
up_votes = deal.getInt("up_votes") + 1;
down_votes = deal.getInt("down_votes");
// if user already down voted
} else if (dealVoteUser.get("vote").toString().equals("0")) {
// change vote to 1
dealVoteUser.put("vote", 1);
up_votes = deal.getInt("up_votes") + 1;
down_votes = deal.getInt("down_votes") - 1;
// if user already up voted
} else if (dealVoteUser.get("vote").toString().equals("1")) {
// already voted up, remove vote
dealVoteUser.put("vote", 2);
up_votes = deal.getInt("up_votes") - 1;
down_votes = deal.getInt("down_votes");
// if user already voted but cleared vote
} else if (dealVoteUser.get("vote").toString().equals("2")) {
// change vote to 1
dealVoteUser.put("vote", 1);
up_votes = deal.getInt("up_votes") + 1;
down_votes = deal.getInt("down_votes");
}
// calculate overall rating percentage
if ((up_votes + down_votes) != 0) {
rating = (up_votes / (up_votes + down_votes)) * 100;
} else if ((up_votes == 0) && (down_votes == 0)) {
rating = 0;
} else {
rating = 50;
}
deal.put("rating", rating);
deal.put("up_votes", up_votes);
try {
deal.save();
} catch (ParseException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try {
dealVoteUser.save();
} catch (ParseException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} else {
// deal not found problem
}
return null;
}
#Override
protected void onPostExecute(Void result) {
// visually change buttons without querying db
setButtons(false);
//remove progress dialogue
if(upVoteProgressDialog != null){
upVoteProgressDialog.dismiss();
upVoteProgressDialog = null;
}
}
}
Use the saveInBackground method - it will do the same as save, but also save it to your application's cache so that you won't get different values while the data is being saved, so it won't have any apparent effect on your application. It's the best method to save or find (it has a 'sister' method named findInBackground). It acts like an Async task and does not clog your main thread.
I switched all parse calls over to ._____InBackground() and I moved the save logic to onPause(). This way I am not making multiple save calls to parse if the user decides to change their vote multiple times.
i have created one simple login application which takes user name and password from sqlserver..it works fine...
i want during login process one progeress bar should be displayed using asyntask...
but i am unaware to use parameters in asyntask...if some one plzz tell me how to put my method in doInbackground of asyntask and what param should i use....
my code is;.....
public void save(){
initilize();
ResultSet rs = null;
String mylog=id.getText().toString();
String mypass=pass.getText().toString();
try{
Statement statement=connect.createStatement();
rs=statement.executeQuery("LOGIN '"+mylog+"', '"+mypass+"'");
}catch(Exception e){
e.printStackTrace();
}
if(mylog.equals("")||mypass.equals("")){
Toast.makeText(getApplicationContext(), "empty fields", Toast.LENGTH_SHORT).show();
} else
try {
if(rs.next()){
Intent i=new Intent(getApplicationContext(),Act2.class);
startActivity(i);
}
else if(rs.next()==false){
Toast.makeText(getApplicationContext(), "incorrect login", Toast.LENGTH_SHORT).show();
id.setText("");
pass.setText("");
}
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
if it is possible that same method save() be kept inside doInbackground() of asyntask...
making a fast refactorization (note that this as it stand it's really bad practice and coding, you MUST refactor this code to be more maintanable and to avoid duplication):
public class MyAsyncTask extends AsyncTask<> {
private Activity activity;
boolean result;
private String myLog;
private String myPass;
private Connection connect;
public MyAsyncTask(Activity activity, Connection connect) {
this.activity = activity;
this.connect = connect;
}
#Override
protected void onPreExecute() {
//show your progress dialog
}
#Override
protected Object doInBackground(Object[] objects) {
ResultSet rs = null;
activity.runOnUiThread(new Runnable() {
#Override
public void run() {
initilize();
mylog=id.getText().toString();
mypass=pass.getText().toString();
}
});
try{
Statement statement=connect.createStatement();
rs=statement.executeQuery("LOGIN '"+mylog+"', '"+mypass+"'");
}catch(Exception e){
e.printStackTrace();
}
if(mylog.equals("")||mypass.equals("")){
activity.runOnUiThread(new Runnable() {
#Override
public void run() {
Toast.makeText(activity.getApplicationContext(), "empty fields", Toast.LENGTH_SHORT).show();
}
});
} else
try {
if(rs.next()){
result = true;
}
else if(rs.next()==false){
activity.runOnUiThread(new Runnable() {
#Override
public void run() {
Toast.makeText(activity.getApplicationContext(), "incorrect login", Toast.LENGTH_SHORT).show();
id.setText("");
pass.setText("");
}
});
}
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
#Override
protected void onPostExecute(Object o) {
//hide your progress dialog
if(result == Boolean.TRUE){
activity.runOnUiThread(new Runnable() {
#Override
public void run() {
Intent i=new Intent(activity.getApplicationContext(),Act2.class);
activity.startActivity(i);
}
});
}
}
}
then in your Activity you do this:
MyAsyncTask a = new MyAsyncTask(this, connect); //im guessing "connect" is your Connection object
a.execute();
As i said i made this fast refactoring for the code to work but best practice and good implementation is not in consideration here.
Maybe, you could use a timer, to check if your
login is ready. As long as it is not, you Show your progress Bar. If its ready, you can close the Bar and start a new activity or anything. timers run can run on u UI thread.
regards :)