Cancel an operation on Toast - java

I wrote a JSoup HTML scraping class for my Android project. This custom class puts the user-inputted zip code into the constructor, and would parse that HTML. It works in an asynchronous thread from my main thread. Since there is no right way to deal with incorrect zip codes, I had check for null in a particular element, specifically:
if(doc.select("div.columns").first().text() == null)
{
((Activity) context).runOnUiThread(new Runnable() {
public void run()
{
Toast toast = Toast.makeText(context, R.string.toast_parse_fail, Toast.LENGTH_LONG);
toast.show();
return;
}
});
}
If that particular element is null (meaning that no such data exists for this zip code), it would create a toast to the user. As to why try wouldn't work in this case, it is because JSoup and Java doesn't know whether the parse failed or not, since the web page still loads fine; only, there is no data, which would crash the app from a NullPointerException from the code following it.
Despite my Toast exception handling using .runOnUiThread, my app would still crash. Is there any particular methods that would cancel the operations that follow my null-checking method? I know I am crashing because Toast is not cancelling my operations, and is preceding to execute the following code which causes my NullPointerExceptions.
Posted is my full Pollen constructor.
public Pollen(int zipcode, final Context context)
{
this.context = context;
this.zipcode = zipcode;
Document doc;
try
{
// pass address to Wunderground's website using our inputted zipcode
doc = Jsoup.connect("http://www.wunderground.com/DisplayPollen.asp?Zipcode=" + this.zipcode).get();
if(doc.select("div.columns").first().text() == null)
{
((Activity) context).runOnUiThread(new Runnable() {
public void run()
{
Toast toast = Toast.makeText(context, R.string.toast_parse_fail, Toast.LENGTH_LONG);
toast.show();
return;
}
});
}
// get "location" from XML
Element location = doc.select("div.columns").first();
this.location = location.text();
// get "pollen type" from XML
Element pollenType = doc.select("div.panel h3").first();
this.pollenType = pollenType.text();
SimpleDateFormat format = new SimpleDateFormat("EEE MMMM dd, yyyy");
// add the four items of pollen and dates
// to its respective list
for(int i = 0; i < 4; i++)
{
Element dates = doc.select("td.text-center.even-four").get(i);
Element levels = doc.select("td.levels").get(i);
try
{
pollenMap.put(format.parse(dates.text()), levels.text());
}
catch (ParseException e)
{
((Activity) context).runOnUiThread(new Runnable() {
public void run()
{
Toast toast = Toast.makeText(context, R.string.toast_parse_fail, Toast.LENGTH_LONG);
toast.show();
return;
}
});
}
}
}
catch (IOException e)
{
((Activity) context).runOnUiThread(new Runnable() {
public void run()
{
Toast toast = Toast.makeText(context, R.string.toast_parse_fail, Toast.LENGTH_LONG);
toast.show();
return;
}
});
}
}
tl;dr I still want the Toast to show - but I want on-Toast, to cancel all operations that follow it, since I know that if this particular Toast shows, if the code following it executes, it would crash the app.

Since you already in a try-catch-block, can't you just throw an exception?
public Pollen(int zipcode, final Context context) {
this.context = context;
this.zipcode = zipcode;
Document doc;
try {
// pass address to Wunderground's website using our inputted zipcode
doc = Jsoup.connect("http://www.wunderground.com/DisplayPollen.asp?Zipcode=" + this.zipcode).get();
if(doc.select("div.columns").first().text() == null) {
// Oh no! div.colums is empty. Lets throw an exception, which
// will prevent the code below from executing.
throw new IllegalStateException("div.columns is NULL");
}
// get "location" from XML
Element location = doc.select("div.columns").first();
this.location = location.text();
// get "pollen type" from XML
Element pollenType = doc.select("div.panel h3").first();
this.pollenType = pollenType.text();
SimpleDateFormat format = new SimpleDateFormat("EEE MMMM dd, yyyy");
// add the four items of pollen and dates
// to its respective list
for(int i = 0; i < 4; i++) {
Element dates = doc.select("td.text-center.even-four").get(i);
Element levels = doc.select("td.levels").get(i);
// Removed nested try-catch block
pollenMap.put(format.parse(dates.text()), levels.text());
}
} catch (IOException e) {
displayToast(context);
} catch (ParseException e) {
// We catch the ParseException here instead of nesting try-catch blocks.
displayToast(context);
} catch (IllegalStateException e) {
// Catch the IllegalStateException thrown when div.columns was null,
// and let the user know what went wrong.
displayToast(context);
}
}
private void displayToast(Context context) {
((Activity) context).runOnUiThread(new Runnable() {
public void run() {
Toast toast = Toast.makeText(context, R.string.toast_parse_fail, Toast.LENGTH_LONG);
toast.show();
}
});
}

