My application works as a BluetoothServer, almost the same as the BluetoothChat example. I'm facing a strange problem. Inside my run-method where I start reading input from the bluetoothSocket, I want to post a message to a handler. This handler is in a seperate class, to avoid possible memory leaks.
public void run() {
Log.i("", "BEGIN ReadInputThread");
final byte[] buffer = new byte[1024];
int bytesread;
Message msg = handler.obtainMessage();
msg.obj = "0";
handler.sendMessage(msg);
...... snip .....
When I receive the String "0", in my handler, I want to show a progressDialog that informing the user that the application has an incoming file. In my handler, this is how I deal with it:
public class MessageHandler extends Handler {
#Override
public void handleMessage(Message m) {
Vibrator v = (Vibrator) c.getSystemService(Context.VIBRATOR_SERVICE);
String message = (String) m.obj;
//Getting files
if (message.equals("0")) {
folder.appendToLogFile(new Date().toString(), "Incoming File From: " + deviceName);
v.vibrate(1500);
pd = new ProgressDialog(c);
pd.setTitle("Please Wait..");
pd.setMessage("Retrieving file from " + deviceName);
pd.setCancelable(false);
pd.show();
}
}
The first time, when I have my Activity open, which will start this Thread, the progressDialog will show. After the transfer has finished, I navigate to a new Activity, and then returning to the previous Activity. When I now try to transfer a file, it will succeed, but no ProgressDialog is shown on the screen.
I did some checks just to figure out if the ProgressDialog is "visible" by adding these two lines under the pd.show() statement
if(pd.isShowing())
Log.w("Handler: ", "inside the handler, and the progressdialog is showing");
And this also appears in LogCat, even if the ProgressDialog is not showing!
Can anybody give me a hint, or a solution to this frustration issue?
Thanks in advance!
Just to clarify a bit
My ProgressDialog is created in a class which not extends Activity, it doesn't extend any classes.
The first thing I do, is to post a 0 to my handler, in the start of my run() method. When I know that I have received the last byte-packet from the socket, I send another message to the handler:
if(lastPacket) {
msg = handler.obtainMessage();
msg.obj = "1";
handler.sendMessage(msg);
}
And in my Handler:
#Override
public void handleMessage(Message m) {
Vibrator v = (Vibrator) c.getSystemService(Context.VIBRATOR_SERVICE);
String message = (String) m.obj;
//Getting files
if (message.equals("0")) {
folder.appendToLogFile(new Date().toString(), "Incoming File From: " + deviceName);
v.vibrate(1500);
pd = new ProgressDialog(c);
pd.setTitle("Please Wait..");
pd.setMessage("Retrieving file from " + deviceName);
pd.setCancelable(false);
pd.show();
if(pd.isShowing())
Log.w("Handler: ", "inside the handler, and the progressdialog is showing");
}
//File complete
if(message.equals("1")) {
Toast.makeText(c, "File Received from: " + deviceName, Toast.LENGTH_LONG).show();
folder.appendToLogFile(new Date().toString(), "File Received");
pd.setMessage(c.getResources().getString(R.string.createCase));
GenerateCase caseGenerator = new GenerateCase(c, pd, lastCases, nextPCN);
caseGenerator.execute("");
}
}
as you can see, I pass the ProgressDialog into the AsyncTask. In my onPostExecute method, I dismiss this ProgressDialog
Solution
If someone is curious. I got confused with the threads. When I left my Activity, I forgot to kill my running thread, which would cause the ProgressDialog to start in a different thread when I resumed my activity.
Close your progress dialog via broadcast Intent;
onPostExecute(){
sendBroadcastIntent(new Intent("ACTION_CLOSE_DIALOG"):
}
BroadCastReceiver receiver = new BroadCastReceiver(){
#Override
public void onReceive(Context context, Intent intent) {
if(pd.isShowing()){
pd.dismiss();
}else{
pd.show()
}
}
}
call Broadcast here:
pd.show();// call broadcast instead pd.show() use sendBroadcastIntent(new Intent("ACTION_CLOSE_DIALOG")
Related
my app does heavy task so I want to show a progress bar to user and run the task in background, so user can understand that its loading.
when the background task completes hide the progress bar.
But progress bar should not take same time to reach its max, it should be dependent on users input or processing.
Use AsyncTask. AsyncTask is one of the easiest ways to implement parallelism in Android without having to deal with more complex methods like Threads. Though it offers a basic level of parallelism with the UI thread, it should not be used for longer operations (of, say, not more than 2 seconds).
AsyncTask has four methods do the task:
onPreExecute()
doInBackground()
onProgressUpdate()
onPostExecute()
Check link for more details.
You can create something like this, the process ends in 30 seconds. I hope it will be useful to you
private ProgressDialog progressDialog;
public void init() {
progressDialog = new ProgressDialog(context);
progressDialog.setCancelable(false);
progressDialog.setMessage("please wait");
progressDialog.show();
new Thread(new Runnable() {
#Override
public void run() {
while (time < 30) {
try {
Thread.sleep(1000);
Message message = new Message();
message.what = UPDATE_PROGRESS;
handler.sendMessage(message);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
Message message = new Message();
message.what = END_PROGRESS;
handler.sendMessage(message);
}
}).start();
}
private static final int UPDATE_PROGRESS = 1;
private static final int END_PROGRESS = 2;
private int time;
private Handler handler = new Handler(new Handler.Callback() {
#Override
public boolean handleMessage(Message msg) {
switch (msg.what) {
case UPDATE_PROGRESS:
progressDialog.setMessage("Time: " + time++);
break;
case END_PROGRESS:
progressDialog.dismiss();
break;
default:
break;
}
return true;
}
});
UPDATE
This is the thread and handler example. But you can also create an asynctask
In my Application I am trying to simply setText() on my Button purchaseButton.
I have an Alert Dialog that takes a value and initializes an AsyncTask to complete the server call to find the discount.
All of that works fine, its when I get to the onPostExecute().
onPostExecute():
protected void onPostExecute(String result) {
Log.d(tag,"Result of POST: " + result);
if(result != null){
if(result.equals("NO")){
createAlert(1);
}else{
result = result.replaceAll("YES", "");
String discount = result;
discountPrice = price - Double.parseDouble(discount);
Log.d(tag, "Discount price after pull:" + discountPrice);
//setPurchase("Purchase $" + String.valueOf(discountPrice));
new Thread(new Runnable()
{
#Override
public void run()
{
Message msg = handler.obtainMessage();
msg.what = (int) discountPrice;
handler.sendMessage(msg);
}
}).start();
}
}
You can see that I make a call to a handler from a new Thread(). This allows me to get to the handler but never sets the text of the button from the handler.
Handler Method:
final static Handler handler = new Handler(){
#Override
public void handleMessage(Message msg){
Log.d(tag, "entered handler");
if(msg.what == discountPrice)
{
setPurchaseText(msg.what);
}
}
};
setPurchaseText() method:
private static void setPurchaseText(int value){
Log.d(tag, "Entered setPurchaseText");
purchaseButton.setText("Purchase $" + String.valueOf(value));
}
From my knowledge this should allow me to set the text from the handler. Why is it not setting the text and how can I get it to set the text with my string value?
Any help is much appreciated!
If the setText() is not working in onPostExecute(), they you might not be creating your AsyncTask on the UI thread. AsyncTask runs onPostExecute() on the thread you create it.
Again, Handler is created on the currently executed Thread. May be your Handler is initialized on a background thread. Try using final static Handler handler = new Handler(Looper.getMainLooper()). This ensures the handler to be attached to the main thread.
I want to create a dialogBuilder with a text field and a button on it. The idea is to make the program wait for any further actions until the text in the field is entered and the OK button is clicked. Below is the code:
private static final Object wait = new int[0];
private static String result = null;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Handler h = new Handler();
final Context context = MainActivity.this;
h.post(new Runnable() {
public void run() {
final Builder dialogBuilder = new AlertDialog.Builder(context);
dialogBuilder.setTitle(R.string.app_name);
final LinearLayout panel = new LinearLayout(context);
panel.setOrientation(LinearLayout.VERTICAL);
final TextView label = new TextView(context);
label.setId(1);
label.setText(R.string.app_name);
panel.addView(label);
final EditText input = new EditText(context);
input.setId(2);
input.setSingleLine();
input.setInputType(InputType.TYPE_CLASS_TEXT
| InputType.TYPE_TEXT_VARIATION_URI
| InputType.TYPE_TEXT_VARIATION_PHONETIC);
final ScrollView view = new ScrollView(context);
panel.addView(input);
view.addView(panel);
dialogBuilder
.setCancelable(true)
.setPositiveButton(R.string.app_name,
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog,
int id) {
result = input.getText().toString();
synchronized (wait) {
wait.notifyAll();
}
dialog.dismiss();
}
}).setView(view);
dialogBuilder.setOnCancelListener(new OnCancelListener() {
public void onCancel(DialogInterface arg0) {
result = null;
synchronized (wait) {
wait.notifyAll();
}
}
});
dialogBuilder.create().show();
}
});
String localResult = null;
try {
synchronized (wait) {
Log.d("Waiting", "Waiting " + localResult);
wait.wait();
}
localResult = result;
result = null;
if (localResult == null) {
// user is requesting cancel
throw new RuntimeException("Cancelled by user");
}
Log.d("RESULT ", "RESULT " + localResult);
} catch (InterruptedException e) {
localResult = result;
result = null;
if (localResult == null) {
// user is requesting cancel
Log.d("CANCELED ", "CANCELED " + localResult);
throw new RuntimeException("Cancelled by user");
}
}
Log.d("RESULT AFTER THE DIALOG", "RESULT AFTER THE DIALOG " + result);
}
The program is going to Log.d("Waiting", "Waiting " + localResult); and after that just waiting. NO DIALOG BUILDER IS SHOWN on the activity window. I used the debug mode and saw that the program flow is not entering the run() method, but the value of the Handler.post() is true. And for this reason the dialog is not shown, and the program is waiting.
I have tried to remove the moment with waiting (remove the Handler.post()), just to see if the dialog will show, and it showed and all moved well, but the result was not I am needing - I want the program to wait the input from the dialog ... I am really out of ideas.
Would you please give me some suggestions as I am really out of ideas.
Thanks a lot!
Handlers don't run in a separate thread. So when you call wait() :
synchronized (wait) {
Log.d("Waiting", "Waiting " + localResult);
wait.wait();
}
It waits indefinitely since the handler runs on the same thread as the current thread. Your Runnable can only be executed after the onCreate() method finishes but this will never happen because you just called wait().
You should reconsider your idea and find a workaround (for example, show the dialog the usual way and disable the "OK" button as long as the user does not enter a valid text). But calling wait() on the UI thread cannot go well.
You should be running the display of the Dialog in the UI Thread, not a seperate thread.
An example would be something like this:
In the onCreate()
runOnUiThread(new Runnable() {
#Override
public void run() {
// Display progress dialog when loading contacts
dialog = new ProgressDialog(this);
// continue with config of Dialog
}
});
// Execute the Asynchronus Task
new AsyncTask<Void, Void, Void>() {
#Override
protected Void doInBackground(Void... params) {
// code to execute in background
return null;
}
#Override
protected void onPostExecute(Void result) {
// Dismiss the dialog after inBackground is done
if (dialog != null)
dialog.dismiss();
super.onPostExecute(result);
}
}.execute((Void[]) null);
Specifically what is happening here is the Dialog is being displayed on the UI thread and then the AsyncTask is executing in the background while the Dialog is running. Then at the end of the execution we dismiss the dialog.
Can anyone help me how to put a progress dialog that loads for 5 seconds and shows a fast after? Here's the code:
btnSend.setOnClickListener(new View.OnClickListener() {
public void onClick(View view) {
String phoneNo = editTextRecipient.getText().toString();
String message = editTextNewMessage.getText().toString();
setResult(RESULT_OK);
saveState(phoneNo, message);
final Toast toast = Toast.makeText(getBaseContext(),
"Your message " + "\"" + message + "\"" + " is sent to " +"\""+ phoneNo+"\"",
Toast.LENGTH_SHORT);
toast.show();
Intent setIntent = new Intent(Edit_Message.this, Main.class);
startActivity(setIntent);
}
});
}
I want to put a 5 second progress dialog and a tots that prompts that the message has been sent. Can anyone help me?
Please try this
showProgress ();
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
dialog.cancel();
Intent i=new Intent(getApplicationContext(),Main.class);
startActivity(i);
finish();
}
}, 5000);
private ProgressDialog dialog;
public void showProgress () {
dialog = new ProgressDialog(this);
dialog.setCancelable(true);
dialog.setMessage("Please wait");
dialog.show();
}
if you really need to make progess bar for 5 second then Progress Dialog & Java thread is use ** Progress dialog**but if you need it to dynamic then AsyncTask is best practice to use.
as per your description you need to raise Toast after complete load then you can make it in after complete thread or in asynctask , onPostExecute() will use.
Ive created a new thread for a file browser. The thread reads the contents of a directory. What I want to do is update the UI thread to draw a graphical representation of the files and folders. I know I can't update the UI from within a new thread so what I want to do is:
whilst the file scanning thread iterates through a directories files and folders pass a file path string back to the UI thread. The handler in the UI thread then draws the graphical representation of the file passed back.
public class New_Project extends Activity implements Runnable {
private Handler handler = new Handler() {
#Override
public void handleMessage(Message msg) {
Log.d("New Thread","Proccess Complete.");
Intent intent = new Intent();
setResult(RESULT_OK, intent);
finish();
}
};
public void fileScanner(){
//if (!XMLEFunctions.canReadExternal(this)) return;
pd = ProgressDialog.show(this, "Reading Directory.",
"Please Wait...", true, false);
Log.d("New Thread","Called");
Thread thread = new Thread(this);
thread.start();
}
public void run() {
Log.d("New Thread","Reading Files");
getFiles();
handler.sendEmptyMessage(0);
}
public void getFiles() {
for (int i=0;i<=allFiles.length-1;i++){
//I WANT TO PASS THE FILE PATH BACK TU A HANDLER IN THE UI
//SO IT CAN BE DRAWN.
**passFilePathBackToBeDrawn(allFiles[i].toString());**
}
}
}
It seems passing simple messages is int based... What I needed to do was pass a Bundle
using Message.setData(Bundle) and Message.getData(Bundle)
So Happy =0)
//Function From Within The Thread
public void newProjectCreation() {
Message msg = new Message();
Bundle bundle = new Bundle();
bundle.putString("Test", "test value");
msg.setData(bundle);
handler2.sendMessage(msg);
}
//Handler in The UI Thread Retreieves The Data
//And Can Update the GUI as Required
private Handler handler2 = new Handler() {
#Override
public void handleMessage(Message msg) {
Bundle bundle = msg.getData();
Toast.makeText(New_Project.this,bundle.getString("Test"),Toast.LENGTH_SHORT).show();
}
};
Check out AsyncTask for this kind of stuff. It's really much more elegant than rolling your own handler and passing messages back and forth.
http://developer.android.com/reference/android/os/AsyncTask.html