I have MainActivity which does some Work before it Executes an AsyncTask called "Datensammlung". This task starts some other Threads via different classes. All of Them implement Runnable and work correct. Two are for communication with a Server(TCP Connections) and some are listening for Events/ generating random numbers(Intervall 10 seconds).
Now i want to display some Values every thread works on(i always use synchronized).
When i only start the Listener-Threads, "onProgressUpdate" is called maybe 5 times until it ends updating the UI. When i start the two other threads for Communication nothing is displayed ever.
Why is my UI still blocked although i used asynctasks?
Anyone got an idea? Thank you!
Fabian
AsyncTask:Datensammlung
protected Void doInBackground(String[]... params) {
// TODO Auto-generated method stub
while (true) {
int counter = 0;
ArrayList<String> texte = new ArrayList<String>();
String test = "";
for (Input i : this.Dataliste) {
String text = " "+i.variablenName + ": "+String.valueOf(i.getAbstrakterWert())+"\n";
texte.add(text);
test += text;
// Log.e("TEXT ", text);
// counter ++;
}
publishProgress(test);
Log.e("TEXT", test);
test = "";
counter ++;
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
// TODO: handle exception
}
}
}
#Override
protected void onProgressUpdate(String... listen) {
TextView t = this.viewList.get(0);
Log.e("hier isser", "1");
for (String r : listen) {
t.setText(r);
Log.e("hier isser", r);
}
}
One of my Communication Class:
package kommunikation;
public class SensorAdapter implements Runnable{
String iP;
int port;
Socket socket;
ObjectOutputStream out;
ObjectInputStream in;
ArrayList<Nachricht> nachrichtenliste = new ArrayList<Nachricht>();
Handler handler = new Handler();
// Konstruktor
public SensorAdapter(String iP, int port) {
super();
this.iP = iP;
this.port = port;
}
public boolean initialisiere_sensor(ArrayList<Textobjekt> pObjekte){
try {
socket = new java.net.Socket(iP,port);
// serialisiere alle Inputs und sende die Daten an das FW
out = new ObjectOutputStream(new ObjectOutputStream(socket.getOutputStream()));
out.writeObject(pObjekte);
out.flush();
} catch (UnknownHostException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return true;
}
public void run() {
try {
while (true) {
if (!nachrichtenliste.isEmpty()) {
PrintWriter printWriter =new PrintWriter(new OutputStreamWriter(socket.getOutputStream()));
Nachricht speicher = nachrichtenliste.get(0);
String senden = schreibe_nachricht(speicher);
printWriter.print(senden);
printWriter.flush();
synchronized (nachrichtenliste) {
nachrichtenliste.remove(speicher);
}
}
try {
Thread.sleep(500);
handler.post(this);
} catch (InterruptedException e) {
// TODO: handle exception
}
}
} catch (Exception e) {
// TODO: handle exception
}
}
The Place where the Communication-Thread gets started:
public class Kommunikator implements Callback{
ArrayList<Input> objektliste;
ArrayList<Textobjekt> textliste;
boolean update_erforderlich = false;
public boolean bereit = false;
private Verbindungsdaten verbindungsdaten;
private SensorAdapter sadapter;
private ClientAdapter cadapter;
Thread sensorfred;
Thread clientfred;
// Konstruktor
public Kommunikator(ArrayList<Input> plist, ArrayList<Textobjekt> ptextliste){
boolean check;
boolean cCheck;
this.objektliste = plist;
this.textliste = ptextliste;
// startet die kommunikation
this.sadapter = new SensorAdapter("192.168.2.106", 1111);
this.cadapter = new ClientAdapter("192.168.2.106", 2222,this);
check = sadapter.initialisiere_sensor(ptextliste);
if (check ) {
sensorfred = new Thread(sadapter);
sensorfred.start();
}
// client darf wirklcih erst nach dem sensorlayer starten
cCheck = cadapter.initialisiere_client(ptextliste);
if (cCheck) {
clientfred = new Thread(cadapter);
clientfred.start();
}
this.bereit = true;
}
// kann vom Sensor aufgerufen werden um die updates an das framework zu senden
public void melde(Nachricht na){
Nachricht speicher =null;
for (Nachricht n : this.sadapter.nachrichtenliste) {
if (n.getName().equals(na.getName())) {
speicher = n;
}
}
// lösche die alte nachricht
if (speicher != null) {
int index = sadapter.nachrichtenliste.indexOf(speicher);
sadapter.nachrichtenliste.remove(index);
}
synchronized (sadapter.nachrichtenliste) {
this.sadapter.nachrichtenliste.add(na);
}
}
public void melde_Abstract(String name, int Version, float wert){
// hier synchronized rein???
for (Input i : objektliste) {
if (i.variablenName.equals(name)) {
// mache Versionscheck und schreibe dann dort den wert
synchronized (i) {
i.setAbstrakterWert(wert);
}
}
}
}
When you use Handler.post() it will execute runnable on UI thread (if handler was created in UI thread). So when you do handler.post(this) you actually do all your communication on UI thread.
Related
Hello I use android thing on raspberry pi 3, I have a problem my app use UsbToSerial and then my app can Tx but cannot Rx data when app run longtime but in first period of work my app can Rx data and app can Tx alway times
How can I fix the problem?
And this is my code
MainActivity.java
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
UartService uart_api = new UartService();
uart_api.UartInit("USB1-1.2:1.0", 9600);
}
UartService.java
public class UartService extends Activity {
private static final String TAG = "LoopbackActivity";
// UART Configuration Parameters
private static final int DATA_BITS = 8;
private static final int STOP_BITS = 1;
private static final int CHUNK_SIZE = 512;
private UartDevice mLoopbackDevice;
private void openUart(String name, int baudRate) throws IOException {
mLoopbackDevice = PeripheralManager.getInstance().openUartDevice(name);
// Configure the UART
mLoopbackDevice.setBaudrate(baudRate);
mLoopbackDevice.setDataSize(DATA_BITS);
mLoopbackDevice.setParity(UartDevice.PARITY_NONE);
mLoopbackDevice.setStopBits(STOP_BITS);
}
public void UartInit(String UartName, int baudrate){
PeripheralManager manager = PeripheralManager.getInstance();
List<String> deviceList = manager.getUartDeviceList();
if (deviceList.isEmpty()) {
Log.i(TAG, "No UART port available on this device.");
} else {
Log.i(TAG, "List of available devices: " + deviceList);
}
// Attempt to access the UART device
try {
openUart(UartName, baudrate);
// Read any initially buffered data
Thread thread_read = new Thread(new ThreadUart(123));
thread_read.start();
} catch (IOException e) {
Log.e(TAG, "Unable to open UART device", e);
}
}
public class ThreadUart implements Runnable {
private int data_in;
public ThreadUart(int in) {
this.data_in = in;
}
#Override
public void run() {
while(true){
///////// Test Rx //////
if (mLoopbackDevice != null) {
// Loop until there is no more data in the RX buffer.
try {
byte[] buffer = new byte[CHUNK_SIZE];
int read;
while ((read = mLoopbackDevice.read(buffer, buffer.length)) > 0) { // <<<< when run long time this cannot Rx data
mLoopbackDevice.write(buffer, read);
}
} catch (IOException e) {
Log.w(TAG, "Unable to transfer data over UART", e);
}
}
// sleep 1 sec.
///////// Test Tx //////
String string = "Hello\r\n";
byte[] b = string.getBytes(StandardCharsets.UTF_8);
try {
mLoopbackDevice.write(b, b.length); // <<<< can Tx work!! always time
} catch (IOException e) {
e.printStackTrace();
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
finarly I follow Example example, It work !! in example use felHR85’s USBSerial library
however I don't know cause of Rx lost when use UART API and then run long time
I'm trying to implement a way to listen to a client's connection event on the smartphone hotspot. I see that android.net.wifi.WIFI_HOTSPOT_CLIENTS_CHANGED is no longer avaible. How can i do this? I think that this is possible because the smartphone notify me when i client make a connection to the smartphone hotspot.
You can't use the Intent Action...You have to use a custom method, i'l suggest you create a background thread that checks/reads the I.P table (/proc/net/arp) constantly and update you...here's a snippet I've used.
Read i.p list table
public ArrayList<String> getConnectedDevices() {
ArrayList<String> arrayList = new ArrayList();
try {
BufferedReader bufferedReader = new BufferedReader(new FileReader("/proc/net/arp"));
while (true) {
String readLine = bufferedReader.readLine();
if (readLine == null) {
break;
}
String[] split = readLine.split(" +");
if (split != null && split.length >= 4) {
arrayList.add(split[0]);
}
}
} catch (Exception e) {
e.printStackTrace();
}
return arrayList;
}
Create runnable to check
class CheckHotSpotConnection implements Runnable {
private CheckHotSpotConnection() {
}
public void run() {
int i = 0;
while (discoverClient()) {
i = getConnectedDevices().size();
if (i > 1) {
//client discovered
//disable client discovery to end thread
} else {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
Start Thread
new Thread(new CheckHotSpotConnection()).start();
Currently, I'm trying to figure out how to stay connected with a device via Bluetooth throughout Activities. I have a few variables that I initialize to get the connection going.
My previous activity flow is Main Page > User input Text page > Bluetooth Connection(SENDING INFO).
So in this way, every time I go back to the User Input Text Page, the Bluetooth connection will be reset because when I go the next page, it'll rerun all the receivers and stuffs.
Now I'm moving the Bluetooth Connection forward. Meaning now it is Main Page > Bluetooth Connection > User Input Text Page(SEND).
But after I connect on my Bluetooth Connection page, I'm not sure what variables I should bring over/save inside SharedPreferences, so that the Bluetooth connection stays and I can send right away.
//This method runs when I click a device on my ListView.
private OnItemClickListener mDeviceClickListener = new OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> arg0, View arg1, int arg2,
long arg3) {
// Cancel discovery because it's costly and we're about to connect
bluetoothAdapter.cancelDiscovery();
System.out.println("Bluetooth Adapter2 = "
+ bluetoothAdapter.cancelDiscovery());
SiriListItem item = delist.get(arg2);
mAdapter.notifyDataSetChanged();
// When device being clicked
count++;
click = 1;
// Get the device MAC address, which is the last 17 chars in the
// View
String info = item.message;
String address = info.substring(info.length() - 17);
BlueToothAddress = address;
if (click == 1) {
clientThread ct = new clientThread();
ct.start();
}
};
};
//This is the clientThread if click == 1, it'll start this.
private class clientThread extends Thread {
public void run() {
try {
//
bdDevice = bluetoothAdapter.getRemoteDevice(BlueToothAddress);
socket = bdDevice.createRfcommSocketToServiceRecord(UUID
.fromString("00001101-0000-1000-8000-00805F9B34FB"));
Message msg2 = new Message();
msg2.obj = "Please wait, connecting to server: "
+ BlueToothAddress;
msg2.what = 0;
LinkDetectedHandler.sendMessage(msg2);
socket.connect();
Log.i("tag", "This is the pairing section");
Message msg = new Message();
msg.obj = "Device connected. Sending message is allowed.";
msg.what = 0;
LinkDetectedHandler.sendMessage(msg);
readThread = new readThread();
readThread.start();
click++;
} catch (IOException e) {
Message msg = new Message();
msg.obj = "Error! Can't connect to device. Please try again.";
msg.what = 0;
LinkDetectedHandler.sendMessage(msg);
click--;
}
}
};
public class readThread extends Thread {
public void run() {
byte[] buffer = new byte[1024];
int bytes;
InputStream mmInStream = null;
String tmp = null;
try {
mmInStream = socket.getInputStream();
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
while (true) {
try {
// read the data from the inputStream
if ((bytes = mmInStream.read(buffer)) > 0) {
for (int i = 0; i < bytes; i++) {
tmp = "" + buffer[i];
String st = new String(tmp);
tmp = null;
Message msg = new Message();
msg.obj = st;
msg.what = 1;
}
}
} catch (IOException e) {
try {
mmInStream.close();
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
break;
}
}
}
}
//On Click it'll send the message stored in the editText.
buttonConnect.setOnClickListener(new View.OnClickListener() {
#SuppressLint("NewApi")
#Override
public void onClick(View arg0) {
if (count == 0) {
Toast.makeText(bluetoothtest.this,
"Please connect to a device first.",
Toast.LENGTH_LONG).show();
}
// Need API=14
else if (!socket.isConnected()) {
Toast.makeText(bluetoothtest.this,
"Connecting! Please wait.", Toast.LENGTH_LONG)
.show();
} else {
try {
sendMessageHandle(contentRow1.getText().toString(),
contentRow2.getText().toString(), contentRow3
.getText().toString(), contentRow4
.getText().toString());
// sendMessageHandle(contentRow2.getText().toString());
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
});
So the main thing is. What method should I have in my User Input Text Page? Must I have all this method in my User Input Text Page or can I just bring over variables via SharedPreferences?
Thanks.
It is probably bad practice to be handling bluetooth connections on the main thread. You should really handle the bluetooth connection/maintenance through a Service/background thread. Your activities can then talk to the service via a BroadcastReceiver and Handles.
I'm using OSMdroid Mapview and using AsyncTask class to get some data, and I create overlays and try to redraw every time I get a msg.
Unfortunately I'm able to get data from a client and I'm able to create overlays to in onProgressUpdated, I've even called invalidate(); But nothing seems to happen. Not sure what is the problem?
Here's my AsyncTask:
public class TaskManager extends AsyncTask<Void, GeoPoint, Void>{
.....
public TaskManager(Master master,MapView mapview) {
//Construtor
}
#Override
protected Void doInBackground(Void... arg0) {
if(Constance.TCPIP) {
Log.d("APP","Inside TCPIP");
//Creation of TCPIP Sockets
try {
m_ssocket = new ServerSocket(Constance.PORT_NO);
Log.d("APP","ServerSocket: "+m_ssocket);
m_socket = m_ssocket.accept();
Log.d("APP","Accepted: "+m_socket);
} catch (IOException e) {
e.printStackTrace();
}
}
else if (Constance.UDPIP) {
//Creation of UDP Sockets
try {
m_dsocket = new DatagramSocket(Constance.PORT_NO);
} catch (SocketException e) {
e.printStackTrace();
}
}
else if (Constance.MCUDP) {
//Lock Wifi multicast
mMultiCastLock = new MultiCastLock(mMaster.getBaseContext());
mMultiCastLock.setMultiCastAcquire();
//Creation of MC-UDP Sockets
try {
m_mcsocket = new MulticastSocket(Constance.PORT_NO);
InetAddress address = InetAddress.getByName(Constance.GROUP_ADDR);
m_mcsocket.joinGroup(address);
} catch (IOException e) {
e.printStackTrace();
}
}
// Create a buffer to read datagrams into.
byte[] mSocketbuffer = new byte[Constance.DGRAM_LEN];
if(Constance.TCPIP) {
try {
m_inSocketData = new BufferedReader(new InputStreamReader(m_socket.getInputStream()));
Log.d("APP","Reading");
} catch (IOException e) {
e.printStackTrace();
}
} else {
// Create a packet to receive data into the buffer
m_inPacket = new DatagramPacket(mSocketbuffer, mSocketbuffer.length);
}
//prepare overlay items
prepareItemizedOverlay();
// Now loop forever, waiting to receive packets and printing them.
if(m_ssocket!=null || m_dsocket!=null || m_mcsocket!=null)
while (true) {
if (isCancelled()) break;
//Get Data
parseData();
//Make Packet Object
if(mMSG!=null) {
make(mMSG);
}
if(m_inPacket!=null && !Constance.TCPIP) {
// Reset the length of the packet before reusing it.
m_inPacket.setLength(mSocketbuffer.length);
}
}
return null;
}
#Override
protected void onProgressUpdate(GeoPoint... geoPoints){
OverlayItem overlayItem = new OverlayItem("Name", "Description", geoPoints[0]);
mItemizedOverlay.addOverlay(overlayItem);
mMapView.getOverlays().add(mItemizedOverlay);
mMapView.getController().animateTo(geoPoints[0]);
mMapView.invalidate();
}
#Override
protected void onCancelled() {
super.onCancelled();
if(Constance.TCPIP) {
if(m_ssocket!=null && m_socket!=null){
try {
m_ssocket.close();
m_socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
} else if(Constance.UDPIP) {
if(m_dsocket!=null)
m_dsocket.close();
} else if(Constance.MCUDP) {
if(m_mcsocket!=null)
m_mcsocket.close();
}
Log.d("APP","Task Ended");
}
private void parseData() {
if(Constance.TCPIP) {
// Wait to receive a socket data
try{
mMSG = m_inSocketData.readLine();
} catch (IOException e) {
e.printStackTrace();
}
} else {
// Wait to receive a datagram
try {
m_dsocket.receive(m_inPacket);
// Convert the contents to a string, and display them
} catch (IOException e) {
e.printStackTrace();
}
}
}
private void make(String plot) {
//Make Object
mMSG = new MSG(plot);
//Overlay
mGeoPoint = mMSG.getGeoPoint();
publishProgress(mMSG.getGeoPoint());
}
private void prepareItemizedOverlay() {
/* itemized overlay */
Drawable newMarker = mMaster.getResources().getDrawable(R.drawable.ic_sensor);
mItemizedOverlay = new PlotItemOverlay(mMaster,mItemList,newMarker,
new ItemizedIconOverlay.OnItemGestureListener<OverlayItem>() {
#Override
public boolean onItemSingleTapUp(int index, OverlayItem item) {
Log.d("APP","HERE");
return true;
}
#Override
public boolean onItemLongPress(int index, OverlayItem item) {
return true;
}
}, mResourceProxy);
}
}
Everything seems to work, but nothing seems to happen, not sure what is the problem?
Finally resolved it. I was actually replacing my MapFragment class which led to all this loss of Object and a new object created was interfacing the old one, and so the data received to interfacing to the older MapFragment and not the new MapFragment. Got it resolved, once I found the logically analyzing the code. Anyways, thanks for the support #kurtzmarc you have been very helpful until now. I will continue same with OSMdroid to see any more things that I come up with.
I was wondering how to use a handler in android to send two messages from a separate thread to update UI. The thread is declared in another file. I understand that using java Thread is not desirable in Android, but I have given up using android methods, they are terrible. The handler messages are sent every 200 miliseconds from my declared thread. I cannot find a decent example of how to implement it.
Here is my extended thread. This is called from the activity.
import java.io.IOException;
import android.media.MediaPlayer;
import android.os.Bundle;
import android.os.Message;
public class MPlayer extends Thread {
private volatile boolean playing = false;
private volatile boolean finished = false;
MediaPlayer player;
Message msg;
Bundle bundle;
String filepath;
/* other fields, constructor etc. */
public MPlayer(String path) {
filepath = path;
player = new MediaPlayer();
bundle = new Bundle();
msg = new Message();
start();
}
public void seekMPlayer(int i) {
// TODO Auto-generated method stub
player.seekTo(i);
}
public boolean getPlaying() {
// TODO Auto-generated method stub
return playing;
}
#Override
public void run() {
try {
player.setDataSource(filepath);
player.prepare();
} catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalStateException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
while (!finished) {
while (playing && !finished) {
try {
Thread.sleep(200);
if (playing && !finished) {
bundle.putString("progval", songTime());
// msg.setData(bundle);
// threadHandler.sendMessage(msg);
} else
break;
} catch (InterruptedException e) {
}
}
}
}
public synchronized void pauseMPlayer() {
playing = false;
player.pause();
}
public synchronized void PlayMPlayer() {
playing = true;
player.start();
// call notify() here when you switch to wait/notify.
}
public void stopMPlayer() {
playing = false;
finished = true;
player.release();
// call notify() here too.
}
private String songTime() {
// TODO Auto-generated method stub
if (filepath != null) {
int progressseconds = (int) ((player.getCurrentPosition() / 1000) % 60);
int progressminutes = (int) ((player.getCurrentPosition() / 1000) / 60);
int durationseconds = (int) ((player.getDuration() / 1000) % 60);
int durationminutes = (int) ((player.getDuration() / 1000) / 60);
String progmin, progsec, durmin, dursec;
if (progressminutes >= 10)
progmin = Integer.toString(progressminutes);
else
progmin = "0" + Integer.toString(progressminutes);
if (progressseconds >= 10)
progsec = Integer.toString(progressseconds);
else
progsec = "0" + Integer.toString(progressseconds);
if (durationminutes >= 10)
durmin = Integer.toString(durationminutes);
else
durmin = "0" + Integer.toString(durationminutes);
if (durationseconds >= 10)
dursec = Integer.toString(durationseconds);
else
dursec = "0" + Integer.toString(durationseconds);
return (progmin + ":" + progsec + "/" + durmin + ":" + dursec);
} else {
return ("No File!");
}
}
}
Handler should bind a Looper of the thread. Use this constructor to specify a thread looper
Handler handler = new Handler(Looper.getMainLooper());
And now the you can send message to the main thread
There is nothing wrong in using Java threads in Android but it is a bit overkill to use it just for sending periodic messages. The recommended way to do it is to use Handler.postDelayed. This article suggests following method: put all your updating code into a Runnable and add postDelayed call to the end of this Runnable's run() to schedule it again. This approach eliminates overhead of having a background thread.
However it is easy to use Handler to send messages from the other thread. As I understand you are trying to send messages to some UI component so it can update itself.
In my application I faced a similar problem. I declared a handler inside the UI component and passed this handler to a background thread in a constructor parameter.
The UI part looks like:
class MyActivity extends Activity {
Handler mHandler = new Handler() {
public void handleMessage(Message msg) {
// update UI according to a content of msg from background thread
// ...
}
};
private Thread mBackgroundWorker = new BackgroundThread(mHandler);
protected void onCreate(Bundle savedInstanceState) {
// ...
mBackgroundWorker.start();
// ...
}
protected void onDestroy() {
// we created the thread in this activity
// so we should manage its lifecycle here
mBackgroundWorker.interrupt();
}
}
And the background thread is implemented like
class BackgroundThread extends Thread {
private final mHandler;
public BackgroundThread(Handler h) {
mHandler = h;
}
public void run() {
// do some processing...
mHandler.sendMessage(/*some message to update an UI*/);
// ...
}
}