Related

Why not update UI elemnts in Android

In my application i should used socket.io and i want when receive my event update UI elements!
I write below codes and i receive my events show me logs, but not update any UI!
I want when receive event, check this winner is user or not and then update my UI.
In logCat show me my logs but not update any UI elements!
My codes:
public void onsocketFinishRecieve(final JSONObject ob) {
try {
((BaseActivity) context).runOnUiThread(() -> {
try {
cancelTimer();
final FinishResponse finishResponse = new Gson().fromJson(ob.toString(), FinishResponse.class);
if (finishResponse.getRes().getWinnerName().equals("not user") || finishResponse.getRes().getWinnerName().equals("not winner")) {
winnerNameWhenFinished = "Not winner";
} else {
winnerNameWhenFinished = finishResponse.getRes().getWinnerName();
}
if (detail.getId() != null) {
if (detail.getId() == finishResponse.getRes().getId()) {
//Set new winner layouts
//Register in auction
if (Constants.profileResponse != null) {
if (Constants.profileResponse.getRes() != null) {
if (Constants.profileResponse.getRes().getUser() != null) {
//Winner
if (Constants.profileResponse.getRes().getUser().getId().equals(finishResponse.getRes().getUserId())) {
Log.e("FinishedSocket", "1");
detailPage_bottomWinnerRateTxt.setVisibility(View.GONE);
detailPage_bottomWinnerBuyTxt.setText("Show basket");
detailPage_bottomWinnerBuyTxt.setOnClickListener(v -> {
Intent intent = new Intent(context, MainActivity.class);
intent.putExtra("OPEN_CART_IN_MAIN", "true");
startActivity(intent);
});
} else {
Log.e("FinishedSocket", "2");
//Loser
detailPage_bottomWinnerBuyTxt.setText("Awesome offers");
}
}
}
}
}
}
} catch (Exception e) {
Log.e("DetailResErr", e.getMessage());
}
});
} catch (Exception e) {
Log.e("DetailResErr", e.getMessage());
}
}
Logcat message :
2020-03-08 13:37:37.399 E/FinishedSocket: 2
In logcat show me above message , why not run this line : detailPage_bottomWinnerBuyTxt.setText("Awesome offers"); ??
How can i fix it?
try to run this on Mainthread like this.
someActivity.runOnUiThread(new Runnable() {
#Override
public void run() {
//Your code to run in GUI thread here
detailPage_bottomWinnerBuyTxt.setText("Awesome offers");
}
});
Sockets work on IOThread while other side UI Work on separate Thread called UI thread. So, update the UI element on UI Thread.
Use Annotation :
#UiThread
public abstract void setText(#NonNull String text) { ... }
For know about more annotation, Check the following blog:
https://medium.com/#gurwindersingh_37022/android-annotations-30b4a2850d0

Send string from thread bluetooth service to textView in main activity

I want to send value from string (distance to obstacle) to my TextView in main activity.
I tried to use Handler, but still not working (crash) or receive nothing.
A part code which receive data from HC-05 (screen where you see in debug value assignet to variable)
enter image description here
#Override
public void run() {
byte[] buffer = new byte[1024];
int bytes;
while(true){
try {
bytes = inputStream.read(buffer);
final String comingMsg = new String(buffer,0,bytes);
Log.d(TAG,"InputStream: " + comingMsg);
/*mHandler2.post(new Runnable() {
#Override
public void run() {
Message message = new Message();
message.obj = comingMsg;
mHandler2.sendMessage(message);
}
});*/
}catch (IOException e){
Log.e(TAG,"Write: Error reading input." + e.getMessage());
active=false;
break;
}
}
}
Here It's parts of code from MainActivity where I tried put something to get values from service.
[I add, that for this moment i want to see something values from bluetooth in textView. Later I want to create parse string and send custom text to custom TextView - example: FL: (Front Left)- to one textView, FR: (Front Right) - to second textView]
There is method implementThreads(), because I wanted to do 6 Threads to 6 TextView which every time is refreshing value from string in Services (there I tried get value from Bluetooth Service)
Log.d(TAG,"Check intent - result");
if(getIntent().getIntExtra("result",0)==RESULT_OK){
mDevice = getIntent().getExtras().getParcelable("bonded device");
myBluetoothService = new MyBluetoothService(getApplicationContext());
startConnection(mDevice,MY_UUID);
Log.d(TAG,"Check is active service");
checkIfActive();
}
Log.d(TAG,"Check intent - connect_to_paired");
if(getIntent().getIntExtra("connect_to_paired",0)==RESULT_OK){
mDevice = getIntent().getExtras().getParcelable("bonded_paired_device");
myBluetoothService = new MyBluetoothService(getApplicationContext());
startConnection(mDevice,MY_UUID);
Log.d(TAG,"Check is active service");
checkIfActive();
}
}
#Override
public void onStart(){
super.onStart();
myBluetoothService = new MyBluetoothService(getApplicationContext());
}
public void checkIfActive(){
Log.d(TAG,"CheckIfActive: Started");
if(myBluetoothService.active){
Log.d(TAG,"CheckIfActive: Running method implementThreads()");
implementThreads();
}
}
public void implementThreads(){
Log.d(TAG,"ImplementThreads: Started");
Thread thread = new Thread(){
#Override
public void run() {
try{
sleep(100);
}catch (InterruptedException e){
e.printStackTrace();
}
}
};
thread.start();
}
public void startConnection(BluetoothDevice device,UUID uuid){
Log.d(TAG,"StartConnection: Initializing connection");
myBluetoothService.startClient(device,uuid);
}
Thanks all for help, because It's very important for me !
Use this to interect with UI Thread for operations like updating textviews etc.
new Handler(Looper.getMainLooper()).post(new Runnable() {
#Override
public void run() {
//YOUR CODE HERE
Message message = new Message();
message.obj = comingMsg;
mHandler2.sendMessage(message);
}
});

