I got a problem which I can't understand. I'm trying to solve it for 8 days and still stuck. I asked about that more experienced developers and they can't answer. So please, I desperately ask for help
the service is simple - it has one method yet - it should give me Log - getLog()
public class AudioService extends Service{
MyBinder binder = new MyBinder();
public void getLog(){Log.d("MyLog","I reached getLog!");}
#Override
public IBinder onBind(Intent arg0) {
// TODO Auto-generated method stub
return binder;
}
class MyBinder extends Binder {
AudioService getService() {
return AudioService.this;
}
}
}
MainAcivity crashes when i try to reach audioService.getLog(); It doesn't crash,however, if i insert line AudioService audioService= new AudioService(); but that's what I don't want - I need to set a Service which will play audio so I can start mp3 from one activity and stop it from another. here's MainActivity :
public class MainActivity extends Activity {
ServiceConnection sConn;
Intent intservice;
AudioService audioService ;
boolean bound=false;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
intservice=new Intent(this,AudioService.class);
sConn=new ServiceConnection(){
#Override
public void onServiceConnected(ComponentName arg0, IBinder binder) {
// TODO Auto-generated method stub
audioService = ((AudioService.MyBinder) binder).getService();
bound=true;
}
#Override
public void onServiceDisconnected(ComponentName arg0) {
// TODO Auto-generated method stub
bound=false;
}
};
startService(intservice);
audioService.getLog();
}
#Override
protected void onStart() {
super.onStart();
bindService(intservice, sConn, Context.BIND_AUTO_CREATE);
}
#Override
protected void onStop() {
super.onStop();
if (!bound) return;
unbindService(sConn);
bound = false;
}
}
in case I messed something in Manifest I shall include part with service here :
</activity>
<service android:enabled="true" android:name="AudioService"></service>
</application>
</manifest>
I can't understand what's wrong here so please give me advice where I did wrong
Well, I've found why it was. Binding is a procedure that needs time and every example existing waits for onClick which means Activity has enough time between onStart() and onCreate(). In my case it goes immediately. So the best way is to move all Activity under public void onServiceConnected(ComponentName arg0, IBinder binder). Which should mean that after binding happened - Activity goes on well.
Hope that will help to many people )
Related
I had previously managed to get my service to continue running. But today after I went back to the application to keep working with the app I noticed that the service gets disconnected after the app is closed which was not happening before.
I start the service in my main activity like this:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// setContentView(R.layout.activity_main);
if(savedInstanceState == null) {
setContentView(R.layout.activity_main);
Intent i = new Intent(MainActivity.this, SystemWebService.class);
SystemWebService.setMain(this);
MainActivity.this.startService(i);
}
The code in the SystemWebService class looks like this:
public class SystemWebService extends Service {
private static WebView webdemo;
private static MainActivity ma;
//Context dex;
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId){
// let the service continue until stopped
Toast.makeText(this, "Service has started", Toast.LENGTH_SHORT).show();
return START_STICKY;
}
#Override
public void onDestroy(){
super.onDestroy();
Toast.makeText(this, "Service has been destroyed", Toast.LENGTH_SHORT).show();
}
#Override
public void onCreate() {
super.onCreate();
}
public static void setMain(MainActivity a) {
ma = a;
SystemWebService sws = new SystemWebService();
sws.setView();
}
}
This is the code that sets the webview
public void setView() {
webdemo = (WebView) ma.findViewById(R.id.webdemo);
webdemo.addJavascriptInterface(new SystemWebService.WebAppInterface(this), "Android");
webdemo.setWebViewClient(new WebViewClient(){
#Override
public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest url){
return false;
}
});
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
webdemo.getSettings().setJavaScriptEnabled(true);
webdemo.getSettings().setDomStorageEnabled(true);
webdemo.getSettings().setAllowFileAccessFromFileURLs(true);
webdemo.getSettings().setAllowUniversalAccessFromFileURLs(true);
}
webdemo.loadUrl("file:///android_asset/_wv.html");
}
The webview establishes a connection to our server and I would normally see data display on the logs. Before I would continue to see the flux of data passing even after the application was closed but as of right not I am not seeing anything, only the message "Application terminated".
I can't seem to understand what is happening.
Passing a reference of your activity to the service, and keeping a static instance of it is not the recommended way of development. It can lead to unexpected behaviour during the life cycle of your activity or the service.
Use the Bound Services instead. Check the documentation here : https://developer.android.com/guide/components/bound-services.html
I know there are several answers to this question, but it isn't working for me, currently my code is:
public class LogoutService extends Service {
public static CountDownTimer timer;
#Override
public void onCreate(){
// TODO Auto-generated method stub
super.onCreate();
timer = new CountDownTimer(1 * 60 * 1000, 1000) {
public void onTick(long millisUntilFinished) {
//Some code
Log.v(TAG, "Service Started");
}
public void onFinish() {
Log.v(TAG, "Call Logout by Service");
// Code for Logout
stopSelf();
}
};
}
#Override
public IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
return null;
}
}
and in every activity I have:
#Override
protected void onResume() {
// TODO Auto-generated method stub
super.onResume();
LogoutService.timer.start();
}
#Override
protected void onStop() {
// TODO Auto-generated method stub
super.onStop();
LogoutService.timer.cancel();
}
But I get a "Unable to resume activity java.lang.NullPointerException: Attempt to invoke virtual method 'android.os.CountDownTimer android.os.CountDownTimer.start()' on a null object reference" when I try to start any of my activities that contain this code. My application isn't too complicated, it's completely offline, so no web service calls or anything, I just need to go back to my login activity after x minutes. Anyone have any ideas?
Here's the one I used: Auto logout after X minutes, Android and http://androidjug.blogspot.com/2015/10/auto-logout-after-15-minutes-due-to.html
You aren't starting the service, so you aren't allocating the timer. Really you should not be using a static for this.
I'm working on an App where i want to stream a specific video, which is located on my mobile device. I want to stream this video with the help of ChromeCast to a projector. I've done the Google Chromecast Tutorials (https://codelabs.developers.google.com/codelabs/cast-videos-android/#0 for example) and already looked for an answer to my Question but there wasn't the perfect answer to solve my problem in my opinion.
There are a few solutions in other coding languages but not especially for java.
My problem with the Google Cast API is: I want to select my ChromeCast without pressing the Cast Button in the OptionMenu, which appears to select one of the ChromeCasts in the Network.
I just found out, that the setRouteSelector-Methode from the class CastButtonFactory is a part to select the Device. But i can't find out, how to select the device automatically.
Here is my Code where the CastButton appears (created in the OnCreateOptionsMenu-Method)(It's just the Code to Connect to the ChromeCast. I didn't implement the Code for selecting and streaming the video yet):
Can anyone help me?
Code:
public class MainActivity extends AppCompatActivity {
private CastSession mCastSession;
private CastContext mCastContext;
private SessionManager mSessionManager;
private final SessionManagerListener mSessionManagerListener = new SessionManagerListenerImpl();
private class SessionManagerListenerImpl implements SessionManagerListener{
#Override
public void onSessionStarting(Session session) {}
#Override
public void onSessionStarted(Session session, String sessionId) {
invalidateOptionsMenu();
}
#Override
public void onSessionStartFailed(Session session, int i) {}
#Override
public void onSessionEnding(Session session) {}
#Override
public void onSessionEnded(Session session, int error) {
finish();
}
#Override
public void onSessionResuming(Session session, String s) {}
#Override
public void onSessionResumed(Session session, boolean wasSuspended) {
invalidateOptionsMenu();
}
#Override
public void onSessionResumeFailed(Session session, int i) {}
#Override
public void onSessionSuspended(Session session, int i) {}
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mCastContext = CastContext.getSharedInstance(this);
mCastContext.registerLifecycleCallbacksBeforeIceCreamSandwich(this, savedInstanceState);
mSessionManager = CastContext.getSharedInstance(this).getSessionManager();
}
#Override
public void onResume(){
mCastSession = mCastContext.getSessionManager().getCurrentCastSession();
mSessionManager.addSessionManagerListener(mSessionManagerListener);
super.onResume();
}
#Override
public void onPause(){
super.onPause();
mSessionManager.removeSessionManagerListener(mSessionManagerListener);
mCastSession = null;
}
#Override
public void onStart(){
super.onStart();
}
#Override public boolean onCreateOptionsMenu(Menu menu) {
super.onCreateOptionsMenu(menu);
getMenuInflater().inflate(R.menu.menu, menu);
CastButtonFactory.setUpMediaRouteButton(getApplicationContext(),
menu,
R.id.media_route_menu_item);
return true;
}}
This is possible with SDK v2. Check out the source code for MediaRouteChooserDialogFragment, the UI element that lets users select a Cast device. You'll want to create a MediaRouter.Callback, and override onRouteAdded(MediaRouter router, MediaRouter.RouteInfo newRoute). If the new route is not the default route, select it with mMediaRouter.selectRoute(newRoute). This will connect you to the receiver device without any user interaction.
This should work for testing, but please don't do this in a production app. #AliNaddaf correctly notes this is against the UX guidelines and Google Cast terms of service (you can imagine the potential for abuse if apps are permitted to start casting without the user's consent).
I'm trying to add a custom quick settings tile for my application. I've followed the sample code/documentation from Google but I'm running into some issues. After searching for some time I couldn't find any solutions.
When I run my app, the tile is visible in the quick settings tray, but it remains in an unavailable state.
I need a two-way flow of communication with the tile, i.e., when the user selects the tile, the app responds and when the user does a certain action within the app, the tile UI is toggled.
The problem seems to come from attempting to bind my custom TileService class to my MainActivity -- whenever I bind it is when the tile goes into a consistently unavailable state. I can't seem to figure out why though because it's being bound successfully. If I don't bind it (i.e. just have the one way communication of the tile commanding the app), the tile is active and the app responds to selecting it.
Ultimately I do the binding to attain a reference to my custom TileService class to be able to call it's method toggleTileUI(). I'm not looking to use a singleton or static member variable as a solution to getting a reference to my service.
Here's what I have in my AndroidManifest.xml:
<service
android:name=".ConnectionQuickSettingsService"
android:label="#string/quick_setting_tile_connect"
android:icon="#drawable/tile_icon"
android:permission="android.permission.BIND_QUICK_SETTINGS_TILE">
<intent-filter>
<action android:name="android.service.quicksettings.action.QS_TILE" />
</intent-filter>
</service>
Here's my ConnectionQuickSettingsService.java:
#TargetApi(24)
public class ConnectionQuickSettingsService extends TileService {
private static final String TAG = "ConnectionQuickSettingsService";
private final IBinder mBinder = new LocalBinder();
public class LocalBinder extends Binder {
ConnectionQuickSettingsService getService() {
return ConnectionQuickSettingsService.this;
}
}
#Override
public IBinder onBind(Intent i) {
return mBinder;
}
#Override
public void onTileAdded() {
L.d(TAG, "onTileAdded()");
}
#Override
public void onStartListening() {
L.d(TAG, "onStartListening()");
}
#Override
public void onClick() {
L.d(TAG, "Quick Settings tile selected");
toggleInAppSwitch();
toggleTileUI();
}
private void toggleInAppSwitch() {
doStuff();
}
public void toggleTileUI() {
Tile tile = this.getQsTile();
doStuffWithTile();
}
}
and lastly (the relevant parts of) my MainActivity.java:
#Override
protected void onStart() {
super.onStart();
Intent i = new Intent(this, ConnectionQuickSettingsService.class);
bindService(i, mConnection, Context.BIND_AUTO_CREATE);
}
#Override
protected void onStop() {
super.onStop();
if (mBound) {
unbindService(mConnection);
mBound = false;
}
}
private ServiceConnection mConnection = new ServiceConnection() {
#Override
public void onServiceConnected(ComponentName className,
IBinder service) {
ConnectionQuickSettingsService.LocalBinder binder = (ConnectionQuickSettingsService.LocalBinder) service;
mQSService = binder.getService();
mBound = true;
L.d(TAG, "Bound to QS service successfully");
}
#Override
public void onServiceDisconnected(ComponentName arg0) {
mBound = false;
L.d(TAG, "Disconnected from QS service");
}
};
public void onOnOff(){
L.d(TAG, "On/Off switch toggled");
if (mBound) {
mQSService.toggleTileUI();
}
}
Any input would be greatly appreciated, thanks!
Part of your problem is that you are overriding onBind(), which clobbers the TileService implementation of onBind(), preventing Android from working with your ConnectionQuickSettingsService. I would expect that there would be error messages in LogCat from a system process complaining about this.
The other part of your problem is that you assume that getQsTile() works at arbitrary points in time. It doesn't.
I recommend finding some other interaction pattern with your tile, such as using META_DATA_ACTIVE_TILE and requestListeningState(), and getting rid of your Binder and onBind() method.
I don't think you need all the service connection. I would add the meta data META_DATA_ACTIVE_TILE to the tile service manifest declaration, and then you can call TileService.requestListeningState(context, new ComponentName(context, TileService.class)); which will trigger onStartListening().
After that onStartListening() could call a method to update the Tile state/label/icon.
Also in your Tile service method to update the tile
I would add a check if (getQsTile !=null)
I've tried implementing an onClickListener on a CameraFragment, however, it never seems to be called. I am probably missing something quite simple. Does anyone have any ideas?
public class CWACCameraFragment extends CameraFragment implements OnClickListener {
//...
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
takePicture();
Toast.makeText(getActivity(),"click",
Toast.LENGTH_LONG).show();
}
Is there a way to ensure that the onClick event occurs?
In the demo app, I added the following to DemoCameraFragment:
#Override
public void onStart() {
super.onStart();
getView().setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Log.e(getClass().getSimpleName(), "got here");
}
});
}
Log messages showed up just fine. Hence, AFAICT, your approach works, so perhaps there is some bug in how you wired in the click listener.