I'm a little bit confused....
I have the following method and my App is closing without a Force close dialog. And I don't know why. I think it should be all fine...
I can't give more information. If you want more, please ask me.
public void findCC3000(View view) {
new AsyncTask<String, Integer, String>() {
private ProgressDialog dialog;
protected void onPreExecute() {
dialog = new ProgressDialog(MainActivity.this);
dialog.setMax(64516);
dialog.setCancelable(false);
dialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
this.dialog.setProgress(0);
this.dialog.show();
}
#Override
protected String doInBackground(String... strings) {
int port = Integer.valueOf(((EditText) MainActivity.this.findViewById(R.id.editText_port)).getText().toString());
String ip = ((EditText) MainActivity.this.findViewById(R.id.editText_ip)).getText().toString();
try {
out("try to connect");
socket = new Socket(ip, port);
PrintWriter printWriter = new PrintWriter(socket.getOutputStream(), true);
printWriter.println("");
BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
String fromServer;
out("listen for message");
while ((fromServer = in.readLine()) != null) { //CRASH-------------------------------------------------------
out(fromServer);
if (fromServer.equals("Connected to CC3000")) {
out("CC3000 found! : " + ip);
//startListenThread();
out("Started Lissten thread " );
findViewById(R.id.button_connect).setEnabled(false);
findViewById(R.id.joystickView_geschwindigkeit).setEnabled(true);
findViewById(R.id.joystickView_lenkung).setEnabled(true);
return ip;
}
}
} catch (UnknownHostException e) {
out(e.getMessage());
} catch (IOException e) {
out(e.getMessage());
}
return "";
}
protected void onProgressUpdate(Integer... progress) {
dialog.setProgress(progress[0]);
}
protected void onPostExecute(String result) {
if (dialog != null && dialog.isShowing()) {
dialog.dismiss();
}
if (result.isEmpty())
Toast.makeText(MainActivity.this, "CC3000 not found! :(", Toast.LENGTH_SHORT).show();
else
Toast.makeText(MainActivity.this, "CC3000 found! :)", Toast.LENGTH_SHORT).show();
ip = result;
}
}.execute("192.168.");
}
But I know the place.
So the important part is (the readLine()):
while ((fromServer = in.readLine()) != null) { //CRASH-------------------------------------------------------
out(fromServer);
if (fromServer.equals("Connected to CC3000")) {
out("CC3000 found! : " + ip);
//startListenThread();
out("Started Lissten thread " );
findViewById(R.id.button_connect).setEnabled(false);
findViewById(R.id.joystickView_geschwindigkeit).setEnabled(true);
findViewById(R.id.joystickView_lenkung).setEnabled(true);
return ip;
}
}
This is my Logcat:
06-06 16:12:16.494 20152-20166/de.mayerhofersimon.cc3000.main
W/dalvikvm﹕ threadid=11: thread exiting with uncaught exception
(group=0x4155dce0)
Hope you can help.
regards
Only the UI Thread can touch the UI. You can take a look the implementation of setEnabled
4586 public void More ...setEnabled(boolean enabled) {
4587 if (enabled == isEnabled()) return;
4588
4589 setFlags(enabled ? ENABLED : DISABLED, ENABLED_MASK);
4590
4591 /*
4592 * The View most likely has to change its appearance, so refresh
4593 * the drawable state.
4594 */
4595 refreshDrawableState();
4596
4597 // Invalidate too, since the default behavior for views is to be
4598 // be drawn at 50% alpha rather than to change the drawable.
4599 invalidate(true);
4600 }
Related
I've been struggling the whole day to make an Android client application. I managed to get the answer from the server but i can't properly display it in a text View. I did the app using other answers from here or Youtube videos.
The application should be really simple.Then i press a button, it sends a SQL query to the server and it returns some data from the database which should be displayed in a text View.
I'll post the code and then explain where the problem occurs:
public class MainActivity extends Activity
{
private TextView serverMessage;
private Thread thread;
private Socket clientSocket;
private String mesaj;
String answer = "";
String partial = "";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
serverMessage = (TextView)findViewById((R.id.textView));
}
#Override
protected void onResume() {
super.onResume();
}
#Override
protected void onDestroy() {
super.onDestroy();
}
#Override
protected void onRestart() {
super.onRestart();
}
#Override
protected void onStart() {
super.onStart();
}
#Override
protected void onPause() {
super.onPause();
}
public void Start(View v)
{
thread = new Thread(new Runnable() {
#Override
public void run() {
try {
clientSocket = new Socket("92.55.154.98", 100);
Log.d("Sending server", "SEnding " + "SELECT * FROM Pubs");
PrintWriter out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(clientSocket.getOutputStream())), true);
out.println("SELECT * FROM Pubs");
BufferedReader in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
while ((partial = in.readLine()) != null) {
answer= answer + partial +"\n" ;
Log.e("In while", answer);
}
in.close();
clientSocket.close();
Log.e("After while", answer);
Message answer = null;
answer.obj=answer;
handler.sendMessage(answer);
}
catch (Exception e) {
e.printStackTrace();
}
}
});
thread.start();
answer="";
//serverMessage.setText(answer);
}
Handler handler = new Handler() {
#Override
public void handleMessage(Message msg)
{ Log.w("Message recieved ?? ", msg.obj.toString());
messageDisplay(msg.obj.toString());
}
};
public void messageDisplay(String mesaj)
{
serverMessage.setText(mesaj);
}
}
The problem appears here in the Start method:
while ((partial = in.readLine()) != null) {
answer= answer + partial +"\n" ;
Log.e("In while", answer);
}
in.close();
clientSocket.close();
Log.e("After while", answer);
The log properly shows me the answer String just inside the while loop. After the while loop ends, nothing else from this method runs. It doesn't display the log that i placed after the while loop Log.e("After while", answer); I managed to show the second log just if i closed the server, but it crashed when it tried to run the rest of the code.
The result is somehow showed if i uncomment this part that's at the end of the Start method:
thread.start();
answer="";
//serverMessage.setText(answer);
In this case he result is only showed if i press the button twice !
Does anybody have an ideea why it acts like that and is there a solution ?
Instead of
Message answer = null;
answer.obj=answer;
handler.sendMessage(answer);
which is guaranteed to fail with a NullpointerException (if you make it compile) try
handler.obtainMessage(0, answer).sendToTarget();
I am writing an IRC Client. The socket connection to the IRC Server is handled via a service. I have managed to stabilize all the UI elements of the Activities in question during the orientation change, but somehow the socket that is maintained by the service is being closed during the change.
Here is what I believe to be the relevant code. Please let me know if you need to see more.
//This is the Service in question
public class ConnectionService extends Service{
private BlockingQueue<String> MessageQueue;
public final IBinder myBind = new ConnectionBinder();
public class ConnectionBinder extends Binder {
ConnectionService getService() {
return ConnectionService.this;
}
}
private Socket socket;
private BufferedWriter writer;
private BufferedReader reader;
private IRCServer server;
private WifiManager.WifiLock wLock;
private Thread readThread = new Thread(new Runnable() {
#Override
public void run() {
try {
String line;
while ((line = reader.readLine( )) != null) {
if (line.toUpperCase().startsWith("PING ")) {
SendMessage("PONG " + line.substring(5));
}
else
queueMessage(line);
}
}
catch (Exception e) {}
}
});
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
if(MessageQueue == null)
MessageQueue = new LinkedBlockingQueue<String>();
return Service.START_STICKY;
}
#Override
public IBinder onBind(Intent arg0) {
return myBind;
}
#Override
public boolean stopService(Intent name) {
try {
socket.close();
wLock.release();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return super.stopService(name);
}
#Override
public void onDestroy()
{//I put this here so I had a breakpoint in place to make sure this wasn't firing instead of stopService
try {
socket.close();
wLock.release();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
super.onDestroy();
}
public void SendMessage(String message)
{
try {
writer.write(message + "\r\n");
writer.flush();
} catch (IOException e) {
e.printStackTrace();
}
}
public String readLine()
{
try {
if(!isConnected())
return null;
else
return MessageQueue.take();
} catch (InterruptedException e) {
return "";
}
}
public boolean ConnectToServer(IRCServer newServer)
{
try {
//create a new message queue (connecting to a new server)
MessageQueue = new LinkedBlockingQueue<String>();
//lock the wifi
WifiManager wifiManager = (WifiManager) getSystemService(Context.WIFI_SERVICE);
wLock = wifiManager.createWifiLock(WifiManager.WIFI_MODE_FULL, "LockTag");
wLock.acquire();
server = newServer;
//connect to server
socket = new Socket();
socket.setKeepAlive(true);
socket.setSoTimeout(60000);
socket.connect(new InetSocketAddress(server.NAME, Integer.parseInt(server.PORT)), 10000);
writer = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
//run basic login scripts.
if(server.PASS != "")
SendMessage("PASS " + server.PASS);
//write nickname
SendMessage("NICK " + server.NICK);
//write username login
SendMessage("USER " + server.NICK + " 0 * :Fluffy IRC");
String line;
while ((line = reader.readLine( )) != null) {
if (line.indexOf("004") >= 0) {
// We are now logged in.
break;
}
else if (line.indexOf("433") >= 0) {
//change to alt Nick
if(!server.NICK.equals(server.ALT_NICK) && !server.ALT_NICK.equals(""))
{
server.NICK = server.ALT_NICK;
SendMessage("NICK " + server.NICK);
}
else
{
queueMessage("Nickname already in use");
socket.close();
return false;
}
}
else if (line.toUpperCase().startsWith("PING ")) {
SendMessage("PONG " + line.substring(5));
}
else
{
queueMessage(line);
}
}
//start the reader thread AFTER the primary login!!!
CheckStartReader();
if(server.START_CHANNEL == null || server.START_CHANNEL == "")
{
server.WriteCommand("/join " + server.START_CHANNEL);
}
//we're done here, go home everyone
} catch (NumberFormatException e) {
return false;
} catch (IOException e) {
return false;
}
return true;
}
private void queueMessage(String line) {
try {
MessageQueue.put(line);
} catch (InterruptedException e) {
}
}
public boolean isConnected()
{
return socket.isConnected();
}
public void CheckStartReader()
{
if(this.isConnected() && !readThread.isAlive())
readThread.start();
}
}
//Here are the relevant portions of the hosting Activity that connects to the service
//NOTE: THE FOLLOWING CODE IS PART OF THE ACTIVITY, NOT THE SERVICE
private ConnectionService conn;
private ServiceConnection mConnection = new ServiceConnection() {
#Override
public void onServiceConnected(ComponentName name, IBinder service) {
conn = ((ConnectionService.ConnectionBinder)service).getService();
Toast.makeText(main_tab_page.this, "Connected", Toast.LENGTH_SHORT)
.show();
synchronized (_serviceConnWait) {
_serviceConnWait.notify();
}
}
#Override
public void onServiceDisconnected(ComponentName name) {
conn = null;
}
};
#Override
protected void onSaveInstanceState(Bundle state){
super.onSaveInstanceState(state);
state.putParcelable("Server", server);
state.putString("Window", CurrentTabWindow.GetName());
unbindService(mConnection);
}
#Override
protected void onDestroy()
{
super.onDestroy();
if(this.isFinishing())
stopService(new Intent(this, ConnectionService.class));
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main_tab_page);
localTabHost = (TabHost)findViewById(R.id.tabHostMain);
localTabHost.setup();
localTabHost.setOnTabChangedListener(new tabChange());
_serviceConnWait = new Object();
if(savedInstanceState == null)
{//initial startup, coming from Intent to start
//get server definition
server = (IRCServer)this.getIntent().getParcelableExtra(IRC_WINDOW);
server.addObserver(this);
AddTabView(server);
startService(new Intent(this, ConnectionService.class));
}
else
{
server = (IRCServer)savedInstanceState.getParcelable("Server");
String windowName = savedInstanceState.getString("Window");
//Add Needed Tabs
//Server
if(!(windowName.equals(server.GetName())))
AddTabView(server);
//channels
for(IRCChannel c : server.GetAllChannels())
if(!(windowName.equals(c.GetName())))
AddTabView(c);
//reset each view's text (handled by tabChange)
if(windowName.equals(server.GetName()))
SetCurrentTab(server.NAME);
else
SetCurrentTab(windowName);
ResetMainView(CurrentTabWindow.GetWindowTextSpan());
//Rebind to service
BindToService(new Intent(this, ConnectionService.class));
}
}
#Override
protected void onStart()
{
super.onStart();
final Intent ServiceIntent = new Intent(this, ConnectionService.class);
//check start connection service
final Thread serverConnect = new Thread(new Runnable() {
#Override
public void run() {
if(!BindToService(ServiceIntent))
return;
server.conn = conn;
conn.ConnectToServer(server);
server.StartReader();
if(server.START_CHANNEL != null && !server.START_CHANNEL.equals(""))
{
IRCChannel chan = server.FindChannel(server.START_CHANNEL);
if(chan != null)
{
AddTabView(chan);
}
else
{
server.JoinChannel(server.START_CHANNEL);
chan = server.FindChannel(server.START_CHANNEL);
AddTabView(chan);
}
}
}
});
serverConnect.start();
}
private boolean BindToService(Intent ServiceIntent)
{
int tryCount = 0;
bindService(ServiceIntent, mConnection, Context.BIND_AUTO_CREATE);
while(conn == null && tryCount < 10)
{
tryCount++;
try {
synchronized (_serviceConnWait) {
_serviceConnWait.wait(1500);
}
}
catch (InterruptedException e) {
//do nothing
}
}
return conn != null;
}
Im not entirely certain what I am doing wrong there. Obviously there's something I'm missing, haven't found yet, or haven't even thought to check. What happens though is that after the orientation change my Send command gives me this message and nothing happens:
06-04 22:02:27.637: W/System.err(1024): java.net.SocketException: Socket closed
06-04 22:02:27.982: W/System.err(1024): at com.fluffyirc.ConnectionService.SendMessage(ConnectionService.java:90)
I have no idea when the socket is getting closed, or why.
Update
I have changed the code so that rather than binding to the service and using that to start it, instead I call startService and stopService at appropriate points as well as binding to it, on the thought that the service was being destroyed when the binding was lost. This is working exactly like it was before I changed it. The socket still closes on an orientation change, and I have no idea why.
Update :- Code and description
I added the code changes recently made for Start/Stop service and START_STICKY. I also recently read a very good article explaining how the orientation change process flow works and why its NOT a bad idea to add the android:configChanges="orientation|screenSize" line to your manifest. So this fixed the orientation issue, but its still doing the same thing if I put the activity into background mode, and then bring it back to the foreground. That still follows the same Save/Destroy/Create process that the orientation does without that manifest line...and it still closes my socket, and I still don't know why.
I do know that it doesn't close the socket until the re-create process...I know this because the message queue will display messages that were received while the app was in the background, but once I bring it back forward it closes the socket and nothing else can be sent or received.
'Socket closed' means that you closed the socket and then continued to use it. It isn't a 'disconnect'.
You need to put something into that catch block. Never just ignore an exception. You might get a surprise when you see what the exception actually was.
NB Socket.isConnected() doesn't tell you anything about the state of the connection: only whether you have ever connected the Socket. You have, so it returns true.
Is there a way to ping a host (standard Android or via NDK implementation), and get detailed info on the response? (time, ttl, lost packages, etc..)
I was thinking of some open source app that has this feature but can't find any...
Thanks
Afaik, sending ICMP ECHO requests needs root (i.e. the app that does it needs to be setuid) - and that's not currently possible in "stock" Android (hell, even the InetAddress#isReachable() method in Android is a joke that doesn't work according to spec).
A very basic example using /usr/bin/ping & Process - reading the ping results, using an AsyncTask:
public class PingActivity extends Activity {
PingTask mTask;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
#Override
protected void onResume() {
super.onResume();
mTask = new PingTask();
// Ping the host "android.com"
mTask.execute("android.com");
}
#Override
protected void onPause() {
super.onPause();
mTask.stop();
}
class PingTask extends AsyncTask<String, Void, Void> {
PipedOutputStream mPOut;
PipedInputStream mPIn;
LineNumberReader mReader;
Process mProcess;
TextView mText = (TextView) findViewById(R.id.text);
#Override
protected void onPreExecute() {
mPOut = new PipedOutputStream();
try {
mPIn = new PipedInputStream(mPOut);
mReader = new LineNumberReader(new InputStreamReader(mPIn));
} catch (IOException e) {
cancel(true);
}
}
public void stop() {
Process p = mProcess;
if (p != null) {
p.destroy();
}
cancel(true);
}
#Override
protected Void doInBackground(String... params) {
try {
mProcess = new ProcessBuilder()
.command("/system/bin/ping", params[0])
.redirectErrorStream(true)
.start();
try {
InputStream in = mProcess.getInputStream();
OutputStream out = mProcess.getOutputStream();
byte[] buffer = new byte[1024];
int count;
// in -> buffer -> mPOut -> mReader -> 1 line of ping information to parse
while ((count = in.read(buffer)) != -1) {
mPOut.write(buffer, 0, count);
publishProgress();
}
out.close();
in.close();
mPOut.close();
mPIn.close();
} finally {
mProcess.destroy();
mProcess = null;
}
} catch (IOException e) {
}
return null;
}
#Override
protected void onProgressUpdate(Void... values) {
try {
// Is a line ready to read from the "ping" command?
while (mReader.ready()) {
// This just displays the output, you should typically parse it I guess.
mText.setText(mReader.readLine());
}
} catch (IOException t) {
}
}
}
}
I found a way to execute ping command without root.
Spawns a 'sh' process first, and then execute 'ping' in that shell, the code:
p = new ProcessBuilder("sh").redirectErrorStream(true).start();
DataOutputStream os = new DataOutputStream(p.getOutputStream());
os.writeBytes("ping -c 10 " + host + '\n');
os.flush();
// Close the terminal
os.writeBytes("exit\n");
os.flush();
// read ping replys
BufferedReader reader = new BufferedReader(new InputStreamReader(p.getInputStream()));
String line;
while ((line = reader.readLine()) != null) {
System.out.println(line);
}
It works fine on my HTC device with CyanogenMod 7.1.0 (Android 2.3.7)
I have a main activity with launch mode set as "singleTask". When I bring it to the foreground and the onNewIntent method is called, it runs an AsyncTask containing a while loop which reads lines from a text file.
Part way into this loop, the value of one of my integer variables changes to 0. This doesn't always happen in the same stage in the loop cycle and the loop has nothing to do with this variable at all so I don't understand why this is happening.
Here's an image that might better explain the problem:
http://i.stack.imgur.com/ogLQh.jpg
EDIT: Code as requested:
private class ReadFile extends AsyncTask<String, String, String> implements DialogInterface.OnCancelListener {
protected void onPreExecute() {
//Launch dialog
}
protected String doInBackground(String... path) {
try {
File f = new File(path[0]);
FileInputStream in = new FileInputStream(f);
InputStreamReader ir;
ir = new InputStreamReader(in);
BufferedReader br = new BufferedReader(ir);
StringBuffer sb = new StringBuffer();
String str = new String();
while ((str = br.readLine()) != null) {
Log.i("My Variable",Integer.toString(myVariable));
sb.append(str);
sb.append("\n\n");
}
br.close();
myTextFile = sb.toString();
} catch (IOException e) {
e.printStackTrace();
}
return "";
}
protected void onProgressUpdate(String... progress) {
//Nothing here
}
protected void onPostExecute(final String unusedString) {
//Dismiss dialog
}
protected void onCancelled() {
finish();
}
public void onCancel(DialogInterface dialog) {
cancel(true);
}
}
myVariable seems to be changed from UI thread (activity thread). Try to add logging in each place where you modify myVariable.
I am using a socket thread.
It takes about 5 to 10 seconds to receive a message after sending a request message.
during that time I want my main thread to show "Please wait" popup.
The process flow of the program looks something like this.
show Popup
create socket thread.
-> this will connect to server
send request message to server
receive message.
My problem is that the show popup does not show up,
until after the socket thread receives its message.
Can anybody tell me a workaround to this problem?
public class LoginActivity extends Activity {
.... <some coded>
public void onClickLogin(View view) {
Log.d(this.toString(), "onClickLogin");
showLoginLoadingPopup();
String login_id = ((EditText)findViewById(R.id.login_id)).getText().toString();
String login_pwd = ((EditText)findViewById(R.id.login_pwd)).getText().toString();
conn = new Connection(handler, 1, null);
conn.start();
conn.sendData(Connection.SSPH_USERCERT, new String[] {login_id, login_pwd});
}
}
public class Connection extends Thread implements ConnectionConstant {
private InetAddress serverAddr;
private int serverPort;
private Socket socket;
PrintWriter out;
BufferedReader in;
private Handler handler;
public Connection(Handler h, int type, ServerClass server) {
Log.d(this.toString(), "Conncetion");
setServerInfo(type, server);
handler = h;
try {
connect();
} catch (Exception e) {
Log.e(this.toString(), "Error", e);
}
}
public void run() {
Log.d(this.toString(), "run");
try {
queue();
disconnect();
} catch (Exception e) {
Log.i(this.toString(), "Information", e);
}
}
private void connect() throws Exception {
if (serverAddr != null)
Log.d(this.toString(), "connect " + serverAddr.getHostName() + "("
+ Integer.toString(serverPort) + ")");
else
Log.d(this.toString(), "connect ");
socket = new Socket(serverAddr, serverPort);
socket.setSoLinger(true, 3000);
// UTF-8
out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(
socket.getOutputStream())), true);
in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
Log.i(this.toString(), "Socket connected!");
}
private void queue() throws Exception {
Log.d(this.toString(), "queue");
while (true) {
String sRcv = null;
sRcv = receive();
if (sRcv.length() > 0)
parseData(sRcv);
Thread.sleep(500);
Thread.yield();
}
}
private void send(String str) throws IOException {
Log.d(this.toString(), "send");
if (!socket.isConnected())
return;
Log.i(this.toString(), "Send : " + str);
out.println(str);
}
private String receive() throws Exception {
Log.d(this.toString(), "receive");
if (!socket.isConnected())
return null;
StringBuilder sb = new StringBuilder();
String str = "";
while ((str = in.readLine()) != null) {
Log.i(this.toString(), "Receive : " + str);
sb.append(str + "\n");
}
return sb.toString();
}
}
Use AsyncTask:
AsyncTask<Void, Void, Void> task = new AsyncTask<Void, Void, Void>() {
#Override
protected void onPreExecute() {
// show dialog
}
#Override
protected Void doInBackground(Void... params) {
// connect to the server
}
#Override
protected void onPostExecute(Void result) {
// close dialog
}
};
task.execute();
onPreExecute(), onPostExecute() and onProgressUpdate() are invoked on UI thread.
doInBackground() is invoked on background thread.
More about AsyncTask: http://developer.android.com/reference/android/os/AsyncTask.html
dialog = ProgressDialog.show(this, "", "Loading",true);
Runnable myRun = new Runnable(){
public void run(){
//DO ALL NETWORKING
//FINALLY DO THIS
runOnUiThread(new Runnable() {
public void run() {
}
});
};
Thread T = new Thread(myRun);
T.start();