Send string from thread bluetooth service to textView in main activity - java

I want to send value from string (distance to obstacle) to my TextView in main activity.
I tried to use Handler, but still not working (crash) or receive nothing.
A part code which receive data from HC-05 (screen where you see in debug value assignet to variable)
enter image description here
#Override
public void run() {
byte[] buffer = new byte[1024];
int bytes;
while(true){
try {
bytes = inputStream.read(buffer);
final String comingMsg = new String(buffer,0,bytes);
Log.d(TAG,"InputStream: " + comingMsg);
/*mHandler2.post(new Runnable() {
#Override
public void run() {
Message message = new Message();
message.obj = comingMsg;
mHandler2.sendMessage(message);
}
});*/
}catch (IOException e){
Log.e(TAG,"Write: Error reading input." + e.getMessage());
active=false;
break;
}
}
}
Here It's parts of code from MainActivity where I tried put something to get values from service.
[I add, that for this moment i want to see something values from bluetooth in textView. Later I want to create parse string and send custom text to custom TextView - example: FL: (Front Left)- to one textView, FR: (Front Right) - to second textView]
There is method implementThreads(), because I wanted to do 6 Threads to 6 TextView which every time is refreshing value from string in Services (there I tried get value from Bluetooth Service)
Log.d(TAG,"Check intent - result");
if(getIntent().getIntExtra("result",0)==RESULT_OK){
mDevice = getIntent().getExtras().getParcelable("bonded device");
myBluetoothService = new MyBluetoothService(getApplicationContext());
startConnection(mDevice,MY_UUID);
Log.d(TAG,"Check is active service");
checkIfActive();
}
Log.d(TAG,"Check intent - connect_to_paired");
if(getIntent().getIntExtra("connect_to_paired",0)==RESULT_OK){
mDevice = getIntent().getExtras().getParcelable("bonded_paired_device");
myBluetoothService = new MyBluetoothService(getApplicationContext());
startConnection(mDevice,MY_UUID);
Log.d(TAG,"Check is active service");
checkIfActive();
}
}
#Override
public void onStart(){
super.onStart();
myBluetoothService = new MyBluetoothService(getApplicationContext());
}
public void checkIfActive(){
Log.d(TAG,"CheckIfActive: Started");
if(myBluetoothService.active){
Log.d(TAG,"CheckIfActive: Running method implementThreads()");
implementThreads();
}
}
public void implementThreads(){
Log.d(TAG,"ImplementThreads: Started");
Thread thread = new Thread(){
#Override
public void run() {
try{
sleep(100);
}catch (InterruptedException e){
e.printStackTrace();
}
}
};
thread.start();
}
public void startConnection(BluetoothDevice device,UUID uuid){
Log.d(TAG,"StartConnection: Initializing connection");
myBluetoothService.startClient(device,uuid);
}
Thanks all for help, because It's very important for me !

Use this to interect with UI Thread for operations like updating textviews etc.
new Handler(Looper.getMainLooper()).post(new Runnable() {
#Override
public void run() {
//YOUR CODE HERE
Message message = new Message();
message.obj = comingMsg;
mHandler2.sendMessage(message);
}
});

Related

Reading Bluetooth data and putting it to MainActivity

