基本后台服务尝试打开套接字

时间:2016-02-07 17:52:16

标签: java android sockets

我正在尝试使用只需按下按钮即可启动后台服务的应用。然后,后台应用程序应使用套接字打开到服务器的连接,然后发送一些虚拟数据。完成后,服务应该死了。

当我点击按钮并且整个应用程序停止时,我正在获得java.lang.IllegalStateException。 这是我迄今为止在主要活动中所拥有的。

public class MainActivity extends AppCompatActivity {

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
  }


  public void start_clicked(View view) {
    Intent my_intent = new Intent(this,BackgroundService.class);
    startActivity(my_intent);
  }
}

以下是与按钮和后台服务对应的XML: 这是Activity_Main.xml

<Button
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="Start"
    android:id="@+id/button"
    android:layout_centerVertical="true"
    android:layout_centerHorizontal="true"
    android:onClick="start_clicked"/>

这是与服务对应的Android清单

<service android:name="com.example.g.backgroundsensor.BackgroundService"
        android:exported="true"
        android:enabled="true" >
</service>

最后这是实际的BackgroundService类(我认为导致错误的片段)

public class BackgroundService extends Service {

private Socket my_socket;

public BackgroundService() {
    try {
        my_socket = new Socket(ip, 5000);
    }catch(Exception e){

    }
}
public int onStartCommand(Intent intent, int flags, int startId) {
    try {
        DataOutputStream my_stream = new DataOutputStream(my_socket.getOutputStream());
        my_stream.write(121);
    }catch(Exception e){

    }
    stopSelf();
    return 1;
}

导致此错误的原因是什么(我将来)自己调试这个错误,因为控制台相对含糊不清:

---/com.example.g.backgroundsensor E/AndroidRuntime: FATAL EXCEPTION: main
---/com.example.g.backgroundsensor E/AndroidRuntime: Process: com.example.g.backgroundsensor, PID: 9876

---/com.example.g.backgroundsensor E/AndroidRuntime: java.lang.IllegalStateException: Could not execute method of the activity

5 个答案:

答案 0 :(得分:4)

要开始Service,您应该使用startService()而不是startActivity()

Intent my_intent = new Intent(this, BackgroundService.class);
startService(my_intent);

我不知道如何调试它,但你应该总是确定你在调用的地方和你要传递的参数。

答案 1 :(得分:3)

首先你必须创建一个Intent Service而不是服务,因为在UI线程上调用了intent服务而且android不允许在UI线程上进行任何网络调用看看下面的代码

public class SocketService extends IntentService {

    @Override
    protected void onHandleIntent(Intent workIntent) {
       //CONNECT SOCKET HERE
    }
}

然后在Manifest中注册此服务

<application>
<service android:name=".SocketService" />
</application>

然后像这样开始你的服务

startService(new Intent(this, SocketService.class)); //YOU HAVE USED startActivity INSTEAD OF startService

答案 2 :(得分:1)

我有一个类似的应用程序,我的Manifest只包含这个:

<service android:name=".ServiceActivity" />

在应用程序标记内,就在活动标记之前。除此之外,你的清单应该明确:

<uses-permission android:name="android.permission.INTERNET" />

答案 3 :(得分:1)

此代码中存在两个问题。

  1. 要启动应该在后台运行的服务,您需要启动服务,因此您需要调用startservice():

    Intent my_intent = new Intent(this,BackgroundService.class); startService(my_intent);

  2. 第二大问题是您创建服务的方式。默认情况下,它将在UI线程上启动。因此,在这种情况下,您应该在单独的线程上使用IntentService或服务。

  3. 意图服务:

        public class BackgroundService extends IntentService {
            private Socket my_socket;
            @Override
            protected void onHandleIntent(Intent workIntent) {
                try {
                    my_socket = new Socket(ip, 5000);
                    DataOutputStream my_stream = new DataOutputStream(my_socket.getOutputStream());
                    my_stream.write(121);
                }catch(Exception e){
    
                }
            }
        }
    

