Android: Synchronizing Threads and Handler
You are implementing a couple of threads, and the order of the operations you are trying to do is not deterministic.
For example, it is possible "showFrame.Runable().run()" executed before getFrame.Runable().run().
- The "synchronize" key word does not help because when the work is down in separate thread. The synchronize function call will return, and lock will be released.
- The "locks" does not help to make sure the right order as well.
My suggestion is to use AsyncTask, http://developer.android.com/reference/android/os/AsyncTask.html. You can do something like this:
private class ProcessFrameTask extends AsyncTask {
protected void doInBackground(Object... objs) {
getFrame(); // Copy the frame
calculateFrame(); // Do your magic
}
protected void onPostExecute(Long result) {
showFrame(); // Post the result back to main thread
}
}
No multiple threading and cooperation, just one Worker thread does all the work, and post the result back to main thread.
Admin
Updated on October 26, 2020Comments
-
Admin over 3 years
I am having some trouble with my App. I'm very new to Android development so i hope it's an easy mistake. So I'm trying to write an app that gets some raw data via Wifi(first Thread), do some calculations(second Thread), create a Bitmap out of the calculated Data(third Thread) and update the Display(Handler). Some Parameters are adjusted by SeekBars. Everything works fine. But sometimes when I change the seekBarValues the Picture isn't updated Anymore. the Threads and the Handler are still running so i dont't get an Error.
Here some Code:
MainActivity:
public class MainActivity extends Activity implements OnClickListener { private Handler outputHandler = new Handler(); private SeekBar seekBarBrightness, seekBarContrast, seekBarGamma; public static volatile double gamma = 1; public static volatile double brightness = 500; public static volatile double contrast = 500; public static volatile double min = 0; public static volatile double max = 0; public static volatile boolean isRunning = false; public static volatile int r = 0; public static volatile int g = 0; public static volatile int b = 0; public static volatile int width = 400; public static volatile int height = 250; public volatile double inputExchangeFrame[][ ]= new double[400][250], outputExchangeFrame[][]= new double[400][250]; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); seekBarBrightness = (SeekBar) findViewById(R.id.seekBarBrightness); seekBarContrast = (SeekBar) findViewById(R.id.seekBarContrast); SeekBarGamma = (SeekBar) findViewById(R.id.seekBarGamma); newImage = Bitmap.createBitmap(width, height, BitmapConfig.ARGB_8888); picture.setImageBitmap(newImage); } @Override public void onClick(View v) { if(v==toggleButtonStartStop){ if(toggleButtonStartStop.isChecked()==true){ isRunning=true; getFrame(); calculateFrame(); showFrame(); } else{ isRunning = false; } } } }
And the Other Methods declared also in MainACtivity: getFrame():
private synchronized void getFrame(){ inputThread = new Runnable(){ public void run(){ while(isRunning == true){ //inputFrame fron WIFI inputExchangeFrameLock.lock(); //synchronized(inputExchangeFrame){ for(int x_1=0 ; x_1<width ; x_1++){ for(int y_1=0 ; y_1<height ; y_1++){ inputExchangeFrame[x_1][y_1]=inputFrame[x_1][y_1]; } } //} inputExchangeFrameLock.unlock(); try { Thread.sleep(120); } catch (InterruptedException e) { e.printStackTrace(); } } } };new Thread(inputThread).start(); };
calculateFrame:
private synchronized void calculateFrame(){ calculationThread = new Runnable(){ public void run(){ while(isRunning == true){ //get Data from InputThread to applicate several Filter inputExchangeFrameLock.lock(); //synchronized(inputExchangeFrame){ for(int x_2=0 ; x_2<width ; x_2++){ for(int y_2=0 ; y_2<height ; y_2++){ calculationFrame[x_2][y_2]=inputExchangeFrame[x_2][y_2]; } } //} inputExchangeFrameLock.unlock(); //Do some calculations on calculationFrame outputExchangeFrameLock.lock(); //synchronized(outputExchangeFrame){ for(int x_3=0 ; x_3<width ; x_3++){ for(int y_3=0 ; y_3<height ; y_3++){ outputExchangeFrame[x_3][y_3] = calculationFrame[x_3][y_3]; } } //} outputExchangeFrameLock.unlock(); } } }; new Thread(calculationThread).start(); };
showFrame():
private synchronized void showFrame(){ outputThread = new Runnable(){ public void while(isRunning == true){ contrast = seekBarContrast.getProgress() +1; brightness = seekBarBrightness.getProgress() + 1; gamma = seekBarGamma.getProgress() + 1; outputExchangeFrameLock.lock(); //synchronized(outputExchangeFrame){ for(int x_4=0 ; x_4<width ; x_4++){ for(int y_4=0 ; y_4<height ; y_4++){ outputFrame[x_4][y_4] = outputExchangeFrame[x_4][y_4]; } } //} outputExchangeFrameLock.unlock(); for (int x_14=0 ; x_14<width ; x_14++){ for(int y_14=0; y_14<height; y_14++){ //Calculation of r,g,b using gamma, brightness and contrast } synchronized(newImage){ newImage.setPixel(x_14, y_14, Color.rgb(r,g,b)); } } outputHandler.removeCallbacks(pictureUpdate); outputHandler.post(pictureUpdate); try { Thread.sleep(50); } catch (InterruptedException e) { e.printStackTrace(); } } } }; new Thread(outputThread).start(); };
and the Handler:
private Runnable pictureUpdate = new Runnable(){
public void run(){ synchronized(newImage){ picture.setImageBitmap(newImage);
} }
};I know thats a lot of Text. But I really don't know where to start searching and what I could do to find the mistake.
Any suggestions would be great!
thanks
Michael