Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 5 years ago.
Improve this question
This Code means that if I Click a button, a progress bar start 0 to 100%. And I want to make the progress bar reset, when I click a button before the progress bar reaches 100%.
Here is a part of my code.
This code is button listener.
public void Cal_btn(View v) {
Message msg;
switch (v.getId()) {
case R.id.Square:
if (Number.getText().toString().length() == 0) {
Toast.makeText(getApplicationContext(), "숫자를 입력하세요.", Toast.LENGTH_LONG).show();
} else {
pThread = new ProThread(pHandler);
pThread.setDaemon(true);
pThread.start();
Cal_Result.setVisibility(View.GONE);
progress.setVisibility(View.VISIBLE);
msg = new Message();
msg.what = 1;
msg.arg1 = Integer.parseInt(Number.getText().toString());
mThread.mBackHandler.sendMessage(msg);
}
break;
}
}
And this code is handler.
Handler pHandler = new Handler(){
public void handleMessage(Message msg){
if(msg.what == 3){
if(msg.arg1 == 100){
Cal_Result.setVisibility(View.VISIBLE);
progress.setVisibility(View.GONE);
}else{
progress.setProgress(msg.arg1);
}
}
}
};
And this code is Thread run code.
class ProThread extends Thread{
int proNum = 0;
Handler pHandler;
ProThread(Handler handler){
pHandler = handler;
}
public void run(){
while(proNum != 100) {
proNum++;
Message msg = new Message();
msg.what = 3;
msg.arg1 = proNum;
pHandler.sendMessage(msg);
try {
Thread.sleep(10);
}catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
Add a boolean member variable as a marker for "ProgressBar" started or not.
boolean isProgressBarRun;
When the button is clicked, change the status of this variable.
And if the button is clicked at first time, send a message.
And when you handle the message, re-send the messages every 10 ms in your "public void handleMessage(Message msg)" method.
And your onClick method can be written like below:
boolean isProgressBarRun = false;
...
public void Cal_btn(View v) {
Message msg;
switch (v.getId()) {
case R.id.Square:
if (Number.getText().toString().length() == 0) {
Toast.makeText(getApplicationContext(), "숫자를 입력하세요.", Toast.LENGTH_LONG).show();
} else {
if (isProgressBarRun) {
isProgressBarRun = false;
msg = new Message();
msg.what = 4; // to stop the progress bar
mThread.mBackHandler.sendMessage(msg);
msg.what = 3;
msg.arg1 = Integer.parseInt(Number.getText().toString());
mThread.mBackHandler.sendMessage(msg);
} else {
isProgressBarRun = true;
Cal_Result.setVisibility(View.GONE);
progress.setVisibility(View.VISIBLE);
msg = new Message();
msg.what = 1;
msg.arg1 = Integer.parseInt(Number.getText().toString());
mThread.mBackHandler.sendMessage(msg);
}
}
break;
}
}
Your handler can be changed like below:
Handler pHandler = new Handler(){
public void handleMessage(Message msg){
if(msg.what == 4){
progress.setVisibility(View.GONE);
} else {
progress.setProgress(msg.arg1);
Message message = new Message();
message .what = 3;
message .arg1 = msg.arg1 + 1;
pHandler.sendMessageDelayed(message, 10);
}
}
};
In summary, you don't need to implement Thread.
Upper codes are incorrect, just see the concept please.
Related
I'm working on a countdown that shows seconds remaining to start of the game. So I put TextView into middle of layout and in for loop I am changing the text of TextView, playing the sound using MediaPlayer, then waits 1 second and repeat the proccesss.
The problem is that my text view is not updating - after finishing whole for loop it just change TextView to last text that should be displayed. But since all sounds was played, I can say that Activity is running normaly. So I'm looking for some easy way how to update my UI. I saw some examples of AsynTask, but I think that's too difficult solution for this simple problem. Also, I've tried using handle to change text, but it has got no effect.
My code:
This is in onResume() method:
//Using handler to delay countdown,
//so Activity have enough time to display view
hand.postDelayed((new Runnable(){
#Override
public void run() {
countdownToStart();
game.start();
}
}), 1000);
countdownToStart() method:
protected void countdownToStart(){
int soundSource[] = {R.raw.cntdwn_three, R.raw.cntdwn_two, R.raw.cntdwn_one, R.raw.cntdwn_go};
final String nums[] = {"3", "2", "1", "GO"};
final TextView countdownText = (TextView) findViewById(R.id.challenge_countdown_text);
Handler hand2 = new Handler();
//4 different texts = 4 cycles of for loop
for(int i = 0; i < 4; i++){
//Load sound
for(int x = 0; x < 5; x++){
countdownSound = MediaPlayer.create(getApplicationContext(), soundSource[i]);
if(countdownSound != null)
break;
}
if(countdownSound == null){
Toast.makeText(getApplicationContext(), R.string.sound_load_error, Toast.LENGTH_SHORT).show();
onBackPressed();
}
countdownSound.start();
//Set textview
countdownText.setText(nums[i]);
if(i == 3)
countdownText.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 200);
//Delay between countdowns
SystemClock.sleep(1000);
//Release MediaPlayer
countdownSound.release();
}
}
}
Try RunOnUIThread by creating a new Thread
Updated
final TextView countdownText = (TextView) findViewById(R.id.challenge_countdown_text);
new Thread(new Runnable() {
#Override
public void run() {
// TODO Auto-generated method stub
try{
for(int i = 0; i < 4; i++){
//Load sound
for(int x = 0; x < 5; x++){
countdownSound = MediaPlayer.create(getApplicationContext(), soundSource[i]);
if(countdownSound != null)
break;
}
if(countdownSound == null){
Toast.makeText(getApplicationContext(), R.string.sound_load_error, Toast.LENGTH_SHORT).show();
onBackPressed();
}
countdownSound.start();
//Set textview
runOnUiThread(new Runnable() {
#Override
public void run() {
// TODO Auto-generated method stub
countdownText.setText(nums[i]);
if(i == 3)
countdownText.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 200);
}
});
Thread.sleep(1000);
}
}
catch(Exception e){
// handle exception
}
}
}).start();
//Delay between countdowns
SystemClock.sleep(1000);
//Release MediaPlayer
countdownSound.release();
}
I'm 7 years behind schedule, but..
If you're using view binding,
And already setup binding, check if in setContentView it's R.layout.whateverlayout or binding.getRoot()
I am using this code to play a sound
final MediaPlayer mp = MediaPlayer.create(this, R.raw.sound);
mp.setOnCompletionListener(new OnCompletionListener() {
#Override
public void onCompletion(MediaPlayer mp) {
mp.release();
}
});
It works fine on its own, however there was a problem after I added an animation that extends ImageView, which refreshes(by calling handler.postDelayed) the image resource at an interval about 30ms to create animation. The problem is that when the animation starts, it terminates the the playing of the sound. Here is the code for the Runnable that refreshes the ImageView.
private Runnable runnable = new Runnable () {
public void run() {
String name = "frame_" + frameCount;
frameCount ++;
int resId = mContext.getResources().getIdentifier(name, "drawable", mContext.getPackageName());
imageView.setImageResource(resId);
if(frameCount < totalFrameCount) {
mHandler.postDelayed(runnable, interval);
}
}
};
I also tried to use a thread that calls the anmiationView.postInvalidate to do the animation, however it has the same problem. Please help. Thanks
Edit:
It looks like the problem is due to WHEN the animation is called. Previously I called it in the onActivityResult of the activity. Looks like this is not the right place to call. Now I put the animation view in a popupWindow and play it there, it works properly. Not sure exactly why.
in handler's comments :
"A Handler allows you to send and process {#link Message} and Runnable
objects associated with a thread's {#link MessageQueue}. Each Handler
instance is associated with a single thread and that thread's message
queue. When you create a new Handler, it is bound to the thread /
message queue of the thread that is creating it -- from that point on,
it will deliver messages and runnables to that message queue and execute
them as they come out of the message queue."
so, the problem may be caused by both of animation and media playing operations are in
the same message queue own by which thread create the handler (let's say the main thread).
if the animation loops for ever, then the media player will hardly get any chance to run.
you could take it a try with HandlerThread, the thread will contain a new looper for the
handler created from it, all the runnables added to that handler will be running in another
individual thread.
the animation thread and the media play thread should be running in the different threads not
scheduling in the same one.
hope, it helps.
the HandlerThread usage and some discuss looks like this :
How to create a Looper thread, then send it a message immediately?
maybe it is caused by your miss arranged codes, i take it a try on my nexus 4 with android version 4.4.2, even no any cache tech, the animation and music works like a charm...
here is the major codes :
public class MainActivity extends Activity implements View.OnClickListener {
protected static final String TAG = "test002" ;
protected static final int UPDATE_ANI = 0x0701;
protected static final int UPDATE_END = 0x0702;
protected static final int[] ANI_IMG_IDS = {R.raw.img1, R.raw.img2, R.raw.img3, R.raw.img4,
R.raw.img5, R.raw.img6, R.raw.img7};
protected static final int[] BTN_IDS = {R.id.btnStart, R.id.btnStop};
protected android.os.Handler aniHandler = null; // async update
protected boolean isAniRunning = false ;
protected int aniImgIndex = 0 ;
protected ImageView aniImgView = null ;
protected MediaPlayer mediaPly = null ;
// animation timer
class AniUpdateRunnable implements Runnable {
public void run() {
Message msg = null ;
while (!Thread.currentThread().isInterrupted() && isAniRunning) {
msg = new Message();
msg.what = UPDATE_ANI;
aniHandler.sendMessage(msg);
try {
Thread.sleep(500);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
break ;
}
}
msg = new Message() ;
msg.what = UPDATE_END ;
aniHandler.sendMessage(msg) ;
}
}
protected void prepareMediaPlayer(MediaPlayer mp, int resource_id) {
AssetFileDescriptor afd = getResources().openRawResourceFd(resource_id);
try {
mp.reset();
mp.setDataSource(afd.getFileDescriptor(), afd.getStartOffset(), afd.getDeclaredLength());
afd.close();
mp.prepare();
} catch (IllegalArgumentException e) {
Log.d(TAG, "IlleagalArgumentException happened - " + e.toString()) ;
} catch(IllegalStateException e) {
Log.d(TAG, "IllegalStateException happened - " + e.toString()) ;
} catch(IOException e) {
Log.d(TAG, "IOException happened - " + e.toString()) ;
}
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// init : buttons onclick callback
{
Button btn;
int i;
for (i = 0; i < BTN_IDS.length; i++) {
btn = (Button) findViewById(BTN_IDS[i]);
btn.setOnClickListener(this);
}
}
// init : update animation handler callback
{
aniHandler = new Handler() {
public void handleMessage(Message msg) {
switch (msg.what) {
case UPDATE_ANI:
updateAniImages();
break ;
case UPDATE_END:
updateAniEnd();
break ;
default:
break;
}
}
};
}
// init : prepare image view
{
aniImgView = (ImageView)findViewById(R.id.imgAni) ;
mediaPly = MediaPlayer.create(this, R.raw.happyny) ;
mediaPly.setLooping(true);
}
}
protected void updateAniImages() {
if(aniImgIndex >= ANI_IMG_IDS.length) {
aniImgIndex = 0 ;
}
InputStream is = getResources().openRawResource(ANI_IMG_IDS[aniImgIndex]) ;
Bitmap bmp = (Bitmap) BitmapFactory.decodeStream(is) ;
aniImgView.setImageBitmap(bmp);
aniImgIndex++ ;
}
protected void updateAniEnd() {
aniImgIndex = 0 ;
aniImgView.setImageBitmap(null);
}
#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;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
#Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.btnStart:
isAniRunning = true ;
// no re-enter protectiion, should not be used in real project
new Thread(new AniUpdateRunnable()).start();
mediaPly.start();
break;
case R.id.btnStop:
isAniRunning = false ;
mediaPly.stop();
prepareMediaPlayer(mediaPly, R.raw.happyny);
break;
default:
break;
}
}
}
the major project codes and test apk should be find here :
apk installer
source code
I have a child thread running to do a task infinitely. I want to (1) constantly send data back to the UI thread, and (2) occasionally send data (corresponding to buttons) to the child thread to pause/continue the infinite task. My problem is that the child thread gets stuck in the looper, meaning the task does not execute.
My questions is this: How do I get the child thread to receive messages from the UI thread without blocking the infinite task?
This is what I have so far:
For task (1), I have a handler in my UI thread, which works, and an infinite loop in the child thread that sends back a message, which works by itself.
In UI thread:
mMainHandler = new Handler() {
public void handleMessage(Message msg) {
Bundle b;
b = msg.getData();
if (msg.what==1)
Log.i("main", "from child (running) - " + b.getBoolean("running"));
else if (msg.what == 2)
Log.i("main", "from child (count) - " + b.getInt("count"));
}
};
In child thread (currently using a dummy task until I get the framework worked out):
while (true) {
if (running) {
try {
curCount += up;
if (curCount == maxCount)
up = -1;
else if (curCount == minCount)
up = 1;
Thread.sleep(1000);
} catch (InterruptedException e) {
Log.e("", "local Thread error", e);
}
Bundle b = new Bundle(1);
b.putInt("count", curCount);
Message toMain = mMainHandler.obtainMessage();
toMain.what = 2;
toMain.setData(b);
mMainHandler.sendMessage(toMain);
}
}
For task (2), I have a method in my UI thread corresponding to a button press that sends a message to the child thread, which works, and a handler in the child thread, which works by itself.
In UI thread:
private void sendRunning(boolean running) {
if (mChildHandler != null) {
Bundle b = new Bundle(1);
b.putBoolean("running", running);
Message msg = mChildHandler.obtainMessage();
msg.what = 1;
msg.setData(b);
mChildHandler.sendMessage(msg);
}
}
In child thread:
Looper.prepare();
mChildHandler = new Handler() {
public void handleMessage(Message msg) {
Bundle b;
if (msg.what==1){
b = msg.getData();
running = b.getBoolean("running");
Log.i(INNER_TAG, "from main (running) - " + b.getBoolean("running"));
Log.i(INNER_TAG, "running - " + running);
try {
Message toMain = mMainHandler.obtainMessage();
toMain.what = 1;
toMain.setData(b);
mMainHandler.sendMessage(toMain);
} finally {}
}
}
};
Looper.loop();
Each one of those scenarios works fine alone, but trying to do both at the same time is the problem. If I put the infinite task after the Looper.loop(), it is never reached. If I put it before the Looper.prepare(), it is run once. If I put it withing the looper, it is still only run once.
Any ideas would be greatly appreciated :)
Here is my full code (minus package/imports) for reference:
public class MainActivity extends Activity {
Thread thread;
private Handler mMainHandler, mChildHandler;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mMainHandler = new Handler() {
public void handleMessage(Message msg) {
Bundle b;
b = msg.getData();
if (msg.what==1)
Log.i("main", "from child (running) - " + b.getBoolean("running"));
else if (msg.what == 2)
Log.i("main", "from child (count) - " + b.getInt("count"));
}
};
thread = new ChildThread();
thread.start();
// Get a reference to the button
Button buttonStart = (Button)findViewById(R.id.btnStart);
Button buttonStop = (Button)findViewById(R.id.btnStop);
// Set the click listener to run my code
buttonStart.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Toast.makeText(MainActivity.this,
"Starting...", Toast.LENGTH_SHORT).show();
sendRunning(true);
}
});
buttonStop.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Toast.makeText(MainActivity.this,
"Stopping...", Toast.LENGTH_SHORT).show();
sendRunning(false);
}
});
}
private void sendRunning(boolean running) {
if (mChildHandler != null) {
Bundle b = new Bundle(1);
b.putBoolean("running", running);
Message msg = mChildHandler.obtainMessage();
msg.what = 1;
msg.setData(b);
mChildHandler.sendMessage(msg);
}
}
#Override
protected void onDestroy() {
Log.i("tag", "stop looping the child thread's message queue");
mChildHandler.getLooper().quit();
super.onDestroy();
}
class ChildThread extends Thread {
private static final String INNER_TAG = "ChildThread";
private boolean running = true;
final int maxCount = 10;
final int minCount = 0;
public int curCount = minCount;
private int up = 1;
public void run() {
while (true) {
if (running) {
try {
curCount += up;
if (curCount == maxCount)
up = -1;
else if (curCount == minCount)
up = 1;
Thread.sleep(1000);
} catch (InterruptedException e) {
Log.e("", "local Thread error", e);
}
Bundle b = new Bundle(1);
b.putInt("count", curCount);
Message toMain = mMainHandler.obtainMessage();
toMain.what = 2;
toMain.setData(b);
mMainHandler.sendMessage(toMain);
}
this.setName("child");
Looper.prepare();
mChildHandler = new Handler() {
public void handleMessage(Message msg) {
Bundle b;
if (msg.what==1){
b = msg.getData();
running = b.getBoolean("running");
Log.i(INNER_TAG, "from main (running) - " + b.getBoolean("running"));
Log.i(INNER_TAG, "running - " + running);
try {
Message toMain = mMainHandler.obtainMessage();
toMain.what = 1;
toMain.setData(b);
mMainHandler.sendMessage(toMain);
} finally {}
}
}
};
Log.i(INNER_TAG, "Child handler is bound to - " +
mChildHandler.getLooper().getThread().getName());
Looper.loop();
}
}
}
}
Just Use Intent service rather then this thread so you can manage all UI of your update and what ever you want to do with UI in intent service one broadcast receiver is using and its very easy to handle threads and infect your your UI is nit hand or lock while your background process run .
I ended up just using a variable time for the thread to avoid the situation. Thanks for the advice.
I am new to Android and found out that to keep updating the main view I had to create a thread to handle various process and then pass back updates to the main view. I decided to use the Handler class to do this. The view in this example has a button to activate the code and a tablelayout to display the messages received - representing a stage of the process.
The problem is that I send 8 different messages and I can see 8 messages coming back in the handler, but all 8 have the same contents as message 8 only.
I was expecting the handler to pick the messages up in sequence.
Any suggestions on a better way of doing this always welcome to learn.
Here is the code:
`
public class messageHandlerTest extends Activity {
protected TextView textView;
protected Handler handler = new Handler() {
#Override
public void handleMessage(Message msg) {
String[] status = (String[]) msg.obj;
createTableRow(status);
Log.e("Got a new message",status[0]+":"+status[1]);
}
};
Button btnStartProgress;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textView = (TextView) findViewById(R.id.statusText);
textView.setText("");
//Getting response from server with Network SSID and Password
Button connectButton = (Button)findViewById(R.id.connectButton);
addListenerOnButton();
} // End of create
protected class connectWiFi extends Thread implements Runnable {
//tokens1 = new String[0];
public void run(){
try {
String[] messageString = new String[2];
Message message = handler.obtainMessage();
messageString[0]="OK";
messageString[1]="Number 1";
message.obj = messageString;
handler.sendMessage(message);
message = handler.obtainMessage();
messageString[0]="OK";
messageString[1]= "Number 2";
message.obj = messageString;
handler.sendMessage(message);
message = handler.obtainMessage();
messageString[0]="OK";
messageString[1] = "Number 3";
message.obj = messageString;
handler.sendMessage(message);
message = handler.obtainMessage();
messageString[0]="OK";
messageString[1] = "Number 4";
message.obj = messageString;
handler.sendMessage(message);
message = handler.obtainMessage();
messageString[0] = "OK";
messageString[1] = "Number 5";
message.obj = messageString;
handler.sendMessage(message);
message = handler.obtainMessage();
messageString[0] = "OK";
messageString[1] = "Number 6";
message.obj = messageString;
handler.sendMessage(message);
message = handler.obtainMessage();
messageString[0] = "OK";
messageString[1] = "Number 7";
message.obj = messageString;
handler.sendMessage(message);
message = handler.obtainMessage();
messageString[0] = "OK";
messageString[1] = "Number 8";
message.obj = messageString;
handler.sendMessage(message);
} catch (Exception e) {
e.printStackTrace();
Log.e("Exception found","bugger");
}
}// End or run
}// End of class
public void addListenerOnButton() {
btnStartProgress = (Button) findViewById(R.id.connectButton);
btnStartProgress.setOnClickListener(
new OnClickListener() {
#Override
public void onClick(View v) {
connectWiFi connectwifi = new connectWiFi();
connectwifi.start();
}
});
}
private void createTableRow(String[] stage) {
TableLayout tl = (TableLayout) findViewById(R.id.statusTable);
TableRow tr = new TableRow(this);
LayoutParams lp = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
tr.setLayoutParams(lp);
tr.setBackgroundColor(0xFFFFFFFF);
TextView tvStatus = new TextView(this);
tvStatus.setLayoutParams(lp);
tvStatus.setPadding(2,1,1,2);
tvStatus.setTextColor(0xFF000000);
tvStatus.setText(stage[0]); // Status
TextView tvStage = new TextView(this);
tvStage.setLayoutParams(lp);
tvStage.setPadding(2,1,1,2);
tvStage.setTextColor(0xFF000000);
tvStage.setText(stage[1]); // Stage
tr.addView(tvStatus);
tr.addView(tvStage);
tl.addView(tr, new TableLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT));
}
#Override
protected void onDestroy() {
super.onDestroy();
}
}
The result of this code looks like:
For sending data through handler you can use bundle as data of message object that you want to send to handler. Like this code :
// receieve message in handleMessage method of handler of your controller (e.g. on UI thread)
handler = new Handler() {
#Override
public void handleMessage(Message msg) {
Bundle b = msg.getData();
Integer value = b.getInt("KEY");
...
}
};
// Sending message in a background thread
new Thread(new Runnable() {
#Override
public void run() {
final Message msg = new Message();
final Bundle b = new Bundle();
Integer value = 1;
b.putInt("KEY", value);
msg.setData(b);
handler.sendMessage(msg);
}
).start();
I suspect what may be happening is that you continually modify the same reference String[] named messageString while never creating a new one. Passing that by reference and then continuing to change the values there are probably what's resulting in this outcome.
A few things,
When using handlers try to use the what field for return code. For instnace, your OK string (if it is just for a status) you would be better off defining int constant return types.
As JanBo mentioned, you don't want to be extending Thread and implementing Runnable.
It really depends on what you're trying to do exactly but the Handler message queue callback pattern is one of many you can choose to accomplish what you want. In the interest of learning another method, take a look at a blog post I wrote here which explains how you can delegate off-UI thread tasks to an IntentService and call back to your Activity when it finishes.
I suppose what's happening is that: messageString, which you create only once, is being updated while message is waiting in the queue. Change your code like this:
String[] messageString1 = new String[2];
Message message = handler.obtainMessage();
messageString1[0]="OK";
messageString1[1]="Number 1";
message.obj = messageString1;
handler.sendMessage(message);
String[] messageString2 = new String[2];
message = handler.obtainMessage();
messageString2[0]="OK";
messageString2[1]= "Number 2";
message.obj = messageString2;
handler.sendMessage(message);
....
....
I am not sure if I am doing this in the right place, but I thought I would post back my refactored code based on the help I received here and it might help someone else. This works well for me and the code looks quite neat, but any feedback on how this could be improved or made more efficient would always be appreciated. Also let me know if I am doing this in the wrong place!
public class messageHandlerTest2 extends Activity {
protected TextView textView;
protected Handler handler = new Handler() {
#Override
public void handleMessage(Message msg) {
createTableRow((mymessageObject) msg.obj);
}
}; //Set-up handler to be used later
Button btnStartProgress;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button connectButton = (Button) findViewById(R.id.connectButton);
addListenerOnButton();
} // End of create
protected class connectWiFi extends Thread {
public void run() {
try {
sendMessage(true,"Number 1"); // send if OK and a stage message
sendMessage(true,"Number 2");
sendMessage(true,"Number 3");
sendMessage(true,"Number 4");
sendMessage(true,"Number 5");
sendMessage(true,"Number 6");
sendMessage(true,"Number 7");
sendMessage(true,"Number 8");
sendMessage(true,"Number 9");
sendMessage(true,"Number 10");
sendMessage(true,"Number 11");
sendMessage(true,"Number 12");
} catch (Exception e) {
e.printStackTrace();
Log.e("Exception found", "bugger");
}
}// End or run
}// End of class
public void addListenerOnButton() {
btnStartProgress = (Button) findViewById(R.id.connectButton);
btnStartProgress.setOnClickListener(
new OnClickListener() {
#Override
public void onClick(View v) {
connectWiFi connectwifi = new connectWiFi();
connectwifi.start();
}
});
}
private void createTableRow(mymessageObject stage) {
String statusString;
TableLayout tl = (TableLayout) findViewById(R.id.statusTable);
TableRow tr = new TableRow(this);
LayoutParams lp = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
tr.setLayoutParams(lp);
tr.setBackgroundColor(0xFFFFFFFF);
TextView tvStatus = new TextView(this);
tvStatus.setLayoutParams(lp);
tvStatus.setPadding(2, 1, 1, 2);
tvStatus.setTextColor(0xFF000000);
if (stage.Status) {statusString = "OK";} else {statusString = "No";};
tvStatus.setText(statusString); // Status
TextView tvStage = new TextView(this);
tvStage.setLayoutParams(lp);
tvStage.setPadding(2, 1, 1, 2);
tvStage.setTextColor(0xFF000000);
tvStage.setText(stage.statusMessage); // Stage
tr.addView(tvStatus);
tr.addView(tvStage);
tl.addView(tr, new TableLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT));
}
#Override
protected void onDestroy() {
super.onDestroy();
}
private class mymessageObject { // Creates object of status flag and stage message
boolean Status;
String statusMessage;
mymessageObject(boolean newStatus, String newMessage){
Status = newStatus;
statusMessage = newMessage;
}
}
private void sendMessage (boolean status, String stageMessage) { // Handle sending message back to handler
Message message = handler.obtainMessage();
message.obj = new mymessageObject(status,stageMessage);
handler.sendMessage(message);
}
}
try this
Message m = Message.obtainMessage();
not
Message m = handler.obtainMessage();
when I call addAdapter() several times in background, sometimes I got some duplicate message. e.g. when I call addAdapter(item1, item2, item3...), it prints item1, item2, item2...
ExaminationItem currentAddItem = null;
private void addAdapter(ExaminationItem item)
{
currentAddItem = item;
addhandler.sendEmptyMessage(1);
}
private Handler addhandler = new Handler() {
#Override
public void handleMessage(Message msg)
{
switch (msg.what) {
case 1:
if (currentAddItem != null) {
_adapter.add(currentAddItem);
Log.i(getClass().getName(), "---------------------------addhandler: currentAddItem._itemName = " + currentAddItem._itemName);
}
break;
default:
break;
}
}
};
That isn't surprising. Every time you call sendEmptyMessage(), you're adding a message to the thread's message queue. You're not adding your item to the queue, you're just sending a message to the Handler to access whatever the value of currentAddItem is at the time that the Handler processes the message. It doesn't get to see what the value was at the time that you sent the message. So you're likely to see both skipped items and duplicate items.
private void addAdapter(ExaminationItem item)
{
Message message = addhandler.obtainMessage();
message.what = 1;
message.obj = item;
addhandler.sendMessage(message);
}
private Handler addhandler = new Handler() {
public void handleMessage(Message msg)
{
switch (msg.what) {
case 1:
if (msg.obj != null) {
_adapter.add((ExaminationItem) msg.obj);
examination_scanner_detail_tv.setText("detect to keep fit.");
Log.i(getClass().getName(), "addhandler: msg.obj = " + msg.obj);
}
break;
default:
break;
}
}
};