我正在尝试使用只需按下按钮即可启动后台服务的应用。然后,后台应用程序应使用套接字打开到服务器的连接,然后发送一些虚拟数据。完成后,服务应该死了。
当我点击按钮并且整个应用程序停止时,我正在获得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
答案 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)
此代码中存在两个问题。
要启动应该在后台运行的服务,您需要启动服务,因此您需要调用startservice():
Intent my_intent = new Intent(this,BackgroundService.class); startService(my_intent);
第二大问题是您创建服务的方式。默认情况下,它将在UI线程上启动。因此,在这种情况下,您应该在单独的线程上使用IntentService或服务。
意图服务:
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?
非常清晰,只需阅读即可轻松解决问题。