サービスから送信されたデータを表示するために使用したいアクティビティがあります。アクティビティは、サービスがアクティビティにメッセージを送信するたびにテキストビューを更新します。ユーザーは、アクティビティのボタンを使用してサービスを開始および停止できます(サービスはユーザーによって明示的に開始/停止されます)。現時点では、私のアクティビティはonResume()でサービスにバインドされ、現在機能しているように見えるonDestroy()でバインドが解除されます。
この問題は、サービスを開始し、戻るボタンを押してから、アクティビティに再度焦点を合わせようとすると発生します。サービスによって更新されていない新しいアクティビティに直面していますが、サービスにメッセージを送信できるようです(ハンドラーのログからこれに気づきました[そのフレーズは私を笑わせました!])。理想的には、アクティビティのインスタンスを1つだけ存在させ、サービスにバインドしたままにしておきたいのですが、アクティビティが更新に追いついていないことを絶対に見たくありません。マニフェストを更新しました<activity android:launchMode="singleTop">
、しかしそれが問題に大いに役立つかどうかはわかりません。後で再開したときに、アクティビティがサービスの既存のインスタンスに再バインドされるようにするにはどうすればよいですか?(私はメッセージパッシングでこれを達成したいのですが、データベースを実装したり、このビットにsharedpreferecesを使用したりしたくありません)。私は以下に私のコードを含めています-私はサービスに比較的慣れていないので、私に気楽に行ってください。乾杯。
オプションの追加:startService()から継続的に実行されるサービスを目指しており、アクティビティの再フォーカスはオプションですが、サービスからの最新情報がすぐに表示されます。私が探しているのはフォアグラウンドサービスだと思います。これは質問の一部ではありませんが、あなたの答えが私がこれを達成するのを妨げるかもしれないと思うならば、私に知らせてください。
MainActivity.java:
public class MainActivity extends Activity
{
private static final String debug = "MainActivity";
private boolean bound = false;
TextView mTextView;
protected Messenger outMessenger;
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Log.i(debug, "onCreate called");
mTextView = (TextView) findViewById(R.id.textView1);
Button bind = (Button) findViewById(R.id.bind);
Button unbind = (Button) findViewById(R.id.unbind);
bind.setOnClickListener(new OnClickListener()
{
public void onClick(View v)
{
Message message = new Message();
Bundle bundle = new Bundle();
bundle.putString("ACTION", "START");
message.setData(bundle);
try
{
outMessenger.send(message);
} catch (RemoteException e)
{
Log.d(debug, "She can't reach the service captain!");
}
}
});
unbind.setOnClickListener(new OnClickListener()
{
public void onClick(View v)
{
Message message = new Message();
Bundle bundle = new Bundle();
bundle.putString("ACTION", "STOP");
message.setData(bundle);
try
{
outMessenger.send(message);
} catch (RemoteException e)
{
Log.d(debug, "She can't reach the service captain!");
}
}
});
}
@Override
public void onPause()
{
super.onPause();
}
@Override
public void onResume()
{
super.onResume();
doBindService();
}
public void onDestroy()
{
super.onDestroy();
Log.i(debug, "onDestroy Called");
doUnbindService();
}
private void doBindService()
{
Log.i(debug, "Attempting to bind");
bound = true;
Intent i = new Intent(this, MyService.class);
i.putExtra("MESSENGER", new Messenger(mHandler));
bindService(i, mConnection, Context.BIND_AUTO_CREATE);
}
private void doUnbindService()
{
Log.i(debug, "Attempting to unbind");
if (bound)
{
bound = false;
unbindService(mConnection);
}
}
private Handler mHandler = new Handler()
{
public void handleMessage(Message message)
{
Log.d(debug, "Got a message!");
Bundle data = message.getData();
if (data != null)
{
Log.i(debug, "This data ain't null!");
if (data.containsKey("MESSAGE"))
{
mTextView.setText(data.getString("MESSAGE"));
}
}
}
};
private ServiceConnection mConnection = new ServiceConnection()
{
public void onServiceConnected(ComponentName className, IBinder binder)
{
Log.i(debug, "Service connected!");
outMessenger = new Messenger(binder);
}
@Override
public void onServiceDisconnected(ComponentName className)
{
Log.d(debug, "Service Disconnected!");
}
};
}
MyService.java
public class MyService extends Service
{
private static final String debug = "MyService";
private Messenger inMessenger = new Messenger(new IncomingHandler());
Messenger outMessenger;
private boolean bound = false;
int secret = 0;
@Override
public void onCreate()
{
Log.d(debug , "MyService Created");
}
@Override
public int onStartCommand(Intent intent, int flags, int startId)
{
Log.d(debug , "onStartCommand called");
handleCommand(intent);
return START_STICKY;
}
Handler handler = new Handler();
public boolean running;
void handleCommand(Intent i)
{
Runnable r = new Runnable()
{
public void run()
{
updateResultsInUi();
if (running)
{
handler.postDelayed(this, 500);
}
}
};
r.run();
}
void updateResultsInUi()
{
Bundle bundle = new Bundle();
bundle.putString("MESSAGE",
Integer.toString(secret = ++secret % 10));
Message message = new Message();
message.setData(bundle);
if (bound)
{
try
{
outMessenger.send(message);
}
catch (RemoteException e)
{
Log.d(debug, "Messaging failed");
}
}
else
{
Log.d(debug, "Not connected, so not messaging!");
}
}
@Override
public IBinder onBind(Intent intent)
{
Log.i(debug, "Bound");
bound = true;
Bundle extras = intent.getExtras();
outMessenger = (Messenger) extras.get("MESSENGER");
return inMessenger.getBinder();
}
@Override
public void onRebind(Intent i)
{
bound = true;
Bundle extras = i.getExtras();
outMessenger = (Messenger) extras.get("MESSENGER");
}
@Override
public boolean onUnbind(Intent i)
{
Log.d(debug, "onUnbind() called.");
bound = false;
outMessenger = null;
return true;
}
class IncomingHandler extends Handler
{
@Override
public void handleMessage(Message msg)
{
Log.d(debug, "Got message");
Bundle data = msg.getData();
if (data.containsKey("ACTION"))
{
if ("START".equals(data.getString("ACTION")))
{
if (!running)
{
running = true;
Intent i = new Intent(getApplicationContext(), MyService.class);
startService(i);
}
else
{
Log.d(debug, "We're already up and running!");
}
}
else if ("STOP".equals(data.getString("ACTION")))
{
running = false;
Intent i = new Intent(getApplicationContext(), MyService.class);
stopService(i);
}
}
}
}
}
AndroidManifest.xml
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.tests.servicetest"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="8"
android:targetSdkVersion="15" />
<application
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name="com.tests.servicetest.MainActivity"
android:label="@string/title_activity_main"
android:launchMode="singleTop" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service
android:name="com.tests.servicetest.MyService"
android:process=":inaneService">
</service>
</application>
</manifest>
そしてそれを実行したい人のために、activity_main.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" >
<TextView
android:id="@+id/textView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:padding="@dimen/padding_medium"
android:text="@string/hello_world"
tools:context=".MainActivity" />
<Button
android:id="@+id/bind"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignLeft="@+id/textView1"
android:layout_below="@+id/textView1"
android:text="Start" />
<Button
android:id="@+id/unbind"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignLeft="@+id/textView1"
android:layout_below="@+id/bind"
android:text="Stop" />
</RelativeLayout>