我试图了解android服务的工作原理。
所以我创建了一个包含活动和服务的简单应用程序,有代码:
MainActivity.xml:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
android:paddingBottom="@dimen/activity_vertical_margin"
tools:context=".MainActivity">
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Start Service"
android:id="@+id/buttonStart"
android:layout_marginTop="60dp"
android:layout_alignParentTop="true"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_alignParentRight="true"
android:layout_alignParentEnd="true"
android:onClick="startButtonClickHandler"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Stop Service"
android:id="@+id/buttonStop"
android:layout_below="@+id/buttonStart"
android:layout_alignParentRight="true"
android:layout_alignParentEnd="true"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:enabled="false"
android:onClick="stopButtonClickHandler" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceLarge"
android:id="@+id/textView"
android:layout_centerVertical="true"
android:layout_centerHorizontal="true"
android:text="Counter is: 0" />
</RelativeLayout>
MainActivity.java:
package com.example.wellsaid.provaservice;
import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.IntentFilter;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.content.Intent;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;
import org.w3c.dom.Text;
public class MainActivity extends Activity {
Button btn_stop = null;
Button btn_start = null;
/*---------------------------- CODICE NUOVO -----------------------------*/
private class MyReceiver extends BroadcastReceiver{
@Override
public void onReceive(Context arg0, Intent arg1) {
int datapassed = arg1.getIntExtra("count", 0);
TextView text = (TextView) findViewById(R.id.textView);
text.setText("Counter is: " + datapassed);
}
}
MyReceiver myreceiver = null;
/*---------------------------------------------------------------------*/
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btn_stop = (Button) findViewById(R.id.buttonStop);
btn_start = (Button) findViewById(R.id.buttonStart);
if(ExampleService.isRunning()){
btn_stop.setEnabled(true);
btn_start.setText("Send request");
Intent intent = new Intent(this, ExampleService.class);
intent.putExtra("count",0);
startService(intent);
}
/*--------------------- CODICE NUOVO -------------------------------*/
myreceiver = new MyReceiver();
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(ExampleService.RETURN_COUNTER);
registerReceiver(myreceiver, intentFilter);
/*------------------------------------------------------------------*/
}
public void startButtonClickHandler(View v){
if(!btn_stop.isEnabled()) {
btn_stop.setEnabled(true);
btn_start.setText("Send request");
}
Intent intent = new Intent(this, ExampleService.class);
intent.putExtra("count",0);
startService(intent);
}
public void stopButtonClickHandler(View v){
Intent intent = new Intent(this, ExampleService.class);
stopService(intent);
btn_start.setText("Start Service");
btn_stop.setEnabled(false);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
return super.onOptionsItemSelected(item);
}
@Override
protected void onStop() {
// TODO Auto-generated method stub
unregisterReceiver(myreceiver);
super.onStop();
}
}
ExampleService.java
package com.example.wellsaid.provaservice;
import android.app.Activity;
import android.app.AlarmManager;
import android.app.Notification;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.os.IBinder;
import android.os.SystemClock;
import android.util.Log;
public class ExampleService extends Service {
/*--------------------- CODICE NUOVO-------------------------------*/
final static String RETURN_COUNTER = "RETURN_COUNTER";
/*----------------------------------------------------------------*/
@Override
public void onTaskRemoved(Intent rootIntent) {
super.onTaskRemoved(rootIntent);
Intent intent = new Intent(this, ExampleService.class);
intent.putExtra("count",thread.getCounter());
startService(intent);
}
@Override
public IBinder onBind(Intent intent) {
return null;
}
ExampleThread thread = null;
private static boolean running = false;
public static boolean isRunning() { return running; }
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
running = true;
if(thread == null) {
int counter = intent.getExtras().getInt("count");
thread = new ExampleThread(counter);
thread.start();
}
else{
/*-----------------------CODICE NUOVO ----------------------*/
Intent send = new Intent();
send.setAction(RETURN_COUNTER);
send.putExtra("count",thread.getCounter());
sendBroadcast(send);
/*----------------------------------------------------------*/
}
return startId;
}
@Override
public void onDestroy() {
running = false;
thread.kill();
super.onDestroy();
}
private class ExampleThread extends Thread {
boolean stopped;
int counter = 0;
public ExampleThread(int counter){
this.counter = counter;
}
public void start(){
stopped = false;
super.start();
}
public int getCounter(){ return counter; }
public void kill(){
stopped = true;
}
public void run(){
while(!stopped) {
try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); }
counter++;
Log.i("Service", "Counter is: " + counter);
}
}
}
}
这就是我的表现:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.wellsaid.provaservice" >
<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name=".MainActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service android:name=".ExampleService" />
</application>
</manifest>
我尝试过:1)打开应用程序,使用启动按钮启动服务,然后用另一个停止它。一切OK 2)打开应用程序,启动服务并关闭应用程序。一切OK(服务仍在运行)3)打开应用程序,启动服务,重新打开应用程序并获取计数器值。一切OK 4)打开应用程序,启动服务,关闭应用程序,重新打开应用程序并停止服务。一切OK(关闭后也重启服务) 当我打开,启动服务,关闭应用程序,重新打开以检查计数器编号然后再次关闭应用程序时出现问题,一段时间后服务停止,logcat中没有消息:( 在应用程序管理的我的Android设备上,我可以看到我的应用程序处于重新启动状态,经过很长时间后,它会重新启动,然后再次停止,打开等等.... 我已经在三星Galaxy express stock(android 4.1.2)和三星galaxy tab 2 10.1上测试了cyanogenmod 10.1.3(android 4.2.2)
答案 0 :(得分:0)
您是否通读了https://developer.android.com/reference/android/app/Service.html?
请注意以下事项:
对于已启动的服务,还有两种主要模式 根据他们的价值,他们可以决定参加比赛 从onStartCommand()返回:START_STICKY用于那些服务 根据需要显式启动和停止,同时START_NOT_STICKY 或START_REDELIVER_INTENT仅用于服务 在处理发送给他们的任何命令时保持运行。
来自START_STICKY
文档:
从onStartCommand(Intent,int,int)返回的常量:如果是这样 服务的进程在启动时被终止(在返回之后) onStartCommand(Intent,int,int)),然后将其保持在启动状态 但不要保留这个意图。稍后系统会尝试 重新创建服务。因为它处于启动状态,它会 保证在创建后调用onStartCommand(Intent,int,int) 新服务实例;如果没有任何挂起的启动命令 如果被传递给服务,它将被调用null意图 对象,所以你必须注意检查这个。
此模式适用于将明确启动的内容 停止运行任意时间段,例如服务 表演背景音乐播放。