I am trying to measure the wifi signal strength 5 times (after every second) & display it in a TextView. I simultaneously write it to external storage as well. Everything runs fine except that I am NOT able to see the results in real time. The app would run for 5 secs with a blank screen and then show up the results (which are correct btw, i.e 5 different readings after each second).
I'd want to see the results updating as soon the new value is calculated in each iteration of the for loop.
Thanks
Here is the code
public class WifiDemo extends Activity implements OnClickListener {
private static final String TAG = "WiFiDemo";
WifiManager wifi;
TextView textStatus;
Button buttonScan;
/** Called when the activity is first created. */
/*
* (non-Javadoc)
*
* #see android.app.Activity#onCreate(android.os.Bundle)
*/
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
// Setup UI
textStatus = (TextView) findViewById(R.id.textStatus);
buttonScan = (Button) findViewById(R.id.buttonScan);
buttonScan.setOnClickListener(this);
// Setup WiFi
wifi = (WifiManager) getSystemService(Context.WIFI_SERVICE);
String state = Environment.getExternalStorageState();
if (Environment.MEDIA_MOUNTED.equals(state)) {
// Get WiFi status
runOnUiThread(new Runnable() {
public void run() {
try {
FileWriter fw = new FileWriter(
Environment.getExternalStorageDirectory()
+ "/bluetooth/wifi.txt");
for (int i = 0; i < 5; i++) {
WifiInfo info = wifi.getConnectionInfo();
Date d = new Date(System.currentTimeMillis());
String stat = "\n\nWiFi Status: " + info.getRssi()
+ " " + d.getHours() + ":" + d.getMinutes()
+ ":" + d.getSeconds();
textStatus.append(stat);
fw.write(stat);
fw.flush();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
fw.close();
}
catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
textStatus.append("something wrong");
}
}
});
}
}
}
You can try to create a handler to handle UI update tasks in the main thread. Do not update UI in your thread, instead, do it by passing handler messages to make sure this job is handled in the main thread. It works fine for me. I've modified some of your code here (I removed the write file part),
public class WifiDemo extends Activity implements OnClickListener {
private static final String TAG = "WiFiDemo";
private static final int WifiDetectStart = 0;
private static final int WifiDetectStop = 1;
private String stat;
WifiManager wifi;
TextView textStatus;
Button buttonScan;
Handler handler;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
// Setup UI
textStatus = (TextView) findViewById(R.id.textStatus);
buttonScan = (Button) findViewById(R.id.buttonScan);
buttonScan.setOnClickListener(this);
//setup handler
handler = new Handler(){
#Override
public void handleMessage(Message msg) {
if(msg.what == WifiDetectStart)
{
textStatus.append(stat);
}
if(msg.what == WifiDetectStop)
{
Thread.currentThread().interrupt();
}
super.handleMessage(msg);
}
};
// Setup WiFi
wifi = (WifiManager) getSystemService(Context.WIFI_SERVICE);
String state = Environment.getExternalStorageState();
if (Environment.MEDIA_MOUNTED.equals(state)) {
// Get WiFi status
Thread myThread = new Thread(new Runnable() {
public void run() {
for (int i = 0; i < 5; i++) {
WifiInfo info = wifi.getConnectionInfo();
Date d = new Date(System.currentTimeMillis());
stat = "\n\nWiFi Status: " + info.getRssi()
+ " " + d.getHours() + ":" + d.getMinutes()
+ ":" + d.getSeconds();
Message msg = new Message();
msg.what = WifiDetectStart;
handler.sendMessage(msg);
// textStatus.append(stat);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
//finish this operation
Message msg = new Message();
msg.what = WifiDetectStop;
handler.sendMessage(msg);
}
});
myThread.start();
}
}
The problem is you're doing something right by trying to do your updating in a separate Runnable... however, your Runnable is running in the UI thread and therefore causing the UI thread to sit in the loop (including the Thread.sleep()). You're not getting your updates because you're causing the UI to wait on you.
If your processing is reasonably heavy, you might wish to break it out into a separate thread and send messages to a handler. Otherwise, it might be easiest to do something like the following (untested, but something similar):
if (Environment.MEDIA_MOUNTED.equals(state)) {
textStatus.postDelayed(new Runnable() {
public void run() {
WifiInfo info = wifi.getConnectionInfo();
Date d = new Date(System.currentTimeMillis());
String stat = "\n\nWiFi Status: " + info.getRssi()
+ " " + d.getHours() + ":" + d.getMinutes()
+ ":" + d.getSeconds();
textStatus.append(stat);
// relaunch if we're not through with our number of iterations.
// mCount is a new field.
if(mCount++ < 5) {
textStatus.postDelayed(this, 1000);
}
}
}, 1000);
}
Related
I try to build an app, that vibrates with a certain pattern depending on the value of a variable that comes constantly with a stream from a video game.
I managed to display telemetry data on the TextView continiously. What I want is the phone to vibrate for a certain lenght in ms or pattern, depending on the value of gforce in Thread2. What I would like to achieve is, the following sequence. Read the stream, display ias, gforce and vertical on the TextView, check gforce value, if value>=2, vibrate(choose length or pattern by gforce value), pause 500ms, repeat.
I know about the lack of connection security in my code, but that is something for later.
I do have the problem of thread management here, that I cant solve. The stream comes from a Java server socket and has an output of around one line per ms.
This the code I try to make that work with.
public class MainActivity extends AppCompatActivity {
Thread Thread1 = null;
EditText etIP, etPort;
TextView tvMessages;
String SERVER_IP;
int SERVER_PORT;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
etIP = findViewById(R.id.etIP);
etPort = findViewById(R.id.etPort);
etIP.setText("192.168.178.61");
etPort.setText("31091");
tvMessages = findViewById(R.id.tvMessages);
Button btnConnect = findViewById(R.id.btnConnect);
btnConnect.setOnClickListener(new View.OnClickListener() {
#RequiresApi(api = Build.VERSION_CODES.O)
#Override
public void onClick(View v) {
tvMessages.setText("");
SERVER_IP = etIP.getText().toString().trim();
SERVER_PORT = Integer.parseInt(etPort.getText().toString().trim());
Thread1 = new Thread(new Thread1());
Thread1.start();
}
});
}
PrintStream output;
BufferedReader input;
Socket socket;
String message;
class Thread1 implements Runnable {
#Override
public void run() {
try {
socket = new Socket(SERVER_IP, SERVER_PORT);
socket.setTcpNoDelay(true);
output = new PrintStream(socket.getOutputStream(), true);
input = new BufferedReader(new InputStreamReader(socket.getInputStream()));
runOnUiThread(new Runnable() {
#Override
public void run() {
tvMessages.setText("Connected\n");
}
});
new Thread(new Thread2()).start();
} catch (IOException e) {
e.printStackTrace();
}
}
}
class Thread2 implements Runnable {
private double ias;
private double gforce;
private double vertical;
#Override
public void run() {
while (!(socket.isClosed())) {
try {
message = input.readLine();
if (message != null && message.contains("IAS")) {
ias = Double.parseDouble(message.substring(5, (message.indexOf(" ", 5))));
gforce = Double.parseDouble(message.substring(message.indexOf("Gy:") + 4, message.indexOf("Gz:") - 1));
vertical = Double.parseDouble(message.substring(message.indexOf("vertical:") + 10, message.indexOf("Gx:") - 1));
}
if (message != null && !(message.equals("exit"))) {
runOnUiThread(new Runnable() {
#Override
public void run() {
System.out.println(message);
tvMessages.setText("IAS: " + ias + "\n" +
"G: " + gforce + "\n" +
"Vertical: " + vertical + "\n");
}
});
//do trigger Vibration handler and make the phone vibrate in a pattern relative to gforce
new VibrationHandler((int)gforce).start();
//at this point sleep for n ms
} else {
Thread1 = new Thread(new Thread1());
Thread1.start();
return;
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
class VibrationHandler extends Thread{
int pattern;
public VibrationHandler(int pattern){
this.pattern=pattern;
}
public void run(){
Vibrator v = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE);
// Vibrate for 500 milliseconds
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
v.vibrate(VibrationEffect.createOneShot(pattern*50, VibrationEffect.DEFAULT_AMPLITUDE));
} else {
//deprecated in API 26
v.vibrate(pattern*50);
}
}
}
}
Thank you a lot for your help.
So in my android application, I have an intent service which pings devices and finds whether they are online/offline.
When I start my IntentService my UI freezes(Debug points to when ping commands are being executed) in the Service.
Service is started from the parent activity after I get the response of a network call
loadFragment(printersFrag, Constants.CONTAINER_ACT_DASHBOARD, PrintersListingFragment.class.getSimpleName(), false, false, false);
serviceIntent = new Intent(this, PrinterPingIntentService.class);
serviceIntent.putExtra("PrinterList", printersResponse);
this.startService(serviceIntent);
The code for my IntentService is as follows:
public class PrinterPingIntentService extends IntentService {
/**
* The IP Address to ping
*/
private String msIPAddressToPing = null;
/**
* Countdown latch instance to decrement after the thread is done
*/
private CountDownLatch mCountDownLatch;
/**
* Handler to handle ping threads
*/
private PingHandler mPingThreadHandler = null;
/**
* Volatile count variable to manage the ping thread count
*/
private volatile int mnPingThreadCount = 0;
/**
* The currently list of valid IP Addresses
*/
private ConcurrentHashMap<String, Device> mPrinterMap = new ConcurrentHashMap<String, Device>();
public PrinterPingIntentService() {
super(PrinterPingIntentService.class.getName());
}
#Override
protected void onHandleIntent(#Nullable Intent intent) {
Bundle bundle = intent.getExtras();
PrintersResponseBean printerResponse = bundle.getParcelable("PrinterList");
for (int i = 0; i < printerResponse.getDevices().size(); i++) {
mPrinterMap.put(printerResponse.getDevices().get(i).getDeviceIP(), printerResponse.getDevices().get(i));
}
validatePrinterIP();
}
#Override
public void onCreate() {
super.onCreate();
/*
* Fire up the Ping handler
*/
mPingThreadHandler = new PingHandler();
}
/**
* Validate the PrinterIPs by pinging them
*
* #author
*/
private void validatePrinterIP() {
try {
mnPingThreadCount = 0;
mCountDownLatch = new CountDownLatch(mPrinterMap.size());
for (String sIP : mPrinterMap.keySet()) {
PingRunnable runnable = new PingRunnable(sIP, mCountDownLatch);
Thread thread = new Thread(runnable);
++mnPingThreadCount;
Log.d("BAT", "validatePrinterIP - Thread count - " + mnPingThreadCount);
thread.start();
}
} catch (Exception e) {
Log.d("BAT", "Exception validatePrinterIP - " + e.getMessage());
}
}
/**
* Runnable to make a ping to the given Ip Address
*
* #author
*/
public class PingRunnable implements Runnable {
////////////////////////////////// CLASS MEMBERS ///////////////////////////////////////////
/**
* The IP Address to ping
*/
private String msIPAddressToPing = null;
/**
* Countdown latch instance to decrement after the thread is done
*/
private CountDownLatch mCountDownLatch;
////////////////////////////////// CLASS METHODS ///////////////////////////////////////////
public PingRunnable(String sIPAddress, CountDownLatch latch) {
msIPAddressToPing = sIPAddress;
mCountDownLatch = latch;
}
#Override
public void run() {
try {
/*
* If the destination is not reachable, remove the IP address
* from the printer map and set the bundle value accordingly
*/
if (!pingURL(msIPAddressToPing)) {
Log.d("BAT", "Could not ping " + msIPAddressToPing + ". Removing from Map");
mPrinterMap.remove(msIPAddressToPing);
} else {
Log.d("BAT", "Could ping " + msIPAddressToPing + ". Present in Map");
}
} catch (Exception e) {
Log.d("BAT", "Exception in Ping Runnable - " + e.getMessage());
} finally {
mPingThreadHandler.sendEmptyMessage(0);
mCountDownLatch.countDown();
}
}
}
/**
* Static Handler class to handle messsages.
* Reduce the count by one each time we receive a message to keep
* track that all threads have returned
*
* #author
*/
public class PingHandler extends Handler {
#Override
public void handleMessage(Message msg) {
Log.d("BAT", "Returning thread..");
if (msg.what == 0) {
mnPingThreadCount--;
Log.d("BAT", "Thread Return count - " + mnPingThreadCount);
}
/*
Await Latch
*/
try {
mCountDownLatch.await();
} catch (InterruptedException e) {
Log.d("BAT", "InterruptedException PingHandler - " + e.getMessage());
}
if (mnPingThreadCount == 0) {
//////TEMP
Log.d("BAT", "All threads accounted for. Final Printer List...");
ArrayList<Device> onlinePrinters = new ArrayList<>();
for (String sIP : mPrinterMap.keySet()) {
onlinePrinters.add(mPrinterMap.get(sIP));
Log.d("BAT", "Printers Active " + sIP);
}
//send data back to fragment via localBroadcastReceiver
Intent localBroadcast = new Intent();
localBroadcast.putParcelableArrayListExtra("onlinePrinters", onlinePrinters);
localBroadcast.setAction("printer");
sendBroadcast(localBroadcast);
}
}
}
/**
* Ping a device. First we try the usual isReachable method. If that does not work,
* we go with the Ping command execution
*
* #param sURL THe uRL / IP Address to ping
* #author
*/
public boolean pingURL(String sURL) {
try {
Log.d("BAT", "Pinging IP sURL");
//First try with isReachable
if (Inet4Address.getByName(sURL).isReachable(1000)) {
Log.d("BAT", "Host Reachable by InetAddress " + sURL);
return true;
}
//else try and ping. If neither works, we return false
else {
Log.d("BAT", "Host Not Reachable by InetAddress. Pinging IP with RunTime... " + sURL);
StringBuffer echo = new StringBuffer();
Runtime runtime = Runtime.getRuntime();
Process proc = runtime.exec("ping -c 1 " + sURL);
// "/system/bin/ping -c 8 " + sURL
int nReturnVal = proc.waitFor();
Log.d("BAT", "Done Pinging - " + sURL + ((nReturnVal == 0) ? " Successful" : " Unsuccessful"));
return (nReturnVal == 0);
}
} catch (IOException e) {
Log.d("BAT", "IOEXception in pingURL - " + e.getMessage().toString());
} catch (InterruptedException e) {
Log.d("BAT", "InterruptedException in pingURL - " + e.getMessage());
} catch (Exception e) {
Log.d("BAT", "EXception in pingURL - " + e.getMessage());
}
return false;
}
}
From my intent service, I send back the data of active devices to my Fragment using:
//send data back to fragment via localBroadcastReceiver
Intent localBroadcast = new Intent();
localBroadcast.putParcelableArrayListExtra("onlinePrinters", onlinePrinters);
localBroadcast.setAction("printer");
sendBroadcast(localBroadcast);
and extract this info in my Fragment using:
IntentFilter filter = new IntentFilter();
filter.addAction("printer");
updateUIReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
//UI update here
Bundle bundle = intent.getExtras();
if (bundle.get("onlinePrinters") != null) {
onlinePrinters = (ArrayList) bundle.get("onlinePrinters");
setPrinterStatus();
}
}
};
As I'm using an IntentService a UI freeze should be unlikely as the task is performed on a worker thread and not in the Main Thread.
Not able to figure out the root cause of the UI freeze
onCreate() method of your service is called on the main thread.
PingHandler instance that you're creating there is associated with the main thread.
So handleMessage for this handler is also executed on the main thread. You seem to have blocking operations there which may be the cause of your problem.
I would like to ask a question about my code in Wifi client communication. I am communicating with a Raspberry Pi as server.
The architecture of my code is:
Main Activity: I have the Handler class and I launch in the OnCreat the first Thread (Thread1) that takes care of establishing the wifi connection.
public class MainActivity extends AppCompatActivity {
public int serverPort = 40000;
public String serverIP = "10.177.86.212";
public WiFiConnector wifiConnection;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
editTextWE = (EditText) findViewById(R.id.editText_WE);
wifiConnection = new WiFiConnector(serverIP, serverPort);
Handler mHandler = new MyHandler();
WiFiConnector.Thread1 = new Thread(new WiFiConnector.Thread1(mHandler,true));
WiFiConnector.Thread1.start();
}
private class MyHandler extends Handler {
private byte[] bytes = null;
#Override
public void handleMessage(Message msg) {
bytes = msg.getData().getByteArray("KEY");
if(bytes!= null){
for (int i = 0; i < bytes.length; i++){
Log.d("Data received", "value " + (0xFF & bytes[i]) );
}
for (int i=0; i<bytes.length; i++) {
editTextWE.setText(editTextWE.getText()+ "Server says: " + bytes.length + " "+ (0xFF & bytes[i]) + "\n");
}
}
}
}
}
WifiConnector class: Thread1 and Thread2 are sharing the handler coming from the Main Activity. Thread1 send a command to Raspberry Pi to let it start sending data. Thread2 is dedicated to read data received from the server.
public class WiFiConnector {
static String serverIP;
static int serverPort;
public static Thread Thread1 = null;
//Constructor
public WiFiConnector(String IP, int port) {
serverIP = IP;
serverPort = port;
}
public static class Thread1 extends Thread implements Runnable {
private Handler handler1;
boolean firsttime = false;
OutputStream out ;
public Thread1(Handler handler_1, boolean firsttime) {
this.handler1 = handler_1;
this.firsttime = firsttime;
}
public void run() {
Socket socket = null;
try {
//Writing to a Socket
InetAddress serverAddress = InetAddress.getByName(serverIP);
socket = new Socket(serverAddress, serverPort);
out = new DataOutputStream(socket.getOutputStream());
if(firsttime){
//I send "B" to Raspberry to let him start sending data
out.write("B".getBytes());
this.fisrttime = false;
}
Thread2 comThread = new Thread2(socket, handler1);
new Thread(comThread).start();
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
public static class Thread2 implements Runnable {
public Socket clientSocket;
private Handler handler_2;
public DataInputStream in;
public byte[] bytes = new byte[13];
public Message msg;
public Thread2(Socket clientSocket, Handler handler2) {
this.clientSocket = clientSocket;
this.handler_2 = handler2;
}
public void run() {
while (!Thread.currentThread().isInterrupted()) {
try {
if (Looper.myLooper() == null) {
Looper.prepare();
}
this.in = new DataInputStream(clientSocket.getInputStream());
in.readFully(bytes);
if (in != null) {
for (int i = 0; i < bytes.length; i++){
Log.d("Data received", "valuewifi " + (0xFF & bytes[i]) );
}
msg = new Message();
Bundle b = new Bundle();
b.putByteArray("KEY", bytes);
msg.setData(b);
handler_2.sendMessage(msg);
} else {
Thread1 = new Thread(new Thread1(handler_2,false));
Thread1.start();
return;
}
} catch (IOException e) {
e.printStackTrace();
}
}
Looper.loop();
}
}
}
NOW THE PROBLEM IS:
I am receiving correctly my data (package of 13 bytes each) from Raspberry Pi, indeed:
Log.d("Data received", "valuewifi " + (0xFF & bytes[i]) );
prints correctly my values. Then I create the message to be sent to the handler in MainActivity. the Bundle contains (I have verified) the same values of the input stream received, but the message printed in the Handler of the MainActivity:
Log.d("Data received", "value " + (0xFF & bytes[i]) );
substitutes the first byte value of each message (I am trying to get 2 package each communications with the RPi) with 66 that actually is the ASCII code of "B" that I sent to start the data sending from Raspberry Pi.
PLEASE DO YOU HAVE ANY IDEA ON WHY THIS IS HAPPENING?
Many thanks for your help in advance!:)
Well, I have found that in Thread2 if I put
public byte[] bytes = new byte[13];
inside the run{..} before
in.readFully(bytes);
The exchange of message happens perfectly. Otherwise I only get in MainActivity the last package of byte received from the server.
Any suggestion on why does it happen?
Thanks!
How can I get the List of all the device connected in same WiFi network. I did find couple of applications are working perfectly available on Google Play like "Who is on My WiFi" and "WiFi Inspector". I want to implement the same functionality in my application.
I find out this code to show all the connected Ips to the same WI-FI:
private int LoopCurrentIP = 0;
String ad ;
#Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//ArrayList<InetAddress> ar = getConnectedDevices( );
}
public ArrayList<InetAddress> getConnectedDevices(String YourPhoneIPAddress) {
ArrayList<InetAddress> ret = new ArrayList<InetAddress>();
LoopCurrentIP = 0;
String IPAddress = "";
String[] myIPArray = YourPhoneIPAddress.split("\\.");
InetAddress currentPingAddr;
for (int i = 0; i <= 255; i++) {
try {
// build the next IP address
currentPingAddr = InetAddress.getByName(myIPArray[0] + "." +
myIPArray[1] + "." +
myIPArray[2] + "." +
Integer.toString(LoopCurrentIP));
ad = currentPingAddr.toString(); /////////////////
Log.d("MyApp",ad); //////////////
// 50ms Timeout for the "ping"
if (currentPingAddr.isReachable(50)) {
ret.add(currentPingAddr);
ad = currentPingAddr.toString(); /////////////////
Log.d("MyApp",ad); //////////////
}
} catch (UnknownHostException ex) {
} catch (IOException ex) {
}
LoopCurrentIP++;
}
return ret;
}
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.