I have an app to receive data through bluetooth. The idea is that I have a bluetooth service running in the background, it is bound to the main activity. The service is created when a button is pressed on a fragment (I bind the service to the activity because I want to keep the bluetooth connection even fragment has been damaged.)
For this, When button in the fragment is pressed, I'm passing the handler from the fragment to the activity, the handler will then be passed to the service, so that I could update the fragment UI based on the received data.
However, I got non-static method cannot be reference from a static context for the getBTService method .I could not solve it as I cannot make the bindService static. Could anyone advice? Or is there a better way to manage this? Here is the relevant code:
Main Activity:
public void getBTService(Handler btHandler){
this.mHandler = btHandler;
Intent intent = new Intent(this, BluetoothService.class);
bindService(intent, connection, Context.BIND_AUTO_CREATE);
}
#Override
protected void onStop() {
super.onStop();
if (btService != null) {
unbindService(connection);
btBound = false;
}
}
private ServiceConnection connection = new ServiceConnection() {
#Override
public void onServiceConnected(ComponentName className,
IBinder service) {
BluetoothService.LocalBinder binder = (BluetoothService.LocalBinder) service;
btService = binder.getService(mHandler);
btBound = true;
}
#Override
public void onServiceDisconnected(ComponentName arg0) {
btBound = false;
}
};
Fragment:
public View onCreateView(#NonNull LayoutInflater inflater,
ViewGroup container, Bundle savedInstanceState) {
View root = inflater.inflate(R.layout.fragment_signal, container, false);
statusTV = root.findViewById(R.id.text_status);
dataTV = root.findViewById(R.id.text_data);\
openBtn = root.findViewById(R.id.openBtn);
mChart = root.findViewById(R.id.chart);
openBtn.setOnClickListener(new View.OnClickListener(){
#Override
public void onClick(View v) {
MainActivity.getBTService(mHandler);
}
}
);
return root;
}
private final Handler mHandler = new Handler(){
#Override
public void handleMessage(#NonNull Message msg) {
switch ((msg.what)){
case MainActivity.MessageConstants.MESSAGE_READ:
String data = (String) msg.obj;
updateTV("data", data);
}
}
};
You can try this instead of call directly by MainActivity
openBtn.setOnClickListener(new View.OnClickListener(){
#Override
public void onClick(View v) {
((MainActivity) requireActivity()).getBTService(mHandler);
}
}
Related
I am writing code for a music player and everything seems to be working fine except the ActionBar. When a song is playing, a thread probes the service every second for a change in the song and if there is a change in the song, a handler object changes the UI elements.
final Handler uiHandler = new Handler() {
#Override
public void handleMessage(Message msg) {
Bundle data = msg.getData();
song = data.getParcelable("song_info");
songText.setText(song.getSongTitle());
artistText.setText(song.getSongArtist());
seekBar.setMax(mService.getDuration()/1000); //All these work
assert getSupportActionBar() != null;
getSupportActionBar().setTitle(mService.getSongName()); //Not updating
super.handleMessage(msg);
}
};
What this does is when there is a message from the thread, it updates the UI. I can confirm that this works and is invoked when I need it to. All the text views and the seekbar get updated as required. However, the getSupportActionBar().setTitle(...) doesn't update the title bar.
The same method of setting action bar title works if I do it in other methods of the same class. Am I missing something here?
Thanks in advance!
Update:
Here's some more code that the Activity has, in case it helps strike something.
private ServiceConnection mConnection = new ServiceConnection() {
#Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
MusicService.MusicBinder mBinder = (MusicService.MusicBinder)iBinder;
mService = mBinder.getService();
pauseBtn = (ImageButton)findViewById(R.id.pause);
seekBar.setMax(mService.getDuration()/1000);
CounterThread cThread = new CounterThread();
Thread counter = new Thread(cThread);
counter.start();
if(mService.isPaused()) {
pauseBtn.setImageResource(R.drawable.ic_play_arrow_white_36dp);
}
else {
pauseBtn.setImageResource(R.drawable.ic_pause_white_36dp);
}
}
#Override
public void onServiceDisconnected(ComponentName componentName) {
}
};
private class CounterThread implements Runnable {
#Override
public void run() {
while(true) {
try {
if(!mService.getSongName().equals(song.getSongTitle())) //This is invoked when there is a change in the song.{
Message msg = uiHandler.obtainMessage();
Bundle b = new Bundle();
b.putParcelable("song_info", mService.getSong());
msg.setData(b); //I receive this message in the handler
uiHandler.sendMessage(msg);
}
seekBar.setProgress(mService.getCurrPosn()/1000);
Thread.sleep(1000);
} catch (Exception e){
e.printStackTrace();
}
}
}
}
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.song_playing);
song = getIntent().getParcelableExtra("song_info");
songText = (TextView) findViewById(R.id.songname);
artistText = (TextView) findViewById(R.id.artistname);
songText.setText(song.getSongTitle());
artistText.setText(song.getSongArtist());
header = getSupportActionBar();
seekBar = (SeekBar)findViewById(R.id.seekBar);
seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
#Override
public void onProgressChanged(SeekBar seekBar, int i, boolean b) {
// Do nothing
}
#Override
public void onStartTrackingTouch(SeekBar seekBar) {
// Do nothing
}
#Override
public void onStopTrackingTouch(SeekBar seekBar) {
int progress = seekBar.getProgress();
mService.seek(progress*1000);
}
});
assert header != null;
header.setDisplayOptions(ActionBar.DISPLAY_SHOW_CUSTOM);
header.setCustomView(R.layout.head_layout);
titleText = (TextView) findViewById(R.id.titleText);
titleText.setText(song.getSongTitle());
}
/*
More operations
*/
public void next(View v) {
mService.nextSong();
pauseBtn.setImageResource(R.drawable.ic_pause_white_36dp);
assert header != null;
header.setTitle(mService.getSongName()); // This works fine
songText.setText(mService.getSongName());
artistText.setText(mService.getArtistName());
titleText.setText(mService.getSongName());
seekBar.setMax(mService.getDuration()/1000);
}
Don't mind the slight indentation offset.
This question already has answers here:
Call Activity method from adapter
(9 answers)
Closed 8 years ago.
I have a textview in a listview on clicking which it should perform some activity. Currently,I am writing onClick of textview inside getView method of custom adapter class. On click of textview , I am trigerring a method in my Activity class . But that Activity has that variable value as NULL eventhough its already been initialised in onCreate of Activity. Here's my code:
Adapter class:
#Override
public View getView(int position, View convertView, ViewGroup parent) {
final int pos = position;
Item item = (Item) getItem(position);
TextView textView = (TextView) view
.findViewById(R.id.tv_song_title);
textView.setText(item.text);
textView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
MainActivity main = new MainActivity();
main.songPicked(pos); //calling act class method
}
});
Activity class:
private MusicService musicSrv;
public void songPicked(int position) { //method called
if (musicSrv!=null) //is null .Why??
{
musicSrv.setSong(position);
songName = musicSrv.playSong();
}
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
songAdt = new SongAdapter();
songAdt.setRows(rows);
songView.setAdapter(songAdt);
playMusic();
}
public void playMusic() {
if (playIntent == null) {
playIntent = new Intent(this, MusicService.class);
startService(playIntent);
bindService(playIntent, musicConnection, Context.BIND_AUTO_CREATE);
}
}
// connect to the service
private ServiceConnection musicConnection = new ServiceConnection() {
#Override
public void onServiceConnected(ComponentName name, IBinder service) {
MusicBinder binder = (MusicBinder) service;
// get service
musicSrv = binder.getService();
// pass list
musicSrv.setList(songList);
musicBound = true;
Log.i("LEAKTEST", "Connected to instance " + this.toString());
}
#Override
public void onServiceDisconnected(ComponentName name) {
musicBound = false;
musicSrv = null;
}
Use listeners instead of passing the whole activity.
The main idea is
public interface SmthListener() {
void onSmthHappens(smthParams);
}
public class WhoNotify {
SmthListener mListener;
public WhoNotify(SmthListener listener) {
mListener = listener;
}
public void smthHappensInMyClass() {
mListener.onSmthHappens(smthParams);
}
}
public class WhoListene implements SmthListener {
#Override
public void onCreate(...) {
... new WhoNotify(this);
}
#Override
void onSmthHappens(smthParams) {
// do stuff;
}
}
I have a trouble with getting Activity(Nullpointerexception) after that I have rotate screen and received callback from AsyncTask to update my views of the fragment. If I wont change orientation then everything is OK(but not all the time, sometimes this bug appears)
My main activity:
public class MainActivity extends SherlockFragmentActivity {
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.pager_layout);
fm = getSupportFragmentManager();
fm.addOnBackStackChangedListener(this);
session = new SessionManager(getApplicationContext());
if (session.isAuthorizated()) {
disableTabs();
FragmentTransaction ft = fm.beginTransaction();
if (session.termsAndConditions()) {
ft.replace(android.R.id.content, new TermsAndConditionsFragment(), "terms-and-conditions").commit();
}
}
} else {
enableTabs();
mTabsAdapter = new TabsAdapter(this, mViewPager);
mTabsAdapter.addTab(actionBar.newTab().setText("Log in"), LoginFragment.class, null);
mTabsAdapter.addTab(actionBar.newTab().setText("Calculator"), CalculatorFragment.class, null);
}
}
That`s my fragment:
public class TermsAndConditionsFragment extends SherlockFragment implements OnClickListener, OnTouchListener, OnEditorActionListener, ValueSelectedListener, AsyncUpdateViewsListener {
private static final String TAG = "TermsAndConditionsFragment";
private TermsAndConditionsManager termsAndConditionsM;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
prepareData();
}
public void prepareData() {
if (getSherlockActivity() == null)
Log.d(TAG, "Activity is null");
termsAndConditionsM = new TermsAndConditionsManager(getSherlockActivity().getApplicationContext());
termsAndConditions = termsAndConditionsM.getTermsAndConditions();
...
// some stuff
...
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
rootView = init(inflater, container);
return rootView;
}
private View init(LayoutInflater inflater, ViewGroup container) {
rootView = inflater.inflate(R.layout.fragment_terms_and_conditions, container, false);
//bla bla bla
return rootView;
}
public void updateTermsAndConditionsView() {
//update views here
}
#Override
public void onClick(View v) {
ft = fm.beginTransaction();
switch (v.getId()) {
case R.id.etHowMuch:
d = NumberPaymentsPickerFragment.newInstance(getSherlockActivity(), Integer.valueOf(howMuch.replace("£", "")), 0);
d.setValueSelectedListener(this);
d.show(getFragmentManager(), Const.HOW_MUCH);
break;
}
}
#Override
public void onValueSelected() {
Bundle args = new Bundle();
...
ExecuteServerTaskBackground task = new ExecuteServerTaskBackground(getSherlockActivity());
task.setAsyncUpdateViewsListener(this);
task.action = ServerAPI.GET_TERMS_AND_CONDITIONS;
task.args = args;
task.execute();
}
#Override
public void onUpdateViews() {
prepareData();
updateTermsAndConditionsView();
}
}
My AsyncTask with callback:
public class ExecuteServerTaskBackground extends AsyncTask<Void, Void, Void> {
private static final String TAG = "ExecuteServerTaskBackground";
Activity mActivity;
Context mContext;
private AsyncUpdateViewsListener callback;
public ExecuteServerTaskBackground(Activity activity) {
this.mActivity = activity;
this.mContext = activity.getApplicationContext();
}
public void setAsyncUpdateViewsListener(AsyncUpdateViewsListener listener) {
callback = listener;
}
#Override
protected Void doInBackground(Void... params) {
ServerAPI server = new ServerAPI(mContext);
if (!args.isEmpty())
msg = server.serverRequest(action, args);
else
msg = server.serverRequest(action, null);
return null;
}
#Override
protected void onPostExecute(Void result) {
super.onPostExecute(result);
callback.onUpdateViews();
}
}
Why does it behave so? How can I get activity correctly if I change orientation.
EDIT:
As I understand correctly nullpointer appears after orientation changed and asynctask executed due to wrong reference between asyctask and Activity. Recreated activity doesnt have this reference thats why when I receive callback I use wrong activity reference which isn`t exist anymore. But how can I save current activity reference?
EDIT:
I have decided to try realize my task throughout Service and that`s what I have done.
Activity:
public class MainFragment extends Fragment implements ServiceExecutorListener, OnClickListener {
private static final String TAG = MainFragment.class.getName();
Button btnSend, btnCheck;
TextView serviceStatus;
Intent intent;
Boolean bound = false;
ServiceConnection sConn;
RESTService service;
ProgressDialog pd = new ProgressDialog();
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
setRetainInstance(true);
intent = new Intent(getActivity(), RESTService.class);
getActivity().startService(intent);
sConn = new ServiceConnection() {
#Override
public void onServiceConnected(ComponentName name, IBinder binder) {
Log.d(TAG, "MainFragment onServiceConnected");
service = ((RESTService.MyBinder) binder).getService();
service.registerListener(MainFragment.this);
if (service.taskIsDone())
serviceStatus.setText(service.getResult());
bound = true;
}
public void onServiceDisconnected(ComponentName name) {
Log.d(TAG, "MainFragment onServiceDisconnected");
bound = false;
}
};
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.main_fragment, container, false);
serviceStatus = (TextView) rootView.findViewById(R.id.tvServiceStatusValue);
btnSend = (Button) rootView.findViewById(R.id.btnSend);
btnCheck = (Button) rootView.findViewById(R.id.btnCheck);
btnSend.setOnClickListener(this);
btnCheck.setOnClickListener(this);
return rootView;
}
#Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.btnSend:
pd.show(getFragmentManager(), "ProgressDialog");
service.run(7);
service.run(2);
service.run(4);
break;
case R.id.btnCheck:
if (service != null)
serviceStatus.setText(String.valueOf(service.taskIsDone()) + service.getTasksCount());
break;
}
}
#Override
public void onStart() {
super.onStart();
Log.d(TAG, "Bind service");
getActivity().bindService(intent, sConn, 0);
}
#Override
public void onPause() {
super.onDestroy();
Log.d(TAG, "onDestroy: Unbind service");
if (!bound)
return;
getActivity().unbindService(sConn);
service.unregisterListener(this);
bound = false;
}
#Override
public void onComplete(String result) {
Log.d(TAG, "Task Completed");
pd.dismiss();
serviceStatus.setText(result);
}
}
Dialog:
public class ProgressDialog extends DialogFragment implements OnClickListener {
final String TAG = ProgressDialog.class.getName();
public Dialog onCreateDialog(Bundle savedInstanceState) {
setRetainInstance(true);
AlertDialog.Builder adb = new AlertDialog.Builder(getActivity())
.setTitle("Title!")
.setPositiveButton(R.string.yes, this)
.setNegativeButton(R.string.no, this)
.setNeutralButton(R.string.maybe, this)
.setCancelable(false)
.setMessage(R.string.message_text)
.setOnKeyListener(new OnKeyListener() {
#Override
public boolean onKey(DialogInterface dialog, int keyCode, KeyEvent event) {
return true;
}
});
return adb.create();
}
public void onClick(DialogInterface dialog, int which) {
int i = 0;
switch (which) {
case Dialog.BUTTON_POSITIVE:
i = R.string.yes;
break;
case Dialog.BUTTON_NEGATIVE:
i = R.string.no;
break;
case Dialog.BUTTON_NEUTRAL:
i = R.string.maybe;
break;
}
if (i > 0)
Log.d(TAG, "Dialog 2: " + getResources().getString(i));
}
public void onDismiss(DialogInterface dialog) {
Log.d(TAG, "Dialog 2: onDismiss");
// Fix to avoid simple dialog dismiss in orientation change
if ((getDialog() != null) && getRetainInstance())
getDialog().setDismissMessage(null);
super.onDestroyView();
}
public void onCancel(DialogInterface dialog) {
super.onCancel(dialog);
Log.d(TAG, "Dialog 2: onCancel");
}
}
Service:
public class RESTService extends Service {
final String TAG = RESTService.class.getName();
MyBinder binder = new MyBinder();
ArrayList<ServiceExecutorListener> listeners = new ArrayList<ServiceExecutorListener>();
Handler h = new Handler();
RequestManager mRequest;
ExecutorService es;
Object obj;
int time;
StringBuilder builder;
String result = null;
public void onCreate() {
super.onCreate();
Log.d(TAG, "RESTService onCreate");
es = Executors.newFixedThreadPool(1);
obj = new Object();
builder = new StringBuilder();
}
public void run(int time) {
RunRequest rr = new RunRequest(time);
es.execute(rr);
}
class RunRequest implements Runnable {
int time;
public RunRequest(int time) {
this.time = time;
Log.d(TAG, "RunRequest create");
}
public void run() {
Log.d(TAG, "RunRequest start, time = " + time);
try {
TimeUnit.SECONDS.sleep(time);
} catch (InterruptedException e) {
e.printStackTrace();
}
try {
Log.d(TAG, "RunRequest obj = " + obj.getClass());
} catch (NullPointerException e) {
Log.d(TAG, "RunRequest error, null pointer");
}
builder.append("result " + time + ", ");
result = builder.toString();
sendCallback();
}
}
private void sendCallback() {
h.post(new Runnable() {
#Override
public void run() {
for (ServiceExecutorListener listener : listeners)
listener.onComplete();
}
});
}
public boolean taskIsDone() {
if (result != null)
return true;
return false;
}
public String getResult() {
return result;
}
public void registerListener(ServiceExecutorListener listener) {
listeners.add(listener);
}
public void unregisterListener(ServiceExecutorListener listener) {
listeners.remove(listener);
}
public IBinder onBind(Intent intent) {
Log.d(TAG, "RESTService onBind");
return binder;
}
public boolean onUnbind(Intent intent) {
Log.d(TAG, "RESTService onUnbind");
return true;
}
public class MyBinder extends Binder {
public RESTService getService() {
return RESTService.this;
}
}
}
As you mention in your edit, the current Activity is destroyed and recreated on orientation change.
But how can I save current activity reference?
You shouldn't. The previous Activity is no longer valid. This will not only cause NPEs but also memory leaks because the AsyncTask might hold the reference to old Activity, maybe forever.
Solution is to use Loaders.
I added a listener to the service called "BindService".
And then I killed the Activity which have added the listener to the "BindService".
"BindService" is still running. I can see it on DDMS of eclipse.
Now I started the Activity again and I want to add a listener to the "BindService" again.
How could I?
"BindService" is just a service which is counting number.
With the following code, after I start the Activity again and tap the button "button_sendwords", it starts to count number from 0 again. That is not my purpose.
public class MainActivity extends Activity {
private ICallbackService service;
private static final int CALLBACK_MESSAGE = 1;
private Handler handler = new Handler(){
#Override
public void dispatchMessage(Message msg){
if(msg.what == CALLBACK_MESSAGE){
TextView resultlbl = (TextView)findViewById(R.id.label_result);
resultlbl.setText((String)msg.obj);
}else{
super.dispatchMessage(msg);
}
}
};
private ICallbackListener listener = new ICallbackListener.Stub() {
#Override
public void receiveMessage(String message) throws RemoteException {
handler.sendMessage(handler.obtainMessage(CALLBACK_MESSAGE, message));
}
};
private ServiceConnection conn = new ServiceConnection(){
#Override
public void onServiceConnected(ComponentName name, IBinder binder) {
service = ICallbackService.Stub.asInterface(binder);
try{
service.addListener(listener);
}catch(RemoteException e){
}
}
#Override
public void onServiceDisconnected(ComponentName name) {
}
};
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button btnSendWords = (Button)findViewById(R.id.button_sendwords);
btnSendWords.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent intent = new Intent(MainActivity.this, BindService.class);
bindService(intent, conn, BIND_AUTO_CREATE);
}
});
}
}
I am doing some investigations with the GoogleTV and a Android tablet. I have managed to make an android application that can send control messages to the google tv from the main Activity, what I am trying to do is launch a new activity from the main Activity and continue using the AnymoteClientService Service with the new activity. In my main activity I get an anymoteSender handle which I use to send KeyEvent messages to the google tv, how do I transfer this to the new activity (SlidepuzzleActivity)? I could instantiate it all again, but that would mean having to go through the whole pairing process again.
From the code below you will see that I have an anymoteSender in my SlidepuzzleActivity class, this will throw an error, but illustrates where I need to reuse that variable.
Code:
MainActivity.java:
package uk.co.myapp.gtvremote;
//imports removed for paste
public class MainActivity extends Activity implements ClientListener{
private AnymoteSender anymoteSender;
private TextView statusText;
protected AnymoteClientService mAnymoteClientService;
private static String statusPrefix = "Status: ";
private Context mContext;
private ProgressBar progressBar;
private Handler handler;
private TouchHandler touchPadHandler;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
progressBar = (ProgressBar) findViewById(R.id.a_progressbar);
progressBar.setVisibility(View.VISIBLE);
mContext = this;
ImageButton upArrowButton = (ImageButton) findViewById(R.id.upArrow);
ImageButton leftArrowButton = (ImageButton) findViewById(R.id.leftArrow);
ImageButton centreButton = (ImageButton) findViewById(R.id.centreButton);
ImageButton rightArrowButton = (ImageButton) findViewById(R.id.rightArrow);
ImageButton downArrowButton = (ImageButton) findViewById(R.id.downArrow);
ImageButton backButton = (ImageButton) findViewById(R.id.backButton);
ImageButton homeButton = (ImageButton) findViewById(R.id.homeButton);
Button testButton = (Button) findViewById(R.id.testButton);
upArrowButton.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
sendKeyEvent(KeyEvent.KEYCODE_DPAD_UP);
}
});
leftArrowButton.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
sendKeyEvent(KeyEvent.KEYCODE_DPAD_LEFT);
}
});
centreButton.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
sendKeyEvent(KeyEvent.KEYCODE_DPAD_CENTER);
}
});
rightArrowButton.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
sendKeyEvent(KeyEvent.KEYCODE_DPAD_RIGHT);
}
});
downArrowButton.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
sendKeyEvent(KeyEvent.KEYCODE_DPAD_DOWN);
}
});
backButton.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
sendKeyEvent(KeyEvent.KEYCODE_BACK);
}
});
homeButton.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
sendKeyEvent(KeyEvent.KEYCODE_HOME);
}
});
testButton.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
Intent myIntent = new Intent(MainActivity.this, SlidepuzzleActivity.class);
MainActivity.this.startActivity(myIntent);
}
});
handler = new Handler();
// Bind to the AnymoteClientService
Intent intent = new Intent(mContext, AnymoteClientService.class);
bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
statusText = (TextView) findViewById(R.id.statusText);
}
/** Defines callbacks for service binding, passed to bindService() */
private ServiceConnection mConnection = new ServiceConnection() {
/*
* ServiceConnection listener methods.
*/
#Override
public void onServiceConnected(ComponentName name, IBinder service) {
mAnymoteClientService = ((AnymoteClientService.AnymoteClientServiceBinder) service)
.getService();
mAnymoteClientService.attachClientListener(MainActivity.this);
}
#Override
public void onServiceDisconnected(ComponentName name) {
mAnymoteClientService.detachClientListener(MainActivity.this);
mAnymoteClientService = null;
}
};
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
#Override
public void onConnected(AnymoteSender anymoteSender) {
if (anymoteSender != null) {
// Send events to Google TV using anymoteSender.
// save handle to the anymoteSender instance.
this.anymoteSender = anymoteSender;
attachTouchListnertoTouchPad();
} else {
statusText.setText(statusPrefix + "Connection attempt failed, cant find send handler");
//attempt to connect again?
//attemptToConnect();
}
// Hide the progressBar once connection to Google TV is established. Make the text display appropriately
handler.post(new Runnable() {
public void run() {
progressBar.setVisibility(View.INVISIBLE);
statusText.setText(statusPrefix + "Connected to GoogleTV");
}
});
}
#Override
public void onDisconnected() {
// show message to tell the user about disconnection.
statusText.setText(statusPrefix + "Disconnected");
// Try to connect again if needed. This may be need to be done via button
attemptToConnect();
this.anymoteSender = null;
}
#Override
public void onConnectionError() {
// show message to tell the user about disconnection.
statusText.setText(statusPrefix + "Connection error encountered");
// Try to connect again if needed.
attemptToConnect();
this.anymoteSender = null;
}
#Override
protected void onDestroy() {
if (mAnymoteClientService != null) {
mAnymoteClientService.detachClientListener(this);
}
unbindService(mConnection);
super.onDestroy();
}
private void attachTouchListnertoTouchPad()
{
// Attach touch handler to the touchpad view
touchPadHandler = new TouchHandler(
findViewById(R.id.touchPad), Mode.POINTER_MULTITOUCH, anymoteSender);
}
public void attemptToConnect()
{
//stub to invoke connection attempt
}
private void sendKeyEvent(final int keyEvent) {
// create new Thread to avoid network operations on UI Thread
if (anymoteSender == null) {
Toast.makeText(MainActivity.this, "Waiting for connection",
Toast.LENGTH_LONG).show();
return;
}
anymoteSender.sendKeyPress(keyEvent);
}
}
SlidepuzzleActivity.java:
package uk.co.myapp.gtvremote;
//imports removed for paste
public class SlidepuzzleActivity extends Activity implements ClientListener{
private AnymoteClientService mAnymoteClientService;
private Context mContext;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.slidepuzzle);
mContext = this;
ImageButton piece1x1 = (ImageButton) findViewById(R.id.piece1x1);
ImageButton piece1x2 = (ImageButton) findViewById(R.id.piece1x2);
ImageButton piece1x3 = (ImageButton) findViewById(R.id.piece1x3);
ImageButton piece2x1 = (ImageButton) findViewById(R.id.piece2x1);
ImageButton piece2x2 = (ImageButton) findViewById(R.id.piece2x2);
ImageButton piece2x3 = (ImageButton) findViewById(R.id.piece2x3);
ImageButton piece3x1 = (ImageButton) findViewById(R.id.piece3x1);
ImageButton piece3x2 = (ImageButton) findViewById(R.id.piece3x2);
ImageButton piece3x3 = (ImageButton) findViewById(R.id.piece3x3);
Intent intent = new Intent(mContext, AnymoteClientService.class);
bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
piece1x1.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
}
});
}
private ServiceConnection mConnection = new ServiceConnection() {
/*
* ServiceConnection listener methods.
*/
#Override
public void onServiceConnected(ComponentName name, IBinder service) {
mAnymoteClientService = ((AnymoteClientService.AnymoteClientServiceBinder) service)
.getService();
mAnymoteClientService.attachClientListener(SlidepuzzleActivity.this);
}
#Override
public void onServiceDisconnected(ComponentName name) {
mAnymoteClientService.detachClientListener(SlidepuzzleActivity.this);
mAnymoteClientService = null;
}
};
private void sendKeyEvent(final int keyEvent) {
// create new Thread to avoid network operations on UI Thread
if (anymoteSender == null) {
Toast.makeText(SlidepuzzleActivity.this, "Waiting for connection",
Toast.LENGTH_LONG).show();
return;
}
anymoteSender.sendKeyPress(keyEvent);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.slidepuzzle, menu);
return true;
}
#Override
public void onConnected(AnymoteSender anymoteSender) {
// TODO Auto-generated method stub
}
#Override
public void onDisconnected() {
// TODO Auto-generated method stub
}
#Override
public void onConnectionError() {
// TODO Auto-generated method stub
}
#Override
protected void onDestroy() {
if (mAnymoteClientService != null) {
mAnymoteClientService.detachClientListener(this);
}
unbindService(mConnection);
super.onDestroy();
}
}
Just published an update to AnymoteLibrary for this.
In your MainActivity call both bindService() (already) and startService() for AnymoteClientService. The reason behind calling startService() is to keep the service and its anymoteSender instance around so that other Activitys in the same app can use it.
In the second Activity, implement ClientListener ( if you want to get onDisconnected() callback) and bind to the service and attachClientListener(). To get the AnymoteSender instance, call AnymoteClientService.getAnymoteSender(). Note that it can return null if the connection to Google TV is lost.
When all Activitys are done using AnymoteSender, remember to call stopService() for AnymoteClientService.