Application Stop when input editText more than 10 digit

i am trying to show calculation textView(txtHasil) it is running but when input more than 10 application suddenly force close. this is my code:
btnHitung.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
//String plafond = NumberTextWatcherForThousand.trimCommaOfString(edtPlafond.getText().toString());
String plafond = edtPlafond.getText().toString().trim();
String jasa = edtJasa.getText().toString().trim();
int edtPlafond = Integer.parseInt(plafond);
float edtJasa = Float.parseFloat(jasa);
double hasil = (edtPlafond * edtJasa )/100;
txtHasil.setText(""+hasil+"\nplafond: "+edtPlafond+"\nJasa: "+edtJasa);
//txtHasil.addTextChangedListener(new NumberTextWatcherForThousand((EditText) txtHasil));
}
}
i have been try change int,float, and double. i have been read this link: This program doesn't work properly for decimals more than 10 digits? but didn't help. any suggest will be help. thanks
Integer.parseInt(plafond);
This is the problem.It can not parse anythong larger than Integer.MAX_VALUE
int edtPlafond;
try {
edtPlafond = Integer.parseInt(plafond);
} catch (NumberFormatException e ) {
e.printStackTrace();
// add proper error handling
}
The best would be to have a longer value - long...
long edtPlafond;
try {
edtPlafond = Long.parseLong(plafond);
} catch (NumberFormatException e ) {
e.printStackTrace();
// add proper error handling
}
And an example of handling the error in a better way, by displaying the error in a dialog:
} catch (NumberFormatException e ) {
new AlertDialog.Builder(getActivity())
.setTitle("Error: incorrect number entered!")
.setMessage("The exact error is: " + e.getMessage())
.setPositiveButton("Ok",
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int b) {
dialog.cancel();
}
});
.create()
.show();
}
Note: all conversions need such a treatment...

