So I have 2 threads (among others) on my application, one that modify an object (in the example , setting the position of a rectangle) and call methods so the second thread can send it on network.
First thread:
public void run(){
while(mIsRunning){
Log.i("MovingRectThread", "Run");
mX += 10;
mRect.setPos(mX,mY);
//Send Rect
mInterface.writeData(mRect);
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
Second thread:
public void run(){
int commandSize=-1;
byte[] bufferR = new byte[ANSWER_SIZE];
int answerResult = 0;
while(mIsRunning){
Log.i("ProcessThreadGraphic", "Run");
switch(mState){
case IDLEREAD:
//****************
try {
commandSize = mmInStream.read(bufferR, 0, ANSWER_SIZE);
}
catch (IOException e) {
connectionLost();
}
// We received something
if(commandSize != -1 && bufferR[0] == 0x02){
answerResult = bufferR[2];
if(answerResult == 0){
//Authorize sending again
mState = IDLEWRITE;
}
}
//*********************
break;
case IDLEWRITE:
//Trying to send something
if(mBuffer != null ){
try {
mmOutStream.write(mBuffer);
mBuffer = null;
mState = IDLEREAD;
Thread.yield();
} catch (IOException e) {
connectionLost();
}
}
//**************
break;
default:
Log.e(TAG, "Error: state unknown");
break;
}
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
and mInterface.writeData only end to call to:
public void write(byte[]buffer){
mBuffer = buffer;
}
My problem is, the threads are not working well together: one is looping multiple time before the other restart, which doesn't fit my needs as you can probably imagine, I need the first one to modify my object once, then the second thread to send it, and then only modify the object again...
Hope I've been clear enough.
Related
I am very new in Android, as a project, am doing a simon says game, and I'm having some problems representing the sequence to follow.
I tried to use a normal thread to make it follow a line (for example, the first button is lighten during X seconds, then turns off, then the yellow one....), but it didn't make it, because only the threads that created the view hierarchy can manipulate that view (in this case was the UI thread). So I had to load all the method in that thread with runOnUiThread, and at that point it worked almost perfect, because now the sequence is shown up but the frames don't. The Log tells me:
I/Choreographer: Skipped 116 frames! The application may be doing too much work on its main thread.
I have been looking for everywhere and I don't find alternatives for simulate the sequence. I leave here the code of the method.
public void createSequence(){
new Thread() {
public void run() {
runOnUiThread(new Runnable() {
#Override
public void run() {
sequence.clear();
for(byte i=0;i<rounds;i++){
add=r.nextInt((4 - 1) + 1) + 1;
if (add == 1) {
btn1.setBackgroundResource(R.drawable.button1_pressed);
try {
Log.i("Waiting for 1.","Waiting for 1.");
Thread.sleep(time);
btn1.setBackgroundResource(R.drawable.button1);
} catch (InterruptedException e) {
e.printStackTrace();
}
Log.i("Value:", "1.");
} else if (add == 2) {
btn2.setBackgroundResource(R.drawable.button2_pressed);
try {
Log.i("Waiting for 2.","Waiting for 2.");
Thread.sleep(time);
btn2.setBackgroundResource(R.drawable.button2);
} catch (InterruptedException e) {
e.printStackTrace();
}
Log.i("Value:", "2.");
} else if (add == 3) {
btn3.setBackgroundResource(R.color.colorpressedbutton3);
try {
Log.i("Waiting for 3.","Waiting for 3.");
Thread.sleep(time);
btn3.setBackgroundResource(R.drawable.button3);
} catch (InterruptedException e) {
e.printStackTrace();
}
Log.i("Value:", "3.");
} else {
btn4.setBackgroundResource(R.color.colorpressedbutton4);
try {
Log.i("Waiting for 4.","Waiting for 4.");
Thread.sleep(time);
btn4.setBackgroundResource(R.drawable.button4);
} catch (InterruptedException e) {
e.printStackTrace();
}
Log.i("Value:", "4.");
}
sequence.add(add);
}
}
});
}
}.start();
}
You almost got it.
You need to implement the timing logic in a separate thread, but the update (UI) logic on the UI thread.
Something like this:
void setState(final Button b, final int state) {
this.runOnUiThread(new Runnable() {
#Override
public void run() {
b.setBackgroundResource(state);
}
});
}
void runSequence() {
new Thread() {new Runnable() {
#Override
public void run() {
sequence.clear();
for(byte i=0;i<rounds;i++){
add=r.nextInt((4 - 1) + 1) + 1;
if (add == 1) {
setState(btn1,R.drawable.button1_pressed);
try {
Log.i("Waiting for 1.","Waiting for 1.");
Thread.sleep(time);
setState(btn1, R.drawable.button1);
} catch (InterruptedException e) {
e.printStackTrace();
}
Log.i("Value:", "1.");
} else if (add == 2) {
....
}
}).start();
}
Edit:- i'm able to start the internet using vpn.The other issues is that now i'm receiving packets in my service in this piece of code of my VpnService.But i can't think of a proper way to block particular website.I've tried using name resolution using InnetAddress but that's not giving the expected result :
**#Override
public void run()
{
Log.i(TAG, "Started");
FileChannel vpnInput = new FileInputStream(vpnFileDescriptor).getChannel();
FileChannel vpnOutput = new FileOutputStream(vpnFileDescriptor).getChannel();
try
{
ByteBuffer bufferToNetwork = null;
boolean dataSent = true;
boolean dataReceived;
while (!Thread.interrupted())
{
if (dataSent)
bufferToNetwork = ByteBufferPool.acquire();
int readBytes = vpnInput.read(bufferToNetwork);
if (readBytes > 0)
{
dataSent = true;
bufferToNetwork.flip();
Packet packet = new Packet(bufferToNetwork);
Log.e("loggg packet",packet.toString());
if (packet.isUDP())
{
deviceToNetworkUDPQueue.offer(packet);
}
else if (packet.isTCP())
{
deviceToNetworkTCPQueue.offer(packet);
}
else
{
Log.w(TAG, "Unknown packet type");
dataSent = false;
}
}
else
{
dataSent = false;
}
ByteBuffer bufferFromNetwork = networkToDeviceQueue.poll();
if (bufferFromNetwork != null)
{
bufferFromNetwork.flip();
vpnOutput.write(bufferFromNetwork);
dataReceived = true;
ByteBufferPool.release(bufferFromNetwork);
}
else
{
dataReceived = false;
}
if (!dataSent && !dataReceived)
Thread.sleep(10);
}
}
catch (InterruptedException e)
{
Log.i(TAG, "Stopping");
}
catch (IOException e)
{
Log.w(TAG, e.toString(), e);
}
finally
{
closeResources(vpnInput, vpnOutput);
}
}**
I'm receiving a packet in this format:
Packet{ip4Header=IP4Header{version=4, totalLength=40, protocol=TCP, headerChecksum=14192, sourceAddress=10.0.8.1, destinationAddress=216.58.196.100}, tcpHeader=TCPHeader{sourcePort=39217, destinationPort=443, sequenceNumber=800911985, acknowledgementNumber=823271551, headerLength=20, window=29596, checksum=32492, flags= ACK}, payloadSize=0}
I'm using THIS CODE for starter and unable to block packets.
Apps like greyshirts no root firewall and mobiwool no root firewall works perfectly and they are also vpn based.Any suggestion is most welcomed.
I developing VOIP android application that make and receive the sip call.I Build the pjsip lilbrary as described in "http://trac.pjsip.org/repos/wiki/Getting-Started/Android".
1. Hold
MainActivity.prm.setOptions(pjsua_call_flag.PJSUA_CALL_UPDATE_CONTACT
.swigValue());
try {
MainActivity.currentCall.setHold(MainActivity.prm);
} catch (Exception e) {
e.printStackTrace();
}
I found this code on pjsip documentation,but this code does not work for put a call on Hold.There is no error message return.
2.Unhold
MainActivity.prm = new CallOpParam(true);
MainActivity.prm.getOpt().setFlag(1);
try {
MainActivity.currentCall.reinvite(MainActivity.prm);
} catch (Exception e) {
e.printStackTrace();
}
Thanks.
Here is my code for hold and unHold:
public void setHold(boolean hold) {
if ((localHold && hold) || (!localHold && !hold)) return;
if(currentCall == null) return;
CallOpParam param = new CallOpParam(true);
try {
if (hold) {
currentCall.setHold(param);
localHold = true;
} else {
CallSetting opt = param.getOpt();
opt.setAudioCount(1);
opt.setVideoCount(0);
opt.setFlag(pjsua_call_flag.PJSUA_CALL_UNHOLD.swigValue());
currentCall.reinvite(param);
localHold = false;
}
} catch (Exception e) {}
}
I hope it's helpful.
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.
When another thread calls closeConnection(), the thread doesn't reach
Log.d("Subscriber", "Client thread has ended.");
Why is this? What is the blocking behaviour of a stream that has been closed? I thought trying to write or flush to it would generate an IOException, but it seems the code is still blocking somewhere. Where? I can't find info on what happens when you interrupt() on a write, or what happens when writing to a closed outputstream.
public void closeConnection() {
try {
this.interrupt();
autoCloseOutputStream.close();
} catch (IOException e) {
Log.w("Subscriber", "IOException when closing stream. Buffer might not have been flushed to client.");
}
}
#Override
public void run() {
Log.d("Subscriber","Client thread has started.");
ByteBuffer pgnAndDataBytes=null;
while(true) {
try {
pgnAndDataBytes=fmsByteBufferSubscriberQueue.take();
} catch (InterruptedException e) {
break;
}
Log.d("Subscriber","Still running thread");
try {
autoCloseOutputStream.write(pgnAndDataBytes.array());
autoCloseOutputStream.flush();
} catch (IOException e) {
break;
}
}
Log.d("Subscriber", "Client thread has ended.");
}
The output is as follows:
Still running thread
Still running thread
Still running thread
Close called.
And nothing more. Where is it blocking and why?
Have a volatile boolean shouldClose that you set to true on closeConnect(). Incorporate the boolean into the condition check of the while loop.
boolean done = false;
while(!shouldClose && !done) {
try{
autoCloseOutputStream.write(pgnAndDataBytes.getInt());
} catch(BufferUnderflowException bue) {
final ArrayList<Byte> remainder = new ArrayList<Byte>(3);
while(!shouldClose && !done) {
try {
remainder.add(pgnAndDataBytes.get());
} catch(BufferUnderflowException ex) {
autoCloseOutputStream.write(remainder.toArray(new Byte[remainder.size()]);
done = true;
}
}
}
}