I'm facing a problem,On a button press i try to read the DataInputstream which has data coming in and display the data.
I'm using a while loop to read the data. But the dynamic update of the Textview doesnt happen.
TextView datatextview = (TextView)findViewById(R.id.data);
DataInputStream Din = new DataInputStream(socket.getInputStream());
Button getData= (Button)findViewById(R.id.getdata);
getData.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
//.......stuff .......
try{
int bufferSize = 1024;
byte[] buffer = new byte[bufferSize];
int bytesRead = -1;
String message1 = "";
while (true) {
message1 = "";
data = Din.readLine();
bytesRead = (reading).length();
if (bytesRead != -1) {
Log.v(TAG,"data"+data); //I'm getting the data correctly
//But not able to update it in the TextView :(
datatextview.setText(data); //doesnt work
}
}
You have to exit your method and relinquish control of the UI thread in order for your views to update. You should probably be using AsyncTask with its progress updating functionality to do this, so that you're not hogging the UI thread.
Something like:
public class MyTask extends AsyncTask<Void, String, Void> {
private final TextView progress;
public MyTask(TextView progress) {
this.progress = progress;
}
#Override
protected void onPreExecute() {
progress.setText("Starting...");
}
#Override
protected Void doInBackground(Void... unused) {
... your buffer code, including publishProgress(data); in your while loop ...
}
#Override
protected void onProgressUpdate(String... data) {
progress.setText(data[0]);
progress.invalidate(); // not sure if this is necessary or not
}
#Override
protected void onPostExecute(Void unused) {
progress.setText("Finished!");
}
}
Then you can create and execute your AsyncTask using:
new MyTask(datatextview).execute();
Edit - make sure to use #Override which helps alert you if your method signatures are not correct.
Matthew is right here but to elaborate...
If you are doing this from a thread you are probably stuck looping so fast the UI never gets a chance to redraw with your new values. If you want to force a redraw of the UI from a thread call View.invalidate().
If you are doing this from your main thread (which you should definitely reconsider) again you are stuck looping and UI can't redraw...you would want to all View.postInvalidate() to force a UI redraw.
Related
I understand that network tasks should be done in an Async thread, and I think my code is inside one, but I still get the error
.MainActivity}: android.os.NetworkOnMainThreadException
which confuses me, since pretty much everything is inside an Async task:
public void onStart() {
super.onStart();
new GetRssFeedTask().execute();
}
The rest of the code is inside the Async task:
private class GetRssFeedTask extends AsyncTask<Void, Void, List<String>> {
private String getRssFeed() throws IOException {
InputStream in = null;
String rssFeed = null;
try {
URL url = new URL("http://stuffilikenet.wordpress.com/feed/main.xml");
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
in = conn.getInputStream();
ByteArrayOutputStream out = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
for (int count; (count = in.read(buffer)) != -1; ) {
out.write(buffer, 0, count);
}
byte[] response = out.toByteArray();
rssFeed = new String(response, "UTF-8");
} finally {
if (in != null) {
in.close();
}
}
return rssFeed;
}
...rest of code (seriously)...
}
Where should I look for my error?
network tasks should be done in an doInBackground() .
doInBackground() callback method runs in a pool of background
threads. To update your UI, you should implement onPostExecute(),
which delivers the result from doInBackground() and runs in the UI
thread, so you can safely update your UI.
perform initilization in onPreExecute() method
perform background task in doInBackground() method
update the UI in onPostExecute() method
public class MyAyncTask extends AsyncTask<Void, Void, Void> {
#Override
protected void onPreExecute() {
//Here you can show progress bar or something on the similar lines.
//Since you are in a UI thread here.
super.onPreExecute();
}
#Override
protected Void doInBackground(Void... params) {
// Here you are in the worker thread and you are not allowed to access UI thread from here
//Here you can perform network operations or any heavy operations you want.
return null;
}
#Override
protected void onPostExecute(Void aVoid) {
super.onPostExecute(aVoid);
//After completing execution of given task , control will return here.
//Hence if you want to populate UI elements with fetched data, do it here
}
#Override
protected void onProgressUpdate(Void... values) {
super.onProgressUpdate(values);
// You can track you progress update here
}
}
It is not enough to do define the network operations inside your AsyncTask class to run them on a background Thread.
You have to execute them inside doInBackgrund().
You need to override doInBackground() inside your AsyncTask class and perform your network operations there.
#Override
protected Void doInBackground(Void... params) {
// here
return null;
}
This question already has answers here:
Android "Only the original thread that created a view hierarchy can touch its views."
(33 answers)
Closed 7 years ago.
My app crashes if TextView.setText is inside Thread:
NOTE: The following class is inside of MainActivity.
private class StreamThread extends Thread {
public StreamThread() {
}
public void run() {
byte[] buffer = new byte[1024];
int bytes;
while (true) {
try {
bytes = mmInStream.read(buffer);
String message = new String(buffer, 0, bytes);
//THIS IS IMPORTANT, READ THIS PLEASE
//I tested many times my app to find the problem, and I found, my app crashes when TextView.setText() is executed
//Here starts the problem
((TextView) findViewById(R.id.textView)).setText(message);
} catch (IOException e) {
break;
}
}
}
This should do the trick:
private class StreamThread extends Thread {
public StreamThread() {}
public void run() {
byte[] buffer = new byte[1024];
int bytes;
while (true) {
try {
bytes = mmInStream.read(buffer);
String message = new String(buffer, 0, bytes);
runOnUiThread(new Runnable() {
#Override
public void run() {
((TextView) findViewById(R.id.textView)).setText(message);
}
});
} catch (IOException e) {
break;
}
}
}
}
Sooo, what was wrong?
Android's UI is single threaded.
This means you are not allowed to change the ui from another thread than the ui thread.
You can post changes to the ui thread using the runOnUiThread-Method or using a Handler.
Threads are designed for execute code by separated allowing another codes execute to the same time.
Unafortunately Threads are not compatible with UI, but I have a solution.
runOnUiThread(new Runnable() {
#Override
public void run () {
//Some stuff that needs to interact with the user (UI).
}
}
You must update visual components in the ui thread. For your purpose you should use an AsyncTask, Service or a Runnable which runs in the ui thread.
For example, you use an AsyncTask like in the following code:
public class MainActivity extends ActionBarActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
TextView textview = (TextView) findViewById(R.id.textView);
new StreamAsyncTask(textview).execute();
}
private class StreamAsyncTask extends AsyncTask<Void, String, Void> {
private TextView textview;
public StreamAsyncTask(TextView textview) {
this.textview = textview;
}
#Override
protected Void doInBackground(Void... voids) {
byte[] buffer = new byte[1024];
int bytes;
while (true) {
try {
bytes = mmInStream.read(buffer);
String message = new String(buffer, 0, bytes);
publishProgress(message);
} catch (IOException e) {
break;
}
}
return null;
}
#Override
protected void onProgressUpdate(String... values) {
super.onProgressUpdate(values);
textview.setText(values[0]);
}
}
}
Or you can use the Activity's method runOnUiThread:
runOnUiThread(new Runnable() {
#Override
public void run() {
((TextView) findViewById(R.id.textView)).setText(message);
}
});
The last way is easier to understand but the first one is more flexible.
Read about AsyncTasks: http://developer.android.com/reference/android/os/AsyncTask.html
I am new to Android development and Java and was wondering if somebody could help me with the following:
I have created an application that runs a server thread listening on a specified port. I would like to print messages received from a connected client into a TextView in the activity.
The server thread is in a separate class. The run method in this class listens for a client connection and reads any data received into a String.
What would be the best way for me to transfer the contents of this String back to the activity so that it can update the TextView?
From my (limited) understanding, only the ui thread should update a TextView and I can't find a way to get runOnUiThread to update the TextView.
Added code as requested.
Activity code:
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
TextView messages = (TextView) findViewById(R.id.messages);
try {
newThread server = new newThread(this, messages);
} catch(Exception e) {
Toast.makeText(ChatActivity.this, e.toString(), Toast.LENGTH_LONG).show();
}
}
Run method in newThread class:
public void run()
{
serv = new ServerSocket(8000);
while(true)
{
cli = serv.accept();
user = cli.getInetAddress().toString();
BufferedReader cli_in = new BufferedReader(new InputStreamReader(cli.getInputStream()));
OutputStreamWriter cli_out = new OutputStreamWriter(cli.getOutputStream());
while((buf = cli_in.readLine()) != null)
{
// Update the messages TextView with buf
}
}
}
To avoid making things too cluttered I have omitted what irrelevant code I can.
Basically, in the inner while loop in run() I would like to pass the "buf" String to the activity so that the messages textview can be updated with it's content.
Cheers
Maybe a bad idea, but how about using AsyncTask? Didn't try if this would work, but it just might, since onProgressUpdate has access to UI thread.
private TextView messages;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
messages = (TextView) findViewById(R.id.messages);
ReceiveTask receive = new ReceiveTask();
receive.execute(100)
}
private void updateTextView(String text)
{
messages.setText(text);
}
private class ReceiveTask extends AsyncTask<Integer, String, Long> {
#Override
protected void onPreExecute() {
}
protected Long doInBackground(Integer... urls) {
newThread nt = new newThread();
while(true)
{
publishProgress(run());
}
return (long)0;
}
protected void onProgressUpdate(String... value) {
updateTextView(value[0]); //method in Activity class, to update TextView
}
protected void onPostExecute(Long result) {
}
}
Basically publishProgress will send data to onProgressUpdate, which will then send data to method (updateTextView) in main class and update TextView.
Usually it helps if you tell people you're working on a chat. Also, run() will need to be modified, to return string back, and remove while(true) loop from it. This is NOT the best idea, I suggest you go through a few tutorials on how to make an android chat first.
I've developed an application that takes content from the internet and shows it accordingly on the device's screen . The program works just fine , a little bit slow . It takes about 3-4 seconds to load and display the content . I would like to put my code that does all the work ( grabbing web content and displaying it) in a background thread . Also , I'd like to show a progress dialog .
public class Activity1 extends Activity
{
private ProgressDialog progressDialog;
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
new AsyncTask<Integer, Integer, Boolean>()
{
ProgressDialog progressDialog;
#Override
protected void onPreExecute()
{
/*
* This is executed on UI thread before doInBackground(). It is
* the perfect place to show the progress dialog.
*/
progressDialog = ProgressDialog.show(Activity1.this, "",
"Loading...");
}
#Override
protected Boolean doInBackground(Integer... params)
{
if (params == null)
{
return false;
}
try
{
/*
* This is run on a background thread, so we can sleep here
* or do whatever we want without blocking UI thread. A more
* advanced use would download chunks of fixed size and call
* publishProgress();
*/
Thread.sleep(params[0]);
// HERE I'VE PUT ALL THE FUNCTIONS THAT WORK FOR ME
}
catch (Exception e)
{
Log.e("tag", e.getMessage());
/*
* The task failed
*/
return false;
}
/*
* The task succeeded
*/
return true;
}
#Override
protected void onPostExecute(Boolean result)
{
progressDialog.dismiss();
/*
* Update here your view objects with content from download. It
* is save to dismiss dialogs, update views, etc., since we are
* working on UI thread.
*/
AlertDialog.Builder b = new AlertDialog.Builder(Activity1.this);
b.setTitle(android.R.string.dialog_alert_title);
if (result)
{
b.setMessage("Download succeeded");
}
else
{
b.setMessage("Download failed");
}
b.setPositiveButton(getString(android.R.string.ok),
new DialogInterface.OnClickListener()
{
#Override
public void onClick(DialogInterface dlg, int arg1)
{
dlg.dismiss();
}
});
b.create().show();
}
}.execute(2000);
/* new Thread()
{
#Override
public void run()
{
// dismiss the progressdialog
progressDialog.dismiss();
}
}.start();
}*/
}
If I run the application with this code , I get this : download failed . On the other hand , if I keep the final thread , the app crashes , NullPointerException . I really don't know what to do anymore .
I would really appreaciate if you could give me an alternative to this code , not just some hints because I'm new to android and I really don't know much . Thanks.
UPDATE :
I don't want to display the progress of the download , I want to display the progress dialog until the app is ready to display the full content.
The best approach to do this is by using the AsyncTask class, as it will allow you to execute some background process and update the UI at the same time (in your case, it's a progress bar).
This is an example code:
ProgressDialog mProgressDialog = new ProgressDialog(YourActivity.this);
mProgressDialog.setMessage("A message");
mProgressDialog.setIndeterminate(false);
mProgressDialog.setMax(100);
mProgressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
DownloadFile downloadFile = new DownloadFile();
downloadFile.execute("the url to the file you want to download");
The AsyncTask will look like this:
private class DownloadFile extends AsyncTask<String, Integer, String>{
#Override
protected String doInBackground(String... url) {
int count;
try {
URL url = new URL(url[0]);
URLConnection conexion = url.openConnection();
conexion.connect();
// this will be useful so that you can show a tipical 0-100% progress bar
int lenghtOfFile = conexion.getContentLength();
// downlod the file
InputStream input = new BufferedInputStream(url.openStream());
OutputStream output = new FileOutputStream("/sdcard/somewhere/nameofthefile.ext");
byte data[] = new byte[1024];
long total = 0;
while ((count = input.read(data)) != -1) {
total += count;
// publishing the progress....
publishProgress((int)(total*100/lenghtOfFile));
output.write(data, 0, count);
}
output.flush();
output.close();
input.close();
} catch (Exception e) {}
return null;
}
The method above (doInBackground) runs always on a background thread. You shouldn't do any UI tasks there. On the other hand, the onProgressUpdate runs on the UI thread, so there you will change the progress bar:
#Override
public void onProgressUpdate(String... args){
// here you will have to update the progressbar
// with something like
mProgressDialog.setProgress(args[0]);
}
}
You will also want to override the onPostExecute method if you want to execute some code once the file has been downloaded completely.
You should create an inner class for AsyncTask like this :
private class YourTask extends AsyncTask<Context, Void, Void>
{
ProgressDialog dialog = new ProgressDialog(mContext);
protected void onPreExecute()
{
dialog.setMessage("loading..");
dialog.show();
}
protected Void doInBackground(Context... params)
{
// ...
return null;
}
protected void onPostExecute(final Void unused)
{
dialog.dismiss();
}
}
and in onCreate() put :
new YourTask().execute();
and for more detail you should check this once:
http://developer.android.com/reference/android/os/AsyncTask.html
When you use the new thread, your app crashes because the progress dialog is not initialized there
Inside your new thread use:
`progressDialog = ProgressDialog.show(Activity1.this, "","Loading...");
and about that alert dialog: Basically either params is null or the logic is throwing some exception. It's not returning true
so check the ddms logs and post them here.
`
My android app connects to my website to retrieve and upload information so I use an AsyncTask thread.
In one instance, I need my thread to return a true or a false value to my main thread.
Is there a way to get this return value from an AsyncTask execute function?
When I do the following:
Toast.makeText(Locate.this, "Testing : "+locationUpdate.execute(location), Toast.LENGTH_LONG).show();
I just get alot of gibberish.
I think what I need is a means to pause the main thread until the second thread completes. The second thread calls a function in the main thread to set my return value.
So when the second thread completes, the main thread can unpause and access the return value as set by the second thread
If this logic is sound, please offer suggestions ... thanks!
You can use AsyncTask get() method for this. It waits if necessary for the computation to complete, and then retrieves its result:
Toast.makeText(Locate.this, "Testing : " + locationUpdate.execute(location).get(), Toast.LENGTH_LONG).show();
But be sure to not block the main thread for a long period of time, as this will lead to unresponsive UI and ANR.
UPDATE
I missed the point that question was about async web download/upload. Web/network operation should considered as a long one and thus the approach "pause UI thread and wait till download finishes" is always a wrong one. Use usual result publishing approach intstead (e.g.: AsyncTask.onPostExecute, Service + sendBroadcast, libraries like Volley, RoboSpice, DataDroid etc).
Handler is the best way to do this
in onPostExcecute() method simply do
#Override
protected void onPostExecute(Boolean bool) {
super.onPostExecute(bool);
Message msg=new Message();
msg.obj=bool;
mHandler.sendMessage(msg);
}
}
and your message handler will be
mHandler = new Handler() {
#Override
public void handleMessage(Message msg) {
bool i=(String)msg.obj;
}
};
public class RunWebScript {
String mString;
public RunWebScript(String url){
try {
URL updateURL = new URL(url);
URLConnection conn = updateURL.openConnection();
// now read the items returned...
InputStream is = conn.getInputStream();
BufferedInputStream bis = new BufferedInputStream(is);
ByteArrayBuffer baf = new ByteArrayBuffer(50);
int current = 0;
while((current = bis.read()) != -1){
baf.append((byte)current);
}
String s = new String(baf.toByteArray());
mString = s;
} catch (Exception e) {
Log.e("ANDRO_ASYNC", "exception in callWebPage",e);
mString = "error";
}
}
public String getVal(){
return mString;
}
}
this is executed as... (showing teh end of a method in teh calling class
asyncWebCall (url1,CONSTANT);
}
private void asyncWebCall(String url,int actionPostExecute){
new WebCall().execute(url,String.format("%d",actionPostExecute));
}
The Async part of the business is ... Note the case statement in onPostExecute this is the key to getting the returned value ito your program again. Note that the call new WebCall().execute(url,String.format("%d",actionPostExecute)); is the last thing done in a thread, no further statements can be executed, control returns through the onPostExecute.
class WebCall extends AsyncTask<String, String, String>{
int chooser = -1;
#Override
protected void onPreExecute() {
super.onPreExecute();
}
#Override
protected String doInBackground(String... params) {
try {
chooser = Integer.parseInt(params[1]);
} catch(NumberFormatException nfe) {
Log.d("ANDRO_ASYNC",String.format("asyncReturn() mString numberformatexception = %s",params[1]));
chooser = 0;
}
return(new RunWebScript(params[0])).getVal();
}
protected void onProgressUpdate(String... progress) {
}
#Override
protected void onPostExecute(String gotFromDoInBkgnd) {
Log.d("ANDRO_ASYNC",String.format("chooser = %s",chooser));
switch (chooser){
case CONSTANT:
printStringx(gotFromDoInBkgnd);
asyncWebCall(url2,5);
break;
case 0:
Log.d("ANDRO_ASYNC",String.format("case 0 = %s",gotFromDoInBkgnd));
break;
case 5:
Log.d("ANDRO_ASYNC",String.format("case 5 = %s",gotFromDoInBkgnd));
asyncWebCall(url3,7);
break;
default:
Log.d("ANDRO_ASYNC",String.format("man we got problems = %s",gotFromDoInBkgnd));
break;
}
}
} // end of class
Here is a complete example of the issue of returning values from an async task. It may occur that there are many tasks to be done one after the other asynchronously.
Basics.
1. get a return value from a class.
public class Snippet {
int computVal;
public Snippet(){
computVal = 17*32;
}
public int getVal(){
return computVal;
}
}
this is called as...
int hooray = (new Snippet()).getVal();