    意向服务的主要好处是,一旦完成所有工作并且没有更多请求,它将调用stopSelf。其次,所有工作都将在后台完成。

    单独线程上的服务:

        public class BackgroundService extends Service {
          private Looper mServiceLooper;
          private ServiceHandler mServiceHandler;
    
          // Handler that receives messages from the thread
          private final class ServiceHandler extends Handler {
              public ServiceHandler(Looper looper) {
                  super(looper);
              }
              @Override
              public void handleMessage(Message msg) {
                  // Normally we would do some work here, like download a file.
                  // For our sample, we just sleep for 5 seconds.
                  public class HelloService extends Service {
      private Looper mServiceLooper;
      private ServiceHandler mServiceHandler;
    
      // Handler that receives messages from the thread
      private final class ServiceHandler extends Handler {
          public ServiceHandler(Looper looper) {
              super(looper);
          }
          @Override
          public void handleMessage(Message msg) {
              // Normally we would do some work here, like download a file.
              // For our sample, we just sleep for 5 seconds.
              try {
                  Thread.sleep(5000);
              } catch (InterruptedException e) {
                  // Restore interrupt status.
                  Thread.currentThread().interrupt();
              }
              // Stop the service using the startId, so that we don't stop
              // the service in the middle of handling another job
              stopSelf(msg.arg1);
          }
      }
    
      @Override
      public void onCreate() {
        // Start up the thread running the service.  Note that we create a
        // separate thread because the service normally runs in the process's
        // main thread, which we don't want to block.  We also make it
        // background priority so CPU-intensive work will not disrupt our UI.
        HandlerThread thread = new HandlerThread("ServiceStartArguments",
                Process.THREAD_PRIORITY_BACKGROUND);
        thread.start();
    
        // Get the HandlerThread's Looper and use it for our Handler
        mServiceLooper = thread.getLooper();
        mServiceHandler = new ServiceHandler(mServiceLooper);
      }
    
      @Override
      public int onStartCommand(Intent intent, int flags, int startId) {
          Toast.makeText(this, "service starting", Toast.LENGTH_SHORT).show();
    
          // For each start request, send a message to start a job and deliver the
          // start ID so we know which request we're stopping when we finish the job
          Message msg = mServiceHandler.obtainMessage();
          msg.arg1 = startId;
          mServiceHandler.sendMessage(msg);
    
          // If we get killed, after returning from here, restart
          return START_STICKY;
      }
    
      @Override
      public IBinder onBind(Intent intent) {
          // We don't provide binding, so return null
          return null;
      }
    
      @Override
      public void onDestroy() {
        Toast.makeText(this, "service done", Toast.LENGTH_SHORT).show();
      }
    }
                  // Stop the service using the startId, so that we don't stop
                  // the service in the middle of handling another job
                  stopSelf(msg.arg1);
              }
          }
    
          @Override
          public void onCreate() {
            // Start up the thread running the service.  Note that we create a
            // separate thread because the service normally runs in the process's
            // main thread, which we don't want to block.  We also make it
            // background priority so CPU-intensive work will not disrupt our UI.
            HandlerThread thread = new HandlerThread("ServiceStartArguments",
                    Process.THREAD_PRIORITY_BACKGROUND);
            thread.start();
    
            // Get the HandlerThread's Looper and use it for our Handler
            mServiceLooper = thread.getLooper();
            mServiceHandler = new ServiceHandler(mServiceLooper);
          }
    
          @Override
          public int onStartCommand(Intent intent, int flags, int startId) {
              Toast.makeText(this, "service starting", Toast.LENGTH_SHORT).show();
    
              // For each start request, send a message to start a job and deliver the
              // start ID so we know which request we're stopping when we finish the job
              Message msg = mServiceHandler.obtainMessage();
              msg.arg1 = startId;
              mServiceHandler.sendMessage(msg);
    
              // If we get killed, after returning from here, restart
              return START_STICKY;
          }
    
          @Override
          public IBinder onBind(Intent intent) {
              // We don't provide binding, so return null
              return null;
          }
    