I've been looking for this for a while and everything I've tried has not worked yet. I implemented a Bluetooth connection service class that let's me connect and send messages via Bluetooth to a HC-05 module. I'm able to see each message within the console (with a Log), however, no matter what I tried, I can't seem to put the bytes received into my main activity where I can treat it. Here is the code I have in the BluetoothConnectionService class where my Log is located:
BluetoothConnectionService:
private Handler mHandler; // handler that gets info from Bluetooth service
// Defines several constants used when transmitting messages between the
// service and the UI.
private interface MessageConstants {
public static final int MESSAGE_READ = 0;
public static final int MESSAGE_WRITE = 1;
public static final int MESSAGE_TOAST = 2;
// ... (Add other message types here as needed.)
}
public void run(){
byte[] buffer = new byte[1024]; // buffer store for the stream
int bytes; // bytes returned from read()
// Keep listening to the InputStream until an exception occurs
while (true) {
// Read from the InputStream
try {
bytes = mmInStream.read(buffer);
String incomingMessage = new String(buffer, 0, bytes);
Log.d(TAG, "InputStream: " + incomingMessage);
// Send the obtained bytes to the MainActivity
Handler mainActivityHandler = new Handler();
mainActivityHandler.obtainMessage(MessageConstants.MESSAGE_READ, bytes, -1, buffer);
// Send the obtained bytes to the UI activity.
/*Message readMsg = mHandler.obtainMessage(
MessageConstants.MESSAGE_READ, bytes, -1,
buffer);
readMsg.sendToTarget();*/
} catch (IOException e) {
Log.e(TAG, "write: Error reading Input Stream. " + e.getMessage() );
break;
}
}
}
MainActivity: (in the onCreate)
btnReadGlucose.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
//On va envoyer quelle personne il faut lire le data
String patientName = mSpinner.getSelectedItem().toString();
int patientPosition = mSpinner.getSelectedItemPosition();
Log.d(TAG, "Le patient " + patientName + " a la position " + patientPosition + " est selectionne");
//Trouver quelle lettre envoyer
DataEnvoyer = mappingPatients(patientPosition);
RequestData = true;
//Envoi du data
envoyerCommandeBluetooth(DataEnvoyer);
//How do I call my handler ?
}
});
I'm still a newbie with Bluetooth communication handlers. I think I'm close to the answer but I really don't know how to get the message in the byte and save it to a value in my main activity.
Can anyone help ?
Thanks,
luisarcher.
METHOD 1 : If this service running on the same thread as the activity then bind the service with activity.
//IN YOUR ACTIVITY
startService(new Intent(getApplicationContext(), BluetoothService.class));
bindService(new Intent(getApplicationContext(), BluetoothService.class), mServiceConnection, Context.BIND_AUTO_CREATE);
private ServiceConnection mServiceConnection = new ServiceConnection() {
#Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
BluetoothService.BackgroundBinder backgroundBinder = (BluetoothService.BackgroundBinder) iBinder;
mBackgroundService = backgroundBinder.getBackgroundService();
startPinging();
}
#Override
public void onServiceDisconnected(ComponentName componentName) {
mBackgroundService = null;
}
};
//IN SERVICE
public class BluetoothBinder extends Binder {
public BluetoothService getBluetoothService() {
return BluetoothService.this;
}
}
#Override
public IBinder onBind(Intent intent) {
Log.d(TAG, "Inside onBind");
return new BluetoothBinder();
}
Now that the service is binded you can declare a getter in service for incomingMessage so when you press the button in activity it returns you the message.
METHOD 2(VIA HANDLER):if you need an interface to communicate across processes you can create a Messenger. It handles communication on single thread.
I haven't done this but a good post about this can be found here.
METHOD 3(VIA LocalBroadCast): In your bluetooth service send a localBroadcast whenever you receive a message
//SERVICE
private void sendMessage(String incomingMessage) {
Intent intent = new Intent("UNIQUE_ACTION");
intent.putExtra("incomingMessage", incomingMessage);
LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
}
public void run(){
byte[] buffer = new byte[1024]; // buffer store for the stream
int bytes; // bytes returned from read()
// Keep listening to the InputStream until an exception occurs
while (true) {
// Read from the InputStream
try {
bytes = mmInStream.read(buffer);
String incomingMessage = new String(buffer, 0, bytes);
Log.d(TAG, "InputStream: " + incomingMessage);
sendMessage(incomingMessage);
//ACTIVITY
#Override
public void onResume() {
super.onResume();
// This registers mMessageReceiver to receive messages.
LocalBroadcastManager.getInstance(this).registerReceiver(mMessageReceiver,new IntentFilter("UNIQUE_ACTION"));
}
// Handling the received Intents for the "UNIQUE_ACTION" event
private BroadcastReceiver mMessageReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
// Extract data included in the Intent
String incomingMessage = intent.getStringExtra()("incomingMessage");
Log.d(TAG, incomingMessage);
}
};
#Override
protected void onPause() {
// Unregister since the activity is not visible
LocalBroadcastManager.getInstance(this).unregisterReceiver(mMessageReceiver);
super.onPause();
}
Also, I would suggest looking at this link for communication between service and activity.
P.S:Have a look at this library for bluetooth communication.It does provide methods to get data from Bluetooth and I have personally tested that it works with HC-05 and also has examples.

AsyncTask doesn't finish after running doInBackground Android

I'm running an AsyncTask on my TakePic class. In doInBackground function I'm using Camera.takePicture function. Now everything is fine at this point; I'm taking the picture and saving the file to /sdcard/%d.jpg that location.
public class TakePic extends AsyncTask<CameraPreview, String, Integer> {
#Override
protected Integer doInBackground(final CameraPreview... params) {
params[0].camera.takePicture(null,null,new Camera.PictureCallback() {
#Override
public void onPictureTaken(byte[] data, Camera camera) {
FileOutputStream outStream = null;
try {
outStream = new FileOutputStream(String.format("/sdcard/%d.jpg", System.currentTimeMillis()));
outStream.write(data);
outStream.close();
Log.e("picture_saved", "Picture has been saved succesfully: " + data.length);
camera.release();
} catch (FileNotFoundException e) {
e.printStackTrace();
Log.e("file_not_found: ","couldn't save the file "+e.getMessage());
} catch (IOException e) {
e.printStackTrace();
Log.e("IOexception: ","couldn't save the file "+e.getMessage());
}
}
});
Log.e("doinback_compt:" ,"done");
return 0;
}
#Override
protected void onPostExecute(Integer integer) {
}
}
But after I execute this AsyncTask on my main class it doesn't finish. I need to execute another function and I have to wait until this AsyncTask finishes. So after I execute the AsyncTask I'm using a while loop to check the status of the task but the status never changes.
TakePic backCam=new TakePic();
backCam.execute(cameraPreview_front);
while (backCam.getStatus()!= AsyncTask.Status.FINISHED){
*waiting for async task to finish*
}
It stuck at the while loop and my logcat show that doInBackground running normal, and the file is saving to that location.
10-10 18:06:14.497 15975-15975/com.urun.camera_test E/clicked_capture:: ok
10-10 18:06:14.633 15975-16452/com.urun.camera_test E/doinback_compt:: done
So what am I need to do? Thanks in advance.
This is being handled in an odd way. First CameraPreview.camera.takePicture() will run in the background itself, that is why you pass it the Camera.PictureCallback in the constructor. You are simply stacking threads there. Try this in the main thread
[yourCameraPreview].camera.takePicture(null,null,new Camera.PictureCallback() {
#Override
public void onPictureTaken(byte[] data, Camera camera) {
camera.release();
// Read below
}
}
Now we can just wait for the picture callback. Once we get data back, we can call an AsyncTask to store it in the file, and apply our own callback to wait for it's response. We can utilize a static inner class to make this all work.
private static class ImageSaver extends AsyncTask<Byte, Void, Exception>{
public interface ImageSavedListener{
void onImageSaved(Exception e);
}
private ImageSavedListener mCallback;
public ImageSaver(ImageSavedListener callback){
mCallback = callback;
}
#Override
protected void doInBackground(Byte... data){
if(data == null || data.length == 0)
return new Exception("Data returned from camera is invalid");
try {
FileOutputStream outStream = new FileOutputStream(String.format("/sdcard/%d.jpg", System.currentTimeMillis()));
outStream.write(data);
outStream.close();
Log.d("picture_saved", "Picture has been saved succesfully: " + data.length);
} catch (FileNotFoundException e) {
Log.e("file_not_found: ","couldn't save the file "+e.getMessage());
return e;
} catch (IOException e) {
Log.e("IOexception: ","couldn't save the file "+e.getMessage());
return e;
}
return null;
}
#Override
protected void onPostExecute(Exception e){
if(mCallback != null)
mCallback.onImageSaved(e);
}
}
Then call it like this (in the section stated Read below above)
new ImageSaver(new ImageSavedListener(){
#Override
public void onImageSaved(Exception e){
if(e == null){
// do what you want
}
else
e.printStackTrace();
}
}).execute(data);
This will take the picture in the background, wait for the response, save the response to a file in the background, wait for the response, and then do what you want based on the exception returned after saving.
If you need to do some code after AsyncTask execution, I can suggest one solution.
Wrap your *waiting for async task to finish* code in Runnable and send it as a param to Async task ( but this is not the best solution, just fast one )
new AsyncTask<Object, Void, Runnable>() {
#Override
protected Runnable doInBackground(Object... runnables) {
CameraPreview cp = (CameraPreview) runnables[0];
Runnable callback = (Runnable) runnables[1];
/**your main logic*/
return callback;
}
#Override
protected void onPostExecute(Runnable aVoid) {
super.onPostExecute(aVoid);
if (aVoid != null)
aVoid.run();
}
}.execute( cameraPreview , new Runnable() {
#Override
public void run() {
/**code to run();**/
}
});
Possible problem with your current code is :
You are not executing super.onPostExecute(integer);
Try change code to
#Override
protected void onPostExecute(Integer integer) {
super.onPostExecute(integer);
}
As pointed out before, does not make sense blocking your main thread waiting do certain event. However, if you still want to get a something from your AsyncTask, I would advise you to use FutureTask
As I can see in your code, the AsyncTask is finishing correctly.
The problem is that you are taking the picture inside the AsyncTask. So while the Camera.PictureCallback is waiting for the picture the task ends immediately after call the "takePicture" method.
What I should do is something like this (this is only an approach):
public class TakePic {
public interface MyTakePicListener{
void onPictureTaken();
void onPictureError();
}
private MyTakePicListener myListener;
public void takePicture(CameraPreview cameraPreview) {
cameraPreview.camera.takePicture(null, null, new Camera.PictureCallback() {
#Override
public void onPictureTaken(final byte[] data, final Camera camera) {
new Thread(new Runnable() {
#Override
public void run() {
FileOutputStream outStream = null;
try {
outStream = new FileOutputStream(String.format("/sdcard/%d.jpg", System.currentTimeMillis()));
outStream.write(data);
outStream.close();
Log.e("picture_saved", "Picture has been saved succesfully: " + data.length);
camera.release();
HERE you should call a listener to continue with your success code
myListener.onPictureTaken();
} catch (FileNotFoundException e) {
e.printStackTrace();
Log.e("file_not_found: ", "couldn't save the file " + e.getMessage());
HERE you should call a listener to continue with your error code
myListener.onPictureError();
} catch (IOException e) {
e.printStackTrace();
Log.e("IOexception: ", "couldn't save the file " + e.getMessage());
HERE you should call a listener to continue with your error code
myListener.onPictureError();
}
Log.e("doinback_compt:", "done");
}
}).start();
}
});
}
}
Please, let me know if this could help you.

Tunring my android to beacon and detecting

Is this right way of doing? AM using this samples https://altbeacon.github.io/android-beacon-library/samples.html
public class App extends Application
implements BootstrapNotifier, BeaconConsumer, RangeNotifier {
private final String TAG = "Application ";
protected static final Region beaconRegion = new Region("2f234454-cf6d-4a0f-adf2-f4911ba9ffa6", null, null, null);
protected BeaconManager beaconManager = null;
private RegionBootstrap regionBootstrap;
private BackgroundPowerSaver backgroundPowerSaver;
protected static String sLog = "";
#Override
public void onCreate() {
super.onCreate();
logIt(TAG, beaconRegion.getId1()+"onCreate - In"+beaconRegion.getUniqueId());
beaconManager = org.altbeacon.beacon.BeaconManager.getInstanceForApplication(this);
beaconManager.getBeaconParsers().clear();
beaconManager.getBeaconParsers().add(new BeaconParser().
setBeaconLayout("m:2-3=0215,i:4-19,i:20-21,i:22-23,p:24-24"));//iBeacon (tutti)
//--- wake up the app when a beacon is seen
regionBootstrap = new RegionBootstrap(this, beaconRegion);
//--- activate power saver
backgroundPowerSaver = new BackgroundPowerSaver(this);
beaconManager.bind(this);
logIt(TAG, "onCreate - Out");
}
private void logIt (String TAG, String msg) {
sLog += TAG + msg + "\n";
Log.w(TAG, msg);
}
//-------------------------//
//--- BootstrapNotifier ---//
//-------------------------//
#Override
public void didDetermineStateForRegion(int state, Region region) {
String msg = "didDetermineStateForRegion ";
switch(state) {
case MonitorNotifier.INSIDE:
msg +="(INSIDE)";
break;
case MonitorNotifier.OUTSIDE:
msg +="(OUTSIDE)";
break;
default:
msg +="(state=" +state +")";
break;
}
logIt(TAG, msg);
}
#Override
public void didEnterRegion(Region arg0) {
logIt(TAG, "didEnterRegion - In");
try {
beaconManager.startRangingBeaconsInRegion(beaconRegion);
logIt(TAG,"dER - startRangingBeaconsInRegion OK");
} catch (RemoteException e) {
logIt(TAG, "dER - startRangingBeaconsInRegion Err " +e);
}
logIt(TAG, "didEnterRegion - Out");
}
#Override
public void didExitRegion(Region region) {
logIt(TAG, "didExitRegion - In");
try {
beaconManager.stopRangingBeaconsInRegion(beaconRegion);
logIt(TAG,"dXR - stopRangingBeaconsInRegion OK");
} catch (RemoteException e) {
logIt(TAG, "dXR - stopRangingBeaconsInRegion Err " +e);
}
logIt(TAG, "didExitRegion - Out");
}
//----------------------//
//--- BeaconConsumer ---//
//----------------------//
#Override
public void onBeaconServiceConnect() {
logIt(TAG, "onBeaconServiceConnect - In");
beaconManager.setRangeNotifier(this);
logIt(TAG, "onBeaconServiceConnect - Out");
}
//---------------------//
//--- RangeNotifier ---//
//---------------------//
#Override
public void didRangeBeaconsInRegion(Collection<Beacon> beacons, Region region) {
logIt(TAG, "didRangeBeaconsInRegion - " +beacons.size() +" beacons");
Toast.makeText(getApplicationContext(), beaconRegion.getId1()+" beacon detected "+beacons.size(),
Toast.LENGTH_SHORT).show();
for(Beacon beac: beacons)
{
System.out.println(beac.getId1()+"id 1"+TAG);
if(beac.getId1().equals("2f234454-cf6d-4a0f-adf2-f4911ba9ffa6")/send notification
}
}
}
So Basically that class, which extends application am listening to beacons around. Below, is how am turning my phone into a beacon.I am doing this inside an activity on click of button. So there is two phones with app downloaded on both, once he clicks on one app the button I want the other phone to detect it since i have implemented in extends application class.
the turn ur android to beacon code.
Beacon beacon = new Beacon.Builder()
.setId1("2f234454-cf6d-4a0f-adf2-f4911ba9ffa6") // UUID for beacon
.setId2("1") // Major for beacon
.setId3("5") // Minor for beacon
.setManufacturer(0x004C) // Radius Networks.0x0118 Change this for other beacon layouts//0x004C for iPhone
.setTxPower(-56) // Power in dB
.setDataFields(Arrays.asList(new Long[]{0l})) // Remove this for beacon layouts without d: fields
.build();
BeaconParser beaconParser = new BeaconParser()
.setBeaconLayout("m:2-3=0215,i:4-19,i:20-21,i:22-23,p:24-24");
beaconTransmitter = new BeaconTransmitter(MenuActivity.this, beaconParser);
beaconTransmitter.startAdvertising(beacon, new AdvertiseCallback() {
#Override
public void onStartFailure(int errorCode) {
Log.e("tag", "Advertisement start failed with code: " + errorCode);
}
#Override
public void onStartSuccess(AdvertiseSettings settingsInEffect) {
Log.i("tag", "Advertisement start succeeded.");
Toast.makeText(MenuActivity.this, "advertisement start succeeded",
Toast.LENGTH_SHORT).show();
System.out.println("startedddddddddddd");
}
});
// beaconTransmitter.stopAdvertising();
}
catch(Exception o)
{
System.out.println("affda "+o.getMessage());
}
I am also havig an issue, that didenterregion and didRangeBeaconsInRegion are fired many times, so am sending many notification to the user multiple times. its not user friendly.
The didRangeBeaconsInRegion callback is supposed to get called many times -- that's how ranging works. It is called approximately once per second when the beacon is detected to tell you it is there and give you a distance estimate.
If you want to fire a notification only once for the first time you get a call to this method, then you can set a flag for this specific beacon.
Here is an example of some code you might use to do that:
// Add this to the top of your class
private HashMap<String,Boolean> mAlreadySentNotification = new HashMap<String,Boolean>();
...
// Add this to the inside of your didRangeBeaconsInRegion method
if (mAlreadySentNotification.get(beacon.toString())) {
mAlreadySentNotification.put(beacon.toString(), true);
// Send notification here.
}

Listing of the Network Devices in Android

Similar or the same Question has been answered here
I am creating an Android App, which sends a broadcast message to the network and prepares a list of devices responding back.
Now What I did:
I created an Activity Class DeviceManagerWindow.java which calls a thread Sender.java.
Sender.java is responsible for sending the broadcast message.
Then the DeviceManagerWindow.java calls another thread which is responsible for listening to the devices responding back. The devices responding back will be listed in the Activity as soon as the device responds back. For that I have a TableLayout named deviceList.
What code I have written:
DeviceManagerWindow.java This method is called when a button for search is pressed
public void searchDevice(View v) throws IOException, InterruptedException
{
//Log.v("TableLayout:",view.toString());
sendMulticastFlyport = new Thread(new FlyportSender(MAC));
sendMulticastFlyport.start();
new Thread()
{
public void run()
{
MulticastSocket socketComputer=null;
try
{
socketComputer = new MulticastSocket(WifiConstants.COMPUTER_RECV_PORT);
socketComputer.joinGroup(InetAddress.getByName(WifiConstants.COMPUTER_NETWORK_ADDR));
socketComputer.setSoTimeout(1*60*1000);
byte[] inBufComputer = new byte[1024];
DatagramPacket inPacketComputer = new DatagramPacket(inBufComputer, inBufComputer.length);
while(true)
{
System.out.println("Listening...");
socketComputer.receive(inPacketComputer);
System.out.println("Received");
String msg = new String(inBufComputer, 0, inPacketComputer.getLength());
DeviceInformation device = new DeviceInformation(1, msg, inPacketComputer.getAddress().toString());
addDevice(device, false, 1);
Log.v("Received:","Received Computer From :" + inPacketComputer.getAddress() + " Msg : " + msg);
//System.out.write(inPacket.getData(),0,inPacket.getLength());
System.out.println();
Thread.sleep(2000);
}
}
catch(Exception e)
{
Log.v("Exception:","During Receiving Computer: "+e.toString());
try
{
addDevice(null, true, 1);
}
catch (IOException e1)
{
Log.v("Exception:", "Computer End Error: " +e1);
}
}
finally
{
socketComputer.close();
}
}
}.start();
The following code creates a list:
public void addDevice(DeviceInformation device, boolean bool, int type) throws IOException
{
TableLayout tb = (TableLayout) findViewById(R.id.DeviceList);
Log.v("addDevice","Called");
if(bool)
{
LayoutParams layout = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
TableRow tr = new TableRow(getApplicationContext());
TextView tv = new TextView(getApplicationContext());
System.out.println(tb);
tv.setLayoutParams(layout);
tr.setLayoutParams(layout);
String message;
Log.v("addDevice","Device Timeout");
switch(type)
{
case 1:
computerEnd=true;
break;
case 2:
raspberryEnd=true;
break;
case 3:
flyportEnd=true;
break;
}
if(computerEnd && raspberryEnd && flyportEnd)
{
if(rowCounter>0)
{
message = "No More Devices";
}
else
{
message = "No Devices Found";
}
tv.setText(message);
tv.setTextColor(Color.WHITE);
if(rowCounter%2==0)
{
tr.setBackgroundColor(Color.DKGRAY);
}
else
{
tr.setBackgroundColor(Color.GRAY);
}
tv.setVisibility(1);
tr.addView(tv);
tb.addView(tr);
}
}
else
{
LayoutParams layout = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
TableRow tr = new TableRow(getApplicationContext());
TextView tv = new TextView(getApplicationContext());
tv.setLayoutParams(layout);
tr.setLayoutParams(layout);
Log.v("addDevice","Received");
String textToDisplay = device.getDeviceTypeString()+"\n"+device.getIPAddress(); //Write the text to display
tv.setText(textToDisplay);
tv.setTextColor(Color.WHITE);
Drawable img;
if(device.getDeviceType()==1)
{
img = getApplicationContext().getResources().getDrawable(R.drawable.pc);
}
else if(device.getDeviceType()==2)
{
img = getApplicationContext().getResources().getDrawable(R.drawable.raspberry);
}
else
{
img = getApplicationContext().getResources().getDrawable(R.drawable.flyport);
}
img.setBounds(0,0,70,45);
tv.setCompoundDrawables(null, null, img, null);
tv.setOnClickListener(new OnClickListener()
{
#Override
public void onClick(View v)
{
}
});
if(rowCounter%2==0)
{
tr.setBackgroundColor(Color.DKGRAY);
}
else
{
tr.setBackgroundColor(Color.GRAY);
}
rowCounter++;
Log.v("Result","Device Added");
}
}
Now it is showing me an error in the logCat as:
05-11 22:01:10.165: E/AndroidRuntime(13873): android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
What I have figured out from this is only the UIThread is allowed to access the Views that is created.
Previously I had tried:
new Thread()
{
public void run()
{
runOnUiThread(){
MulticastSocket socketComputer=null;
try
{
....
....
....
}
}
And that time I received an error:
Main thread cannot access Network
Before that I had tried to use synchronized methods which was called from the Receiving.java Thread File. but It also gave an error of not creating the list.
I have tried all possible ways.
Now what whould I do.?
You figured it out right. Now you can learn to either use a Handler to pass information to the UI thread (see http://www.techotopia.com/index.php/A_Basic_Overview_of_Android_Threads_and_Thread_handlers) or AsyncTask (see http://developer.android.com/reference/android/os/AsyncTask.html).
I personally prefer AsyncTask. You can paste the code which performs the search into the doInBackground() method (not need to use a separate thread, doInBackground() already does that for you) and paste the UI-related code (the list creation code) into the onPostExecute() method. Search for further examples of AsyncTask if it is not sufficiently clear how it works from the link.
EDIT: If you intend your device search code to run indefinitely, then you have to resort to Handler, as AsyncTask expects the doInBackground() method to finish before running onPostExecute(). See which option better suits your needs.

Android Thread and class behavior question

The project i am working on needs this type of behavior. The user will be presented with a UI that will give them the option to connect and disconnect to a server. I would also like this UI to show the status of the connection, 'connected or disconnected'. Whenever the user clicks connect, the application will start a thread that handles the connection to the server. The user will still be looking at the main UI. When they start that connection and while the connection remains, i would like the status of the connection to be 'connected'. If the connection is ever broken at any point i would like it to display disconnected. Listed below is what i have so far.
My question is... Am i doing the threading right? So that the phone will not be crushed by the server connection while it is connected?
Also, how do i get the main UI to reflect the connection status of the server and display when the connection is broken?
Thanks in advance! If you have any further questions, please let me know.
The server connection thread.
public class ConnectDevice implements Runnable {
private boolean connected;
private ObjectInputStream ois;
public void run() {
try {
InetAddress host = InetAddress.getByName("192.168.234.1");
Socket socket = new Socket(host.getHostName(), 7777);
connected = true;
while (connected) {
try {
ois = new ObjectInputStream(socket.getInputStream());
String message = (String) ois.readObject();
System.out.println("Message: " + message);
}
catch (Exception e) {
e.printStackTrace();
}
}
ois.close();
} catch (UnknownHostException e) {
e.printStackTrace();
connected = false;
} catch (IOException e) {
e.printStackTrace();
connected = false;
} /*catch (ClassNotFoundException e) {
e.printStackTrace();
connected = false;
}*/
}
}
The main UI and main class.
public class SmartApp extends Activity
{
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.intro);
final Button firstTimeButton = (Button) findViewById(R.id.firstTimeButton);
firstTimeButton.setOnClickListener(
new View.OnClickListener()
{
#Override
public void onClick(View v)
{
// TODO Auto-generated method stub
Intent userCreationIntent = new Intent(v.getContext(), UserCreation.class);
startActivityForResult(userCreationIntent, 0);
}
});
final Button connectDeviceButton = (Button) findViewById(R.id.connectDeviceButton);
connectDeviceButton.setOnClickListener(
new View.OnClickListener()
{
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
//Intent connectDeviceIntent = new Intent(v.getContext(), ConnectDevice.class);
//startActivityForResult(connectDeviceIntent, 0);
Thread cThread = new Thread(new ConnectDevice());
cThread.start();
}
});
}
}
Android has a UI thread, which is the only thread that is allowed to update UI elements.
You need to have a background thread doing the work, and posting back to the UI thread when its done.
AsyncTask is an Android class designed to do just that.
Once your worker thread ends its work, and will update the UI element taken by findViewById, it will automatically change on the screen without you having to do anything else.
Check out the AsyncTask, it's tailor made for this sort of thing.

Categories

Resources