I'm trying to do a simple HTTP request in Android. It has to be in separate theread. But how can I operate on the view controls inside the thread?
Here's what I have now:
public void saveData(final View v)
{
Button btn = (Button) v.findViewById(R.id.button);
btn.setText("Saving...");
new Thread() {
public void run()
{
HttpURLConnection connection = null;
try {
URL myUrl = new URL("http://example.com");
connection = (HttpURLConnection)myUrl.openConnection();
InputStream inputStream = connection.getInputStream();
final String fResponse = IOUtils.toString(inputStream);
}
catch (MalformedURLException ex) {
Log.e("aaa", "Invalid URL", ex);
}
catch (IOException ex) {
Log.e("aaa", "IO Exception", ex);
}
finally {
if (connection != null) {
connection.disconnect();
}
}
// How can I access v and btn here?
// btn.getText("Saved, thanks.");
// btn.setText("Saved, thanks.");
}
}.start();
}
To elaborate what I'm trying to achieve:
I have a text box and a button. Once the button is clicked, I want to get the text from text box, use in the URL, wich returns a value, then update the button text with this value.
Here's an example on how you could do it.
public class YourClass extends Activity {
private Button myButton;
//create an handler
private final Handler myHandler = new Handler();
final Runnable updateRunnable = new Runnable() {
public void run() {
//call the activity method that updates the UI
updateUI();
}
};
private void updateUI()
{
// ... update the UI
}
private void doSomeHardWork()
{
//update the UI using the handler and the runnable
myHandler.post(updateRunnable);
}
private OnClickListener buttonListener = new OnClickListener() {
public void onClick(View v) {
new Thread(new Runnable() {
doSomeHardWork();
}).start();
}
};
}
As you can see, you need to update the UI with yet another Runnable object. This is one way of doing it.
Another option is via the runOnUiThread function
runOnUiThread(new Runnable()
{
#Override
public void run() {
updateActivity();
}
});
If you try to access your Views directly from another thread like that, you will get an exception because all UI operations must be performed on the main thread.
One method that the Android SDK provides for performing background tasks that need to update the UI is the AsyncTask.
The onPostExecute() method of an AsyncTask is called after doInBackground() returns, and is run on the UI thread.
Your AsyncTask might look something like this:
public class MyBackgroundTask extends AsyncTask<URL, Void, String> {
protected String doInBackground(URL... urls) {
URL myUrl = new URL("http://example.com");
connection = (HttpURLConnection)myUrl.openConnection();
InputStream inputStream = connection.getInputStream();
return IOUtils.toString(inputStream);
}
protected void onPostExecute(String result) {
// Call back to your Activity with the result here
}
}
Related
i'm developing an android App.
The user registration process calls a service that sends an email so it takes several seconds, like 5 or 6 seconds,that's why I execute that task within a thread. The problem is, the Dialog is never dismissing. It stays rolling and the user can do nothing. Here's my code:
try
{
final ProgressDialog progDailog = new ProgressDialog(ActividadAltaUsuario.this);
new Thread(new Runnable()
{
#Override
public void run()
{
try
{
URL url = new URL("slowWS");
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("POST");
InputStream in = new BufferedInputStream(conn.getInputStream());
String response = IOUtils.toString(in, "UTF-8");
final JSONObject jsonPrincipal = new JSONObject(response);
Boolean success = jsonPrincipal.get("status").toString() == "true";
if (success)
{
ActividadAltaUsuario.this.runOnUiThread(new Runnable() {
#Override
public void run() {
progDailog.show(ActividadAltaUsuario.this, "Sendind email");
}
});
final String idUsuario = jsonPrincipal.get("idUsuario").toString();
URL url2 = new URL("anotherSlowWS");
HttpURLConnection conn2 = (HttpURLConnection) url2.openConnection();
conn2.setRequestMethod("POST");
InputStream in2 = new BufferedInputStream(conn2.getInputStream());
String response2 = IOUtils.toString(in2, "UTF-8");
JSONObject jsonRtaMail = new JSONObject(response2);
//finish();
}
else
{
//finish();
showToast(jsonPrincipal.get("message").toString());
}
ActividadAltaUsuario.this.runOnUiThread(new Runnable() {
#Override
public void run() {
progDailog.dismiss();
}
});
}
catch (Exception e)
{
e.printStackTrace();
}
}
}).start();
}
catch(Exception e)
{
Log.e("log_tag", "Error in http connection" + e.toString());
}
Can anybody help me?
Thanks!
AsyncTask would be a better approach instead of thread, Replace your network call from thread to use AsyncTask. You can use something like this
private class LongOperation extends AsyncTask<Void, Void, Void> {
#Override
protected String doInBackground(Void... params) {
//Main stuff that needs to be done in background
}
#Override
protected void onPostExecute(Void result) {
//Post Execution this method will be called, handle result accordingly
//You can dismiss your dialog here
}
#Override
protected void onPreExecute() {
//Do initialization relative stuff here
// Initialize your dialog here.
}
}
As both onPostExecute() and onPreExecute() work on main thread you can show and dismiss your dialog in this methods.
The UI controls have to be accessed only from the UI thread.
Usually I do this in class that extends AsyncTask
Something like:
public class MyTask extends AsyncTask {
protected void onPreExecute() {
//create and display your alert here
progDialog = ProgressDialog.show(MyActivity.this,"Please wait...", "Logging ...", true);
}
protected Void doInBackground(Void... unused) {
// here is the thread's work ( what is on your method run()
...
// if we want to show some progress in UI, then call
publishProgress(item)
}
protected void onProgressUpdate(Item... item) {
// theoretically you can show the progress here
}
protected void onPostExecute(Void unused) {
//dismiss dialog here where the thread has finished his work
progDialog.dismiss();
}
}
LE:
More detalis about AsyncTask https://developer.android.com/reference/android/os/AsyncTask
check especially the Protected Methods
I load my articles from my wordpress webpage. And want to display them in my app.
In order to be allowed to wait for a internet response I had to create a Thread.
Using this method:
private void loadArticles(final String url) {
Thread thread = new Thread(new Runnable(){
#Override
public void run() {
try {
//Get my data and run createArticles();
} catch (Exception e) {
e.printStackTrace();
}
}
});
thread.start();
}
Then in the createArticles function I try to use my function addViewToParent(...) and I get an error that says:
Only the original thread that created a view hierarchy can touch its
views.
How can i work around this problem?
EDIT: I use these networking functions if it matters...
//Connect to the url
URL pageURL = new URL(url);
HttpURLConnection connection = (HttpURLConnection) pageURL.openConnection();
BufferedReader in = new BufferedReader(
new InputStreamReader(connection.getInputStream())
);
If you want to modify your Views, e.g. show your article, you have to run the code on the UI/main thread. To achieve this, you could call run runOnUiThread() in your Activity:
private void loadArticles(final String url) {
Thread thread = new Thread(new Runnable(){
#Override
public void run() {
try {
//Get my data ...
runOnUiThread(new Runnable() {
public void run() {
// modify Views here
createArticles();
}
});
} catch (Exception e) {
e.printStackTrace();
}
}
});
thread.start();
}
You need to use function runOnUiThread. This is function for user interface thread.
private void loadArticles(final String url) {
//Get my data ...
runOnUiThread(new Runnable() {
public void run() {
// modify Views here
createArticles();
}
});
});
Just use a Handler instead, so you'll have access to the UI Thread:
new Handler().post(new Runnable(){
#Override
public void run() {
try {
//Get my data and run createArticles();
} catch (Exception e) {
e.printStackTrace();
}
}
});
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 use a worker thread to read text from a url. My thread is as follow. In the first time running, I am sure thread running is finished as I can check sdcard_readstr is null.
In the second time running, when I call thread_download.start();, then the program crashed.
What could be wrong? Thanks
public class DownloadingThread extends AbstractDataDownloading {
#Override
public void doRun() {
// TODO Auto-generated method stub
try {
// Create a URL for the desired page
URL url = new URL(SDcard_DetailView.textfileurl);
// Read all the text returned by the server
BufferedReader in = new BufferedReader(new
InputStreamReader(url.openStream()));
do{
sdcard_readstr = in.readLine();
}while(sdcard_readstr!=null);
in.close();
} catch (MalformedURLException e) {
} catch (IOException e) {
}
}
}
public abstract class AbstractDataDownloading extends Thread{
private final Set<ThreadCompleteListener> listeners
= new CopyOnWriteArraySet<ThreadCompleteListener>();
public final void addListener(final ThreadCompleteListener listener) {
listeners.add(listener);
}
public final void removeListener(final ThreadCompleteListener listener) {
listeners.remove(listener);
}
private final void notifyListeners() {
for (ThreadCompleteListener listener : listeners) {
listener.notifyOfThreadComplete(this);
}
}
#Override
public final void run() {
try {
doRun();
} finally {
notifyListeners();
}
}
public abstract void doRun();
}
EDIT1:
In my thread complete notification, I use runOnUiThreadto use the UI components.
Is that causing problem?
public void notifyOfThreadComplete(Thread thread) {
// TODO Auto-generated method stub
if(downloadingStopbuttonispressed == false){//background process completed
textfileurl = null;
this.runOnUiThread(new Runnable() {
public void run() {
Wifibutton = (Button) findViewById(R.id.Wifiscanning);
Wifibutton.setText("Load another day's data");
final MenuItem refreshItem = optionsMenu.findItem(R.id.airport_menuRefresh);
refreshItem.setActionView(null);
}
});
}
}
I called thread start in onResume() as
#Override
protected void onResume() {
super.onResume();
if(textfileurl != null){
Wifibutton.setText("Stop Data Loading");
buttonStatus = "loading";
setRefreshActionButtonState(true);
thread_download.start();
}
}
EDIT2:
My LogCat image is attached.
My solution is here . I can't reuse the same instance of the Thread object in the second time. I need to create a new instance to call the Thread in the second time. So Thread is suitable for single time running process, for multiple time running process I should use AsyncTask. Even AsyncTack is only for one time execution and for multiple time execution, we should use as new MyAsyncTask().execute(""); I don't understand why people downvote with no reason given. I couldn't find the link in my first search.
I am trying to use ProgressDialog. when i run my app the Progress Dialog box show and disappear after 1 second. I want to show it on completion of my process.. Here is my code:
public class MainActivity extends Activity {
android.view.View.OnClickListener mSearchListenerListener;
private ProgressDialog dialog;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
new YourCustomAsyncTask().execute(new String[] {null, null});
}
private class YourCustomAsyncTask extends AsyncTask <String, Void, Void> {
protected void onPreExecute() {
dialog = new ProgressDialog(MainActivity.this);
dialog.setMessage("Loading....");
dialog.setIndeterminate(true);
dialog.setCancelable(true);
dialog.show(); //Maybe you should call it in ruinOnUIThread in doInBackGround as suggested from a previous answer
}
protected void doInBackground(String strings) {
try {
// search(strings[0], string[1]);
runOnUiThread(new Runnable() {
public void run() {
// updateMapWithResult(); //Or call it onPostExecute before progressDialog's dismiss. I believe this method updates the UI so it should run on UI thread
}
});
} catch(Exception e) {
}
}
#Override
protected void onPostExecute(Void params) {
dialog.dismiss();
//result
}
#Override
protected Void doInBackground(String... params) {
// TODO Auto-generated method stub
return null;
}
}
}
Updated Question:
#Override
public void onCreate(SQLiteDatabase db) {
mDatabase = db;
Log.i("PATH",""+mDatabase.getPath());
mDatabase.execSQL(FTS_TABLE_CREATE);
loadDictionary();
}
/**
* Starts a thread to load the database table with words
*/
private void loadDictionary() {
new Thread(new Runnable() {
public void run() {
try {
loadWords();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}).start();
}
private void loadWords() throws IOException {
Log.d(TAG, "Loading words...");
for(int i=0;i<=25;i++)
{ //***//
final Resources resources = mHelperContext.getResources();
InputStream inputStream = resources.openRawResource(raw_textFiles[i]);
//InputStream inputStream = resources.openRawResource(R.raw.definitions);
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
try {
StringBuilder sb = new StringBuilder();
while ((word = reader.readLine()) != null)
{
sb.append(word);
// Log.i("WORD in Parser", ""+word);
}
String contents = sb.toString();
StringTokenizer st = new StringTokenizer(contents, "||");
while (st.hasMoreElements()) {
String row = st.nextElement().toString();
String title = row.substring(0, row.indexOf("$$$"));
String desc = row.substring(row.indexOf("$$$") + 3);
// Log.i("Strings in Database",""+title+""+desc);
long id = addWord(title,desc);
if (id < 0) {
Log.e(TAG, "unable to add word: " + title);
}
}
} finally {
reader.close();
}
}
Log.d(TAG, "DONE loading words.");
}
I want to show ProgressDialogue box untill all words are not entered in the database. This code is in inner calss which extends SQLITEHELPER. so how to can i use ProgressDialogue in that inner class and run my addWords() method in background.
You cannot have this
runOnUiThread(new Runnable() {
public void run() {
// updateMapWithResult(); //Or call it onPostExecute before progressDialog's dismiss. I believe this method updates the UI so it should run on UI thread
}
});
in your doInBackground().
Progress dialog doesn't take priority when there is some other action being performed on the main UI thread. They are intended only when the actions are done in the background. runonUIthread inside doInBackground will not help you. And this is normal behavior for the progressdialog to be visible only for few seconds.
You have two doInBackground() methods inside your AsyncTask Class. Remove the runOnUiThread() from First doInBackground() and move it to second doInBackground() which has #Override annotation.
I don't know whether you wantedly written two doInBackground() methods or by mistake but it is not good to have such confusion between the Method. Your AsyncTask is not calling the first doInBackground() and it will call doInBackground() which has #Override annotation. So your ProgressDialog is dismissed in 1 second of time as it returns null immediately.