          @Override
          public void onDestroy() {
            Toast.makeText(this, "service done", Toast.LENGTH_SHORT).show();
          }
        }
    

    我建议使用intentservice,因为它很简单,非常适合您的场景。

答案 4 :(得分:0)

导致此错误的原因

调用

startActivity而不是startService

我怎么能(将来)调试这个,因为控制台相对模糊

这是一个有趣的部分,消息后面应该是一个完整的堆栈跟踪,它是明确描述错误的。像这样:

02-10 12:26:52.734: E/AndroidRuntime(16214): FATAL EXCEPTION: main
02-10 12:26:52.734: E/AndroidRuntime(16214): Process: com.example.sandbox, PID: 16214
02-10 12:26:52.734: E/AndroidRuntime(16214): java.lang.IllegalStateException: Could not execute method for android:onClick
02-10 12:26:52.734: E/AndroidRuntime(16214):    at android.view.View$DeclaredOnClickListener.onClick(View.java:4458)
02-10 12:26:52.734: E/AndroidRuntime(16214):    at android.view.View.performClick(View.java:5204)
02-10 12:26:52.734: E/AndroidRuntime(16214):    at android.view.View$PerformClick.run(View.java:21153)
02-10 12:26:52.734: E/AndroidRuntime(16214):    at android.os.Handler.handleCallback(Handler.java:739)
02-10 12:26:52.734: E/AndroidRuntime(16214):    at android.os.Handler.dispatchMessage(Handler.java:95)
02-10 12:26:52.734: E/AndroidRuntime(16214):    at android.os.Looper.loop(Looper.java:148)
02-10 12:26:52.734: E/AndroidRuntime(16214):    at android.app.ActivityThread.main(ActivityThread.java:5417)
02-10 12:26:52.734: E/AndroidRuntime(16214):    at java.lang.reflect.Method.invoke(Native Method)
02-10 12:26:52.734: E/AndroidRuntime(16214):    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726)
02-10 12:26:52.734: E/AndroidRuntime(16214):    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)
02-10 12:26:52.734: E/AndroidRuntime(16214): Caused by: java.lang.reflect.InvocationTargetException
02-10 12:26:52.734: E/AndroidRuntime(16214):    at java.lang.reflect.Method.invoke(Native Method)
02-10 12:26:52.734: E/AndroidRuntime(16214):    at android.view.View$DeclaredOnClickListener.onClick(View.java:4453)
02-10 12:26:52.734: E/AndroidRuntime(16214):    ... 9 more
02-10 12:26:52.734: E/AndroidRuntime(16214): Caused by: android.content.ActivityNotFoundException: Unable to find explicit activity class {com.example.sandbox/com.example.sandbox.BackgroundService}; have you declared this activity in your AndroidManifest.xml?
02-10 12:26:52.734: E/AndroidRuntime(16214):    at android.app.Instrumentation.checkStartActivityResult(Instrumentation.java:1794)
02-10 12:26:52.734: E/AndroidRuntime(16214):    at android.app.Instrumentation.execStartActivity(Instrumentation.java:1512)
02-10 12:26:52.734: E/AndroidRuntime(16214):    at android.app.Activity.startActivityForResult(Activity.java:3930)
02-10 12:26:52.734: E/AndroidRuntime(16214):    at android.app.Activity.startActivityForResult(Activity.java:3890)
02-10 12:26:52.734: E/AndroidRuntime(16214):    at android.app.Activity.startActivity(Activity.java:4213)
02-10 12:26:52.734: E/AndroidRuntime(16214):    at android.app.Activity.startActivity(Activity.java:4181)
02-10 12:26:52.734: E/AndroidRuntime(16214):    at com.example.sandbox.MainActivity.start_clicked(MainActivity.java:19)
02-10 12:26:52.734: E/AndroidRuntime(16214):    ... 11 more

部分Unable to find explicit activity class com.example.sandbox/com.example.sandbox.BackgroundService}; have you declared this activity in your AndroidManifest.xml?非常清晰,只需阅读即可轻松解决问题。