I am using a freind to download a picture and set in the ImageView; however, I get this error:
Only the original thread that created a view hierarchy can touch its views.
This is my code.
ImageView profilePicture =....
Thread thread = new Thread() {
#Override
public void run() {
profilePic.setImageBitmap(image_profile);
}
};
thread.start();
The image_profile Bitmap is a valid Bitmap file. (I checked it via debug.)
This thread is running in the OnCreate method.
You cannot update your UI directly from the Thread. Instead, use runOnUiThread() or equivalent.
Replace this:
profilePic.setImageBitmap(image_profile);
With this:
YourActivityName.this.runOnUiThread(new Runnable() {
#Override
public void run() {
profilePic.setImageBitmap(image_profile);
}
});
You cannot update ui on another thread. Update ui on the main ui thread as below
Thread thread = new Thread()
{
#Override
public void run() {
runOnUiThread(new Runnable() //run on ui thread
{
public void run()
{
profilePic.setImageBitmap(image_profile);
}
});
}
};
thread.start();
The problem isn't about the Bitmap. The problem is that you are trying to do UI stuff in a separate Thread. With the code you've given, there is no reason for the Thread. Remove the Thread. If you are doing other things that you aren't showing then you can use runOnUiThread or an AsyncTask and update the ImageView in any method other than doInBackground() as it doesn't run on the UI
Related
I am getting data from a RoomDB then using a custom adapter to present this data in a recycler view.
But I am occasionally getting this error, "Only the original thread that created a view hierarchy can touch its views."
This is where the error happens
((MyActivity)context).runOnUiThread(new Runnable() {
#Override
public void run() {
setData();
}
});
I don't understand what is from as I am using the context of the activity the recycler view is in and then running the thread on the UI thread.
You have to move the task that updates the UI onto the main thread.
Try like this
runOnUiThread(new Runnable() {
#Override
public void run() {
// UI Updates
}
});
Sorry everyone this has been asked a few times but I just do not understand any of the answers because most are about timed UI updates. So I have a backgroundTasks thread that is called when my app first starts(Does network connections so..I think that's how you do it?)
public class MainActivity extends ActionBarActivity {
String data[][];
int arrayPosition = 0;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
runBackgroundTask();
}
Here is my thread..
public void runBackgroundTask(){
new Thread(new Runnable() {
public void run() {
data = pullSchedule(data);
updateUI(data,arrayPosition);
}
}).start();
}
All it does is call a method pullSchedule which updates a 2D array with a webcrawler. So my problem comes when I call the updateUI method which is also used by two buttons to cycle through the array data which work perfectly fine. It's just when the thread first runs if I try to update the UI I get an error.
public void upDateUI(String data[][], int arrayPosition){
TextView gameTime =(TextView)findViewById(R.id.txtDate);
//more but deleted to save space :)
}
I have researched why I cannot update the UI from the background thread but I don't understand how to fix this? I thought about putting that entire method into the runOnUiThread(new Runnable()but then I believe my data and arrayPosition have to be declared final because of an inner class..First Android app just lost. Thanks for any help.
you can use asyntask for this from which you can update ui
public myAsyn extends AsyncTask<Void,Void,Void>
{
#Override
protected String doInBackground(Void... params) {
data = pullSchedule(data);
return null;
}
#Override
protected void onPostExecute(String result) {
updateUI(data,arrayPosition);
}
}
doInBackground runs on seperate thread whereas onPostExecute runs on Ui thread therefore you can update UI from there.
You are on the right track. The reason your app is crashing is because you are attempting to update a UI element off of the UI thread. To avoid this, you can either do as RichS suggested, and use an AsyncTask which will execute onPostExecute() on the UI thread, or surround your updateUI() call in your background thread with runOnUiThread(new Runnable() {....
I have following code to run a function in another thread:
Button buttonb = (Button) this.findViewById(R.id.buttonb);
buttonb.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
…
progressBar.setVisibility(View.VISIBLE);
Thread thread = new Thread() {
#Override
public void run() {
matrixOperation(sourcePhoto);
}
};
thread.start();
progressBar.setVisibility(View.INVISIBLE);
…
}
});
But on running i am getting this error:
Can't create handler inside thread that has not called Looper.prepare()
I searched and found that one reason for this error is “You cannot execute an AsyncTask from a background thread. See the "Threading Rules" section of” But this is not background thread I am calling it from my Main Activity.
Please tell me how I can fix this.
The Handler class uses Loopers to perform its scheduling, and threads that have just been created does not have an associated looper – hence the error.
As you have not provided the handler creation code, I'm assuming you want to call code on the main thread. In this case, create the Handler as follows:
Handler handler = new Handler(Looper.getMainLooper());
Anything scheduled to run on that Handler will execute on the main Looper, which is running on the main thread.
I am following this tutorial to have a loading screen in my program. The tutorial says my activity should Sleep() using the Sleep() command, however it does not recognize Sleep() as a function and provides me with an error, asking if I would like to create a method called Sleep().
Here is the code sample:
public class LoadingScreenActivity extends Activity {
//Introduce an delay
private final int WAIT_TIME = 2500;
#Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
System.out.println("LoadingScreenActivity screen started");
setContentView(R.layout.loading_screen);
findViewById(R.id.mainSpinner1).setVisibility(View.VISIBLE);
new Handler().postDelayed(new Runnable(){
#Override
public void run() {
//Simulating a long running task
this.Sleep(1000);
System.out.println("Going to Profile Data");
/* Create an Intent that will start the ProfileData-Activity. */
Intent mainIntent = new Intent(LoadingScreenActivity.this,ProfileData.class);
LoadingScreenActivity.this.startActivity(mainIntent);
LoadingScreenActivity.this.finish();
}
}, WAIT_TIME);
}
}
You can use one of the folllowing methods:
Thread.sleep(timeInMills);
or
SystemClock.sleep(timeInMills);
SystemClock.sleep(milliseconds) is a utility function very similar to Thread.sleep(milliseconds), but it ignores InterruptedException. Use this function for delays if you do not use Thread.interrupt(), as it will preserve the interrupted state of the thread.
The function is Thread.sleep(long).
Note, however, that you should not perform a sleep on the UI thread.
The code you posted is horrible. Please don't use that on an actual device. You will get an "Application Not Responding" error if you run something similar to this.
If you're using Handlers, keep in mind that a Handler is created on the thread where it runs. So calling new Handler().post(... on the UI thread will execute the runnable on the UI thread, including this "long running operation". The advantage is that you can create a Handler to the UI Thread which you can use later, as shown below.
To put the long running operation into a background thread, you need to create a Thread around the runnable, as shown below. Now if you want to update the UI once the long running operation is complete, you need to post that to the UI Thread, using a Handler.
Note that this functionality is a perfect fit for an AsyncTask which will make this look a lot cleaner than the pattern below. However, I included this to show how Handlers, Threads and Runnables relate.
public class LoadingScreenActivity extends Activity {
//Introduce a delay
private final int WAIT_TIME = 2500;
private Handler uiHandler;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
uiHandler = new Handler(); // anything posted to this handler will run on the UI Thread
System.out.println("LoadingScreenActivity screen started");
setContentView(R.layout.loading_screen);
findViewById(R.id.mainSpinner1).setVisibility(View.VISIBLE);
Runnable onUi = new Runnable() {
#Override
public void run() {
// this will run on the main UI thread
Intent mainIntent = new Intent(LoadingScreenActivity.this,ProfileData.class);
LoadingScreenActivity.this.startActivity(mainIntent);
LoadingScreenActivity.this.finish();
}
};
Runnable background = new Runnable() {
#Override
public void run() {
// This is the delay
Thread.Sleep( WAIT_TIME );
// This will run on a background thread
//Simulating a long running task
Thread.Sleep(1000);
System.out.println("Going to Profile Data");
uiHandler.post( onUi );
}
};
new Thread( background ).start();
}
use Thread.sleep(1000);
1000 is the number of milliseconds that the program will pause.
try
{
Thread.sleep(1000);
}
catch(InterruptedException ex)
{
Thread.currentThread().interrupt();
}
Keep in mind: Using this code is not recommended, because it is a delay of time but without control and may need more or less time.
I have a simple function that shows loading spinner while fetching data (usually takes 7 seconds or so)
private void load_data(View v)
{
task_complete = false;
progressBar = new ProgressDialog(v.getContext());
progressBar.setCancelable(false);
progressBar.setMessage("Fetching data ...");
progressBar.setProgressStyle(ProgressDialog.STYLE_SPINNER);
progressBar.show();
try
{
Log.v("thread", "Starting thread");
new Thread(new Runnable()
{
public void run()
{
while(!task_complete)
{
fetch_data();
try
{
Thread.sleep(1000);
}
catch(InterruptedException e)
{
e.printStackTrace();
}
}
progressBar.dismiss();
}
}).start();
Log.v("thread", "Thread finished successfully");
}
catch(Exception e)
{
Log.v("thread", "fail "+e.toString());
}
}
The problem I have is that the function gets called by onClick via
load.setOnClickListener(new View.OnClickListener()
{
public void onClick(View v)
{
load_data(v);
show_data(v); // shows the data on a spinner
}
});
And when I press the load button the second time I get an error. My log does show
Starting thread
Thread finished successfully
But somehow the app dies with an error saying
03-27 02:48:39.282: E/AndroidRuntime(956): Uncaught handler: thread Thread-9 exiting due to uncaught exception
03-27 02:48:39.293: E/AndroidRuntime(956): android.view.ViewRoot$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
03-27 02:48:39.293: E/AndroidRuntime(956): at android.view.ViewRoot.checkThread(ViewRoot.java:2683)
I would greatly appreciate it if someone can show me or explain to me what causes the error
The problem is that your progressBar.dismiss(); is executed in another thread, to make it run in UI thread, do this:
runOnUiThread(new Runnable() {
#Override
public void run() {
progressBar.dismiss();
}
});
ProgressDialog is a View and you can access it in the UI thread (or main thread) only. Use AsyncTask instead of threads.
EDIT
This official link will help you get the hang of AsyncTask. The thing to remember is doInBackground() method runs in separate thread where you should put your data loading method i.e. fetch_data(). Once the method completed execution, onPostExecute() will get called, which will run on UI thread, where you can dismiss the dialog. You can start the dialog in the onPreExecute() method.
Though in this context you do not need the onProgressUpdate() method, but just FYI, it is used to update the Views in UI thread while the loading is still working using publishProgress() call (In case you use the AsyncTask in future).
PS: Only the doInBackground() method runs in separate thread, every other method runs in UI thread. The rule about not accessing the View in any other thread except the UI one, still applies here.