4

サーバーに接続して応答を出力しようとしています。
奇妙なことに、接続を開始するアクティビティのボタンをクリックすると、
すぐに強制的に閉じます。
調べてみるとlogcat、VMがシャットダウンしていることがわかります。
私と同じような問題を見た人がいるように見えます
。Androidのlogcatは、単にVMをシャットダウンしていることを示していますか?
残念ながら、問題が実際に解決されたとは思いません。それは本当に私を困惑させます。

スタックトレース:

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

3行目(「私は見積もりビューアにいます」)は、QuoteViewerActivityにいる部分で、押されたときにサーバーに接続するボタンがあります。
以下のQuoteViewerActivityのコード:

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);
        }
    }
}

どんな助けや提案も大歓迎です!ありがとう!

4

1 に答える 1

2

エミュレーターがこの正確なエラーを表示している理由はわかりませんが、4.0より前のデバイス(およびエミュレーター)では実行していることが大いに嫌われ、4.0以降のデバイスでは通常禁止されていることは知っています。つまり、ネットワーク呼び出しは常に別のスレッドで実行する必要があります。これを行う適切な方法は、AsyncTaskを使用することです。

これらのオブジェクトは非常に醜いですが、UIスレッドを拘束していないことを確認するための最良の方法でもあります。UIスレッドは、showQuotesメソッドが現在実行されているスレッドであり、Androidは、このスレッドが簡単なことだけを実行することを期待しています。あまりにも多くのイベントをキューに入れ始めると、Android4.0以降はアプリをクラッシュさせます。4.0より前のバージョンはフリーズしているように見えると思いますが(基本的には、あなたが望んでいることとまったく同じです)、私はそれを当てにしません。

したがって、AsyncTaskを使用すると、次のように記述できます。

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);

デスクトップアプリケーションを作成するのに比べて直感に反するため、このようなことをしなければならないのは残念ですが、問題は、Androidが複数のアプリを同時に実行し、いつでもアプリケーションをすばやく一時停止できるようにする必要があることです。別のアプリが前面に出てきます(これにより、Androidはバッテリーを消耗することなく「マルチタスク」を実行できます)。そのため、UIスレッドは常に着信イベントに多かれ少なかれ利用可能である必要があります。

于 2013-03-06T21:16:58.557 に答える