Using Toast to deal with exception outside of my Fragment class

Currently creating an Android app. I have a class called Pollen, on top of my Fragment class, and I am dealing with exception handling within this second class.
Here is my Pollen class.
public static class Pollen
{
#SuppressLint("SimpleDateFormat")
public Pollen(int zipcode, Context context)
{
this.context = context;
this.zipcode = zipcode;
Document doc;
try
{
// pass address to
doc = Jsoup.connect("http://www.wunderground.com/DisplayPollen.asp?Zipcode=" + this.zipcode).get();
// get "location" from XML
Element location = doc.select("div.columns").first();
this.location = location.text();
// get "pollen type" from XML
Element pollenType = doc.select("div.panel h3").first();
this.pollenType = pollenType.text();
SimpleDateFormat format = new SimpleDateFormat("EEE MMMM dd, yyyy");
// add the four items of pollen and dates
// to its respective list
for(int i = 0; i < 4; i++)
{
Element dates = doc.select("td.text-center.even-four").get(i);
Element levels = doc.select("td.levels").get(i);
try
{
pollenMap.put(format.parse(dates.text()), levels.text());
}
catch (ParseException e)
{
Toast toast = Toast.makeText(context, R.string.toast_parse_fail, Toast.LENGTH_LONG);
toast.show();
return;
}
}
}
catch (IOException e)
{
Toast toast = Toast.makeText(context, R.string.toast_parse_fail, Toast.LENGTH_LONG);
toast.show();
return;
}
}
}
Since Pollen uses Network tasks, it's under an asynchronous thread which is irrelevant to this question.
Whenever Pollen is met under an exception, despite the Toast, the app would crash.
I was wondering - what is the accepted way to deal with exception on classes outside of the main class?
Your application is crashing because you are creating a toast from outsied the UI thread.
You cannot create a Toast from a class which is not running on the main thread(UI thread). But you can use the runOnUiThread (http://developer.android.com/reference/android/app/Activity.html#runOnUiThread(java.lang.Runnable)) to execute code on the UI thread from your Pollen class.
YourActivity.this.runOnUiThread(new Runnable() {
public void run() {
Toast toast = Toast.makeText(YourActivity.this, R.string.toast_parse_fail, Toast.LENGTH_LONG);
toast.show();
}
});
For this to work you have to pass the Activity's context to you custom class and use the above method or you can throw exception and catch it from the activity and handle it there.

Listing of the Network Devices in Android

Similar or the same Question has been answered here
I am creating an Android App, which sends a broadcast message to the network and prepares a list of devices responding back.
Now What I did:
I created an Activity Class DeviceManagerWindow.java which calls a thread Sender.java.
Sender.java is responsible for sending the broadcast message.
Then the DeviceManagerWindow.java calls another thread which is responsible for listening to the devices responding back. The devices responding back will be listed in the Activity as soon as the device responds back. For that I have a TableLayout named deviceList.
What code I have written:
DeviceManagerWindow.java This method is called when a button for search is pressed
public void searchDevice(View v) throws IOException, InterruptedException
{
//Log.v("TableLayout:",view.toString());
sendMulticastFlyport = new Thread(new FlyportSender(MAC));
sendMulticastFlyport.start();
new Thread()
{
public void run()
{
MulticastSocket socketComputer=null;
try
{
socketComputer = new MulticastSocket(WifiConstants.COMPUTER_RECV_PORT);
socketComputer.joinGroup(InetAddress.getByName(WifiConstants.COMPUTER_NETWORK_ADDR));
socketComputer.setSoTimeout(1*60*1000);
byte[] inBufComputer = new byte[1024];
DatagramPacket inPacketComputer = new DatagramPacket(inBufComputer, inBufComputer.length);
while(true)
{
System.out.println("Listening...");
socketComputer.receive(inPacketComputer);
System.out.println("Received");
String msg = new String(inBufComputer, 0, inPacketComputer.getLength());
DeviceInformation device = new DeviceInformation(1, msg, inPacketComputer.getAddress().toString());
addDevice(device, false, 1);
Log.v("Received:","Received Computer From :" + inPacketComputer.getAddress() + " Msg : " + msg);
//System.out.write(inPacket.getData(),0,inPacket.getLength());
System.out.println();
Thread.sleep(2000);
}
}
catch(Exception e)
{
Log.v("Exception:","During Receiving Computer: "+e.toString());
try
{
addDevice(null, true, 1);
}
catch (IOException e1)
{
Log.v("Exception:", "Computer End Error: " +e1);
}
}
finally
{
socketComputer.close();
}
}
}.start();
The following code creates a list:
public void addDevice(DeviceInformation device, boolean bool, int type) throws IOException
{
TableLayout tb = (TableLayout) findViewById(R.id.DeviceList);
Log.v("addDevice","Called");
if(bool)
{
LayoutParams layout = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
TableRow tr = new TableRow(getApplicationContext());
TextView tv = new TextView(getApplicationContext());
System.out.println(tb);
tv.setLayoutParams(layout);
tr.setLayoutParams(layout);
String message;
Log.v("addDevice","Device Timeout");
switch(type)
{
case 1:
computerEnd=true;
break;
case 2:
raspberryEnd=true;
break;
case 3:
flyportEnd=true;
break;
}
if(computerEnd && raspberryEnd && flyportEnd)
{
if(rowCounter>0)
{
message = "No More Devices";
}
else
{
message = "No Devices Found";
}
tv.setText(message);
tv.setTextColor(Color.WHITE);
if(rowCounter%2==0)
{
tr.setBackgroundColor(Color.DKGRAY);
}
else
{
tr.setBackgroundColor(Color.GRAY);
}
tv.setVisibility(1);
tr.addView(tv);
tb.addView(tr);
}
}
else
{
LayoutParams layout = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
TableRow tr = new TableRow(getApplicationContext());
TextView tv = new TextView(getApplicationContext());
tv.setLayoutParams(layout);
tr.setLayoutParams(layout);
Log.v("addDevice","Received");
String textToDisplay = device.getDeviceTypeString()+"\n"+device.getIPAddress(); //Write the text to display
tv.setText(textToDisplay);
tv.setTextColor(Color.WHITE);
Drawable img;
if(device.getDeviceType()==1)
{
img = getApplicationContext().getResources().getDrawable(R.drawable.pc);
}
else if(device.getDeviceType()==2)
{
img = getApplicationContext().getResources().getDrawable(R.drawable.raspberry);
}
else
{
img = getApplicationContext().getResources().getDrawable(R.drawable.flyport);
}
img.setBounds(0,0,70,45);
tv.setCompoundDrawables(null, null, img, null);
tv.setOnClickListener(new OnClickListener()
{
#Override
public void onClick(View v)
{
}
});
if(rowCounter%2==0)
{
tr.setBackgroundColor(Color.DKGRAY);
}
else
{
tr.setBackgroundColor(Color.GRAY);
}
rowCounter++;
Log.v("Result","Device Added");
}
}
Now it is showing me an error in the logCat as:
05-11 22:01:10.165: E/AndroidRuntime(13873): android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
What I have figured out from this is only the UIThread is allowed to access the Views that is created.
Previously I had tried:
new Thread()
{
public void run()
{
runOnUiThread(){
MulticastSocket socketComputer=null;
try
{
....
....
....
}
}
And that time I received an error:
Main thread cannot access Network
Before that I had tried to use synchronized methods which was called from the Receiving.java Thread File. but It also gave an error of not creating the list.
I have tried all possible ways.
Now what whould I do.?
You figured it out right. Now you can learn to either use a Handler to pass information to the UI thread (see http://www.techotopia.com/index.php/A_Basic_Overview_of_Android_Threads_and_Thread_handlers) or AsyncTask (see http://developer.android.com/reference/android/os/AsyncTask.html).
I personally prefer AsyncTask. You can paste the code which performs the search into the doInBackground() method (not need to use a separate thread, doInBackground() already does that for you) and paste the UI-related code (the list creation code) into the onPostExecute() method. Search for further examples of AsyncTask if it is not sufficiently clear how it works from the link.
EDIT: If you intend your device search code to run indefinitely, then you have to resort to Handler, as AsyncTask expects the doInBackground() method to finish before running onPostExecute(). See which option better suits your needs.

Categories

Resources