问题
I'm trying to connect to a server and print the responses.
Weird thing is that when I click on the button in my activity that starts the connection,
it force closes immediately.
After looking in logcat
, what I see is that VM is shutting down.
I do see that there appears to be someone that saw a similar problem as me:
The logcat in android shows simply shutting down the VM?
Unfortunately, I don't think the problem was actually answered, and it really puzzles me.
Stack trace:
03-06 20:12:47.012: I/System.out(2757): I'm in main
03-06 20:12:48.092: D/gralloc_goldfish(2757): Emulator without GPU emulation detected.
03-06 20:13:03.462: I/System.out(2757): I'm at quote viewer
03-06 20:13:04.291: I/Choreographer(2757): Skipped 32 frames! The application may be doing too much work on its main thread.
03-06 20:13:09.881: D/AndroidRuntime(2757): Shutting down VM
03-06 20:13:09.881: W/dalvikvm(2757): threadid=1: thread exiting with uncaught exception (group=0x40a70930)
03-06 20:13:09.901: D/dalvikvm(2757): GC_CONCURRENT freed 130K, 9% free 2652K/2888K, paused 80ms+5ms, total 222ms
03-06 20:13:09.941: E/AndroidRuntime(2757): FATAL EXCEPTION: main
03-06 20:13:09.941: E/AndroidRuntime(2757): java.lang.IllegalStateException: Could not execute method of the activity
Line 3 ("I'm at quote viewer") is the part where I'm in the QuoteViewerActivity where I have a button that connects to the server when pressed.
Code for the QuoteViewerActivity below:
package com.pheno.networkprogrammingiphenoexercise;
import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.TextView;
import java.io.BufferedReader;
import java.io.IOException;
import java.net.Socket;
import java.net.UnknownHostException;
public class QuoteViewerActivity extends Activity {
private String mHost = "ota.iambic.com";
private int mPort = 17;
private TextView mQuote1, mQuote2, mQuote3;
@Override
public void onCreate(Bundle savedInstanceState) {
System.out.println("I'm at quote viewer");
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_quote_viewer);
mQuote1 = (TextView)findViewById(R.id.quote1);
mQuote2 = (TextView)findViewById(R.id.quote2);
mQuote3 = (TextView)findViewById(R.id.quote3);
}
public void showQuotes(View clickedButton) {
try {
TextView[] quoteArray = {mQuote1, mQuote2, mQuote3};
for(int i = 0; i < 3; i++) {
Socket socket = new Socket(mHost, mPort);
System.out.println("Get Socket");
BufferedReader in = SocketUtils.getReader(socket);
String quoteResult = in.readLine();
System.out.println(quoteResult);
quoteArray[i].setText(quoteResult);
socket.close();
}
} catch(UnknownHostException uhe) {
mQuote1.setText("Unknown host: " + mHost);
//uhe.printStackTrace();
Log.e("pheno", "What happened", uhe);
} catch(IOException ioe) {
mQuote1.setText("IOException: " + ioe);
Log.e("pheno", "What happened", ioe);
}
}
}
Any help or suggestion would be much appreciated! Thanks!
回答1:
I cannot be certain why the emulator is showing this exact error, but I do know for a fact that what you're doing is frowned upon greatly in pre-4.0 devices (and emulators) and typically forbidden in 4.0+ devices. That is, you should always do any network calls on a separate thread. The proper way to do this is with an AsyncTask.
These objects are quite ugly, but are also the best way to ensure that you are not tying up the UI thread. The UI thread is the thread on which your showQuotes
method is currently running, and Android expects this thread to do only brief things. If it starts to queue up too many events, Android 4.0+ will crash the app. I think pre-4.0 it will just appear to be frozen (essentially exactly what you want it to do I guess), but I wouldn't count on it.
So, with an AsyncTask, you would write it like so:
AsyncTask<Void, Void, Void> task = new AsyncTask<Void, Void, Void>()
{
String someData = "";
@Override
protected Void doInBackground(Void... unused)
{
// Here, do your networking stuff, but don't access
// UI elements (such as whatever.setText).
someData = getStuffFromSocketsBlahBlah();
// This method is called from a different (non-UI thread) automatically
// shortly after you call task.execute()
}
@Override
protected void onPostExecute(Void unused)
{
// This will get called from the main (UI thread) shortly after doInBackground returns.
// Here it is okay to access UI elements but not to do any serious work
// or blocking network calls (such as socket.read, etc.)
someTextView.setText(someData);
}
};
task.execute(null, null, null);
It sucks that you have to do things like this, since it's counter-intuitive compared to writing a Desktop application, but the issue is that Android has to run multiple apps at the same time and be able to quickly suspend your application at any moment when another app comes to the foreground (this allows Android to 'multitask' without the battery draining), which is why your UI thread always has to be more or less available for incoming events.
来源:https://stackoverflow.com/questions/15257976/logcat-showing-shutting-down-vm