First of all, i have to state that i am new to Java in general & Android. I do however have the basics, or at least getting there.
The Purpose of my Application: At the company, we have a Remote server that we SSH to, and do some work. At some times, the server is unreachable and therefore disrupts our work.
My application is suppose to do the following:
1- Using Jsch, i SSH to the server, if there is a response, then, i will attempt again in 15 minutes, if there is no response, i want to notify.
i have successfully done the above in non android version of Java, and was able to do it in Android version, however on the main thread, thus i cannot update anything on the UI. In essence the Progress Bar..
In the regular version, the UI freezes, and in the AsyncTask version provided below. i get an exception as soon as i hit the button
Below is the code i am using, to be honest, i read all over that the best solution is AsyncTask, but since i am new to that, i am not sure were my wrong is. I honestly assume its may be in the AsyncTask and AsyncTask .
I am not sure what to use there...
Below is my code, hopefully someone can point out my mistake.
package com.example.myapp;
import java.io.IOException;
import android.app.Activity;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.HandlerThread;
import android.os.StrictMode;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ProgressBar;
import android.widget.Toast;
import android.os.Handler;
public class VedasServerMonitorActivity extends Activity {
/** Called when the activity is first created. */
Button button;
EditText IP;
EditText UserName;
EditText Password;
EditText Port;
ProgressBar progressBar1;
String UserStr;
String PassStr;
String IPStr;
int PortInt;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
button = (Button) findViewById(R.id.button1);
IP = (EditText) findViewById(R.id.serverIp);
UserName = (EditText) findViewById(R.id.userName);
Password = (EditText) findViewById(R.id.password);
Port = (EditText) findViewById(R.id.port);
progressBar1 = (ProgressBar) findViewById(R.id.progressBar1);
StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder()
.permitAll().build();
StrictMode.setThreadPolicy(policy);
button.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
new asyncTaskUpdateProgress().execute();
}
});
}
public class asyncTaskUpdateProgress extends AsyncTask<Void, Void, Void> {
#Override
protected void onPostExecute(Void result) {
// TODO Auto-generated method stub
}
#Override
protected void onPreExecute() {
// TODO Auto-generated method stub
progressBar1.setVisibility(View.VISIBLE);
UserStr = UserName.getText().toString();
PassStr = Password.getText().toString();
IPStr = IP.getText().toString();
PortInt = Integer.parseInt(Port.getText().toString());
button.setClickable(true);
progressBar1.setVisibility(View.INVISIBLE);
}
#Override
protected void onProgressUpdate(Void... values) {
// TODO Auto-generated method stub
progressBar1.setVisibility(View.INVISIBLE);
}
#Override
protected Void doInBackground(Void... arg0) {
boolean ok = false;
try {
SSHTest sshtest = new SSHTest();
ok = sshtest.sshconnect(UserStr, PassStr, IPStr, PortInt);
}
catch (Exception e) {
e.printStackTrace();
Log.i("ERROR HERE", "doInBackground: IOException");}
if (ok) {
Toast.makeText(getApplicationContext(),
"Connection Susccessfull", Toast.LENGTH_LONG)
.show();
} else {
Toast.makeText(getApplicationContext(),
"Unable to connect", Toast.LENGTH_LONG).show();
notify(getApplicationContext(), true);
}
return null;
}
protected void notify(Context context, Boolean on) {
NotificationManager nm = (NotificationManager) context
.getSystemService(Context.NOTIFICATION_SERVICE);
ComponentName comp = new ComponentName(context.getPackageName(),
getClass().getName());
Intent intent = new Intent().setComponent(comp);
PendingIntent pendingIntent = PendingIntent.getActivity(context, 0,
intent, Intent.FLAG_ACTIVITY_NEW_TASK);
Notification n = new Notification(R.drawable.warning, "Message",
System.currentTimeMillis());
n.setLatestEventInfo(context, "Vedas Server Monitor",
"Port Un-rechable", pendingIntent);
nm.notify(22, n);
}
}
}
android× 194760
There are some correction that you need to make in the doInBackground(). But before that a small detailing about the AsyncTask.
AsyncTask is used when you have any non-UI back ground activity to perform. The function onPreExecute() is used to show any UI action
(in most cases its showing of a dialog) before you enter the background thread. The function doInBackground() is used to perform the non-ui action (in most cases fetching data from server). While doing the background activity in doInBackground() you may wish to show some progress which you do by using publishProgress() which will internally call the onProgressUpdate() method. On completion of the background activity in doInBackground() you return the result of the activity, if you have any. After you return from the doInBackground() method internally there is call made to the onPostExecute() which will receive the result you have returned in doInBackground() as a parameter. Now onPostExecute() will run on a UI thread and most of the UI action like dismissing of dialog which was shown in onPreExecute(), displaying the result on some UI component etc. happens in this method.
Now to the mistake you are doing in you code:
You are showing a toast or a notification based on the result of your server data fetch using a function notify but you are still in the background non-ui thread. Now this result should ideally be returned and checked in the onPostExecute() and based on its value you can show the UI component of toastor notification.
I hope this explanation helps you in solving your problem.
EDIT
In your case since you can send the boolean type result variable ok to onPostExecute(). For that you need to make the following changes:
in class declaration:
public class asyncTaskUpdateProgress extends AsyncTask<Void, Void, Boolean>
and
protected void onPostExecute(Boolean result){
if (ok) {
Toast.makeText(getApplicationContext(),
"Connection Susccessfull", Toast.LENGTH_LONG)
.show();
} else {
Toast.makeText(getApplicationContext(),
"Unable to connect", Toast.LENGTH_LONG).show();
notify(getApplicationContext(), true);
}
}
and finally in
protected Void doInBackground(Void... arg0) {
boolean ok = false;
try {
SSHTest sshtest = new SSHTest();
ok = sshtest.sshconnect(UserStr, PassStr, IPStr, PortInt);
}
catch (Exception e) {
e.printStackTrace();
Log.i("ERROR HERE", "doInBackground: IOException");}
return ok;
}
You can try this
in your protected void onPreExecute() need to add
progressBar = new ProgressDialog(v.getContext());
progressBar.setCancelable(true);
progressBar.setMessage("File downloading ...");
progressBar.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
progressBar.setProgress(0);
progressBar.setMax(100);
progressBar.show();
//reset progress bar status
progressBarStatus = 0;
then
protected void onProgressUpdate(Void... values) {
progressBarStatus= progressBarStatus + x; // x means any value
progressBar.setProgress(progressBarStatus);
}
after that you need to finish your progressBar in onPostExecute(). like
protected void onPostExecute(Void result) {
progressBar.dismiss();
}
Related
Hello everyone, I am new to android application development. I have written and code and trying to update the UI from the message obtained from handler. I have tried to debug the code but i couldn't find what the error is. please help me out. Thank you.
package com.threadcommunicationexample;
import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;
public class MainActivity extends Activity implements OnClickListener {
Button Click;
TextView Message;
Handler Mrmessenger;
int Counter = 0;
/*
*Initialisation area....
*/
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Click = (Button) findViewById(R.id.ClickButton);
Message = (Button) findViewById(R.id.TextView);
Click.setOnClickListener(this);
}
#Override
public void onClick(View v) {
// Operation to be performed after the button click
Runnable myThreadRunner = new Runnable() {
#Override
public void run() {
// Saving the text in bundle and passing it to handler ....
while (Counter < 100) {
try {
Thread.sleep(100);
Message msg = Mrmessenger.obtainMessage();
Bundle myBundle = new Bundle();
myBundle.putString("Communication", "Loading....");
msg.setData(myBundle);
//Sending the bundle to Handler
Mrmessenger.sendMessage(msg);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Mrmessenger = new Handler() {
public void handleMessage(final Message msg) {
Mrmessenger.post(new Runnable() {
// Getting the message from the handler and updating it using textview
#Override
public void run() {
Bundle ComBundle = msg.getData();
// TODO Auto-generated method stub
String myMessage = ComBundle
.getString("Communication");
Message.setText(myMessage);
}
});
}
};
Counter++;
}
}
};
Thread myRunner = new Thread(myThreadRunner);
//creating a thread and passing the runnable object.
myRunner.start();
}
}
For one thing, the line
Message msg = Mrmessenger.obtainMessage();
will fail since you don't initialize Mrmessenger until a few lines later.
Would recommend you use AsyncTask for this type of thing; it deals with all of the threading so you don't have to.
Also: per Java conventions, variable names should start with a lowercase letter, class names start with an uppercase letter. This would make your code easier for others to read.
the problem with your code is, that the run method in your handler is called on another thread than the main / ui thread.
To make the code working you can use the following code..
runOnUiThread(new Runnable() {
public void run() {
Message.setText(myMessage);
}
});
..to run the ui update explicitly on the ui thread.
I'm working on getting a better handle on AsyncTask and am trying to create controls dynamically with asyncTask's onPostExecute().
The code I have below does work and it creates controls, but is there a way to loop this, but delay it so that variable I is incremented after the asynctask completes?
I've read through using the get() method, but I can't seem to make it work.
Can anyone advise how to either wait till a background task is complete or some other way to dynamically create controls based on a variable number?
package com.example.dynamicallycreatecontrols;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import android.app.Activity;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.SystemClock;
import android.util.Log;
import android.view.Menu;
import android.view.ViewGroup.LayoutParams;
import android.widget.Button;
import android.widget.LinearLayout;
public class MainActivity extends Activity {
Integer i = 0;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
while (i < 5) {
new createControl().execute(i);
i++;
}
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
//asynctask
public class createControl extends AsyncTask<Integer, Void, Button> {
Button btn = new Button(MainActivity.this);
LinearLayout ll = (LinearLayout) findViewById (R.id.llMain);
LayoutParams lp = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
protected void onPreExecute(Integer i) {
// nothing right now
}
#Override
protected Button doInBackground(Integer... arg0) {
// TODO Auto-generated method stub
// do the calculation
return null;
}
protected void onPostExecute(Button v) {
// build the controls here
btn.setText("Play" + i);
ll.addView(btn, lp);
SystemClock.sleep(1000);
}
}
}
I'm new to android development and java so i'm not sure if I'm just misunderstanding a concept of get() or if there is a better way to do this all together.
Thanks for any time allocated in assistance.
-nick
When doInBackground() done I move to onPostExecute(). I don't need any delays there. When I call task.execute(/**/) actually I invoke doInBackground() async task and I don't care when it finish but I know that I have callback onPostExecute() and I wait and update my main Thread from there.
To make it clearer lets say you have application where user wants to register to server and update GUI led to green color. User presses on button and calls method registerClient()
This method runs:
private void registerClient(){
...
dialog = ProgressDialog.show(LoginActivity.this, "", "Connecting. Please wait...", true);
HeavyTask task = new HeavyTask();
task.execute(user, password, domain);
}
So what we have in HeavyTask:
private class HeavyTask extends AsyncTask<String, Void, Void> {
private String username = "";
private String domain = "";
private String password = "";
// run async task
protected Void doInBackground(String... args) {
username = args[0];
password = args[1];
domain = args[2];
registerClientToServer(username, password, domain, null);
return null;
}
protected void onPostExecute(Void results) {
mHandler.postDelayed(new Runnable() {
#Override
public void run() {
updateGUI(username, domain);
}
}, 500);
}
}
Why not create an object and instantiate it? You can control if the object exists or if it already finished what he had to do.
Example:
public class MainActivity extends Activity {
private createControl cc = null;
Integer i = 0;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
while (i < 5) {
if (cc == null){
cc = new createControl();
cc.execute(i);
i++;
}
}
}
...
}
Then in onPostExecute just add cc = null;
I have one button in the main.xml which will link to another xml which include information from server. I include progress bar to avoid the blank screen while the system is loading the information. i already done the code as below but it's still not the things i wanted. the code below will "WAIT" for 1000 ms then only will execute the next code. how can i modify it so that the loading "WAIT TIME" will depends on the internet speed, if internet connection is slow, then the progress-bar-screen will show longer.
package com.android.myApps;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.view.View;
import android.widget.TextView;
public class MainScr extends Activity {
private final int WAIT_TIME = 1000;
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.MainScr);
}
public void onClickCategory(View view)
{
findViewById(R.id.mainSpinner1).setVisibility(View.VISIBLE);
new Handler().postDelayed(new Runnable(){
#Override
public void run() {
Intent mainIntent = new Intent(MainScr.this, Category.class);
MainScr.this.startActivity(mainIntent);
MainScr.this.finish();
}
}, WAIT_TIME);
}
}
The mistake you are doing here is you are dumping specific time into your code
You never know how much it will take to get response.
You should follow following approach
Step 1 Show progress dialog on screen
Step 2 Let download take its own time.But it should be done in new thread
Step 3 Once download is complete it will raise message that task is done,now remove that
progress dialog and proceed.
I am pasting sample code here.Hope it will help you.
package com.android.myApps;
import android.app.Activity;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
public class MainScr extends Activity
{
private Handler handler;
private ProgressDialog progress;
private Context context;
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
context = AncActivity.this;
progress = new ProgressDialog(this);
progress.setTitle("Please Wait!!");
progress.setMessage("Wait!!");
progress.setCancelable(false);
progress.setProgressStyle(ProgressDialog.STYLE_SPINNER);
handler = new Handler()
{
#Override
public void handleMessage(Message msg)
{
progress.dismiss();
Intent mainIntent = new Intent(context, Category.class);
startActivity(mainIntent);
super.handleMessage(msg);
}
};
progress.show();
new Thread()
{
public void run()
{
// Write Your Downloading logic here
// at the end write this.
handler.sendEmptyMessage(0);
}
}.start();
}
}
Did you try Asyntask? Your doing process will be update in UI.
public final class HttpTask
extends
AsyncTask<String/* Param */, Boolean /* Progress */, String /* Result */> {
private HttpClient mHc = new DefaultHttpClient();
#Override
protected String doInBackground(String... params) {
publishProgress(true);
// Do the usual httpclient thing to get the result
return result;
}
#Override
protected void onProgressUpdate(Boolean... progress) {
// line below coupled with
// getWindow().requestFeature(Window.FEATURE_INDETERMINATE_PROGRESS)
// before setContentView
// will show the wait animation on the top-right corner
MyActivity.this.setProgressBarIndeterminateVisibility(progress[0]);
}
#Override
protected void onPostExecute(String result) {
publishProgress(false);
// Do something with result in your activity
}
}
I am displaying a progress bar using Async task class and simulatneously in parallel operation , i want to retrieve a string array from a function of another class that takes some time to return the string array.
The problem is that when i place the function call in doing backgroung function of AsyncTask class , it gives an error in Doing Background and gives the message as cant change the UI in doing Background ..
Therefore , i placed the function call in post Execute method of Asynctask class . It doesnot give an error but after the progress bar has reached 100% , then the screen goes black and takes some time to start the new activity.
How can i display the progress bar and make the function call simultaneously.??plz help , m in distress
here is the code
package com.integrated.mpr;
import android.app.Activity;
import android.app.ProgressDialog;
import android.content.Intent;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Handler;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
public class Progess extends Activity implements OnClickListener{
static String[] display = new String[Choose.n];
Button bprogress;
#Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.progress);
bprogress = (Button) findViewById(R.id.bProgress);
bprogress.setOnClickListener(this);
}
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
switch(v.getId()){
case R.id.bProgress:
String x ="abc";
new loadSomeStuff().execute(x);
break;
}
}
public class loadSomeStuff extends AsyncTask<String , Integer , String>{
ProgressDialog dialog;
protected void onPreExecute(){
dialog = new ProgressDialog(Progess.this);
dialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
dialog.setMax(100);
dialog.show();
}
#Override
protected String doInBackground(String... arg0) {
// TODO Auto-generated method stub
for(int i = 0 ;i<40;i++){
publishProgress(5);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
dialog.dismiss();
String y ="abc";
return y;
}
protected void onProgressUpdate(Integer...progress){
dialog.incrementProgressBy(progress[0]);
}
protected void onPostExecute(String result){
display = new Logic().finaldata();
Intent openList = new Intent("com.integrated.mpr.SENSITIVELIST");
startActivity(openList);
}
}
}
You can't dismiss the dialog in doInBackground() - even dismissing a dialog needs the UI task. Move dialog.dismiss() to onPostExecute() of the AsyncTask.
I am experiencing a problem I have following code:
public void onCreate(Bundle savedInstanceState) {
MyDialog = ProgressDialog.show(this, "Nalagam kanale" , "Prosimo počakaj ... ", true);
MyDialog.show();
... }
Which should actually start he dialog... But the problem is that dialog is shown when everything is loaded...
How can I do solve that?
Actual code
package com.TVSpored;
import java.util.ArrayList;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import android.app.Activity;
import android.app.ProgressDialog;
import android.os.Bundle;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.ListView;
public class Currently extends Activity{
static final int PROGRESS_DIALOG = 0;
private ArrayList<CurrentlyItem> currentItems;
private CurrentAdapter aa;
private ListView currentListView;
private JSONArray CurrentShows;
private Communicator CommunicatorEPG;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
setContentView(R.layout.layout_currently);
CommunicatorEPG = new Communicator();
currentItems = new ArrayList<CurrentlyItem>();
if(currentItems == null)
int resID = R.layout.current_item;
aa = new CurrentAdapter(this, resID, currentItems);
currentListView = (ListView)findViewById(R.id.currentListView);
try {
currentListView.setAdapter(aa);
} catch (Exception e) {
Log.d(" * Napaka", e.toString());
}
try {
populateCurrent();
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public void populateCurrent() throws JSONException
{
CurrentShows = CommunicatorEPG.getCurrentShows(0);
for (int i = 0; i < CurrentShows.length(); i++)
{
JSONObject jsonObject = CurrentShows.getJSONObject(i);
String start = jsonObject.getString("1");
Integer duration = jsonObject.getInt("2");
String title = jsonObject.getString("3");
String epg_channel = jsonObject.getString("4");
String channel_name = jsonObject.getString("5");
CurrentlyItem newItem = new CurrentlyItem(1, 2, 3, 4, 5);
currentItems.add(i, newItem);
}
}
}
This is actual code... I would like to do populateCurrent(); in AsyncTask and meanwhile I would like a loading screen to be shown... Have been trying for few hours now but no actual success... I have successfully shown loading screen and wen trough JSONArray, but couldn't update listview...
Thanks for support!
Expected behaviour...
Show a dialog is a typical task of UI thread, but until you complete the onCreate method, the UI thread s not free to execute the dialog creation...
Two solution: create a dialog in a separate thread or execute your long task in a separate thread.
Some highlights here:
http://developer.android.com/guide/topics/ui/dialogs.html
You could wait to set the content of the activity until the you're finished with the progress dialog.
Update:
This would run your command in async-task:
new AsyncTask<Void, Void, Void> {
protected Long doInBackground(Void... voids) {
populateCurrent();
}
}.execute()
However, then you probably have to make sure to update the list in the GUI thread again and in some way tell the adapter that the list have been updated (since you've given that list to the adapter):
runOnUiThread(new Runnable() {
public void run() {
currentItems.add(i, newItem);
aa.notifyDataSetChanged();
}
}
It is probably best to create a new list entirely and set the view to view that.