Android : Google API inside a custom adapter - java

I'm using a custom adapter called CustomQuestionAdapter, to display a list of question inside a listview, as we know the adapter extends from an ArrayAdapter, then i needed info about my location inside the adapter so i implemented the needed interfaces ( GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener ) and implemented it's methods, however it show me an error saying "method does not override method from its superclass" in the Overrided methods onStart() and onStop() , but when i tried to extends from AppCompatActivity instead of ArrayAdapter the error disappear.
This is the signature of my class :
public class CustomQuestionAdapter extends ArrayAdapter<Question> implements
GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener
Error here "method does not override method from its superclass"
#Override
protected void onStart() {
super.onStart();
mGoogleApiClient.connect();
}
#Override
protected void onStop() {
super.onStop();
if (mGoogleApiClient.isConnected()) {
mGoogleApiClient.disconnect();
}
}
So how to fix this properly ?

For implementing GoogleApiClient.ConnectionCallbacks and GoogleApiClient.OnConnectionFailedListener, you have to override these methods
#Override
public void onConnected(#Nullable Bundle bundle) {
Log.d("isj","connected");
}
#Override
public void onConnectionSuspended(int i) {
Log.d("isj","connection susspended");
}
#Override
public void onConnectionFailed(#NonNull ConnectionResult connectionResult) {
Log.d("isj","connection failed");
}
EDIT:
onStart() and onStop() methods dont belong to the arrayAdapter class.
Connect the google api client in the constructor of your adapter or you could create two methods to connect and disconnect the googleApiClient and call them from the activity in which you are setting the adapter.
Its always a better idea to pass the needed values in the constructor of the adapter from the activity

Related

How to check internet connectivity using broadcast receiver and Change the intent

I am working on an Android application which requires constant listener of Internet connectivity. I am using Broadcast listener and successfully applied it. But my code only shows the Toast message.
I want to stop the current activity and show a default XML file which says "No Internet Connection". and whenever it connect the Internet, previous activity resumes.
ExampleBradcastReceiver.java
public class ExampleBroadcastReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
if (ConnectivityManager.CONNECTIVITY_ACTION.equals(intent.getAction())) {
boolean noConnectivity = intent.getBooleanExtra(
ConnectivityManager.EXTRA_NO_CONNECTIVITY, false
);
if (noConnectivity) {
Toast.makeText(context, "Disconnected", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(context, "Connected", Toast.LENGTH_SHORT).show();
}
}
}
MainActivity.java
public class MainActivity extends AppCompatActivity {
ExampleBroadcastReceiver exampleBroadcastReceiver = new ExampleBroadcastReceiver();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
#Override
protected void onStart() {
super.onStart();
IntentFilter filter = new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION);
registerReceiver(exampleBroadcastReceiver, filter);
}
#Override
protected void onStop() {
super.onStop();
unregisterReceiver(exampleBroadcastReceiver);
}
}
In the place of Toast Message, I want to show a default XML file whenever disconnected and resume activity whenever connected.
You can move ExampleBroadcastReceiver to MainActivity as an inner class. And since in Java inner classes have access to their parent classes' methods and fields, you can in onReceive method consider showing/hiding the Internet disconnected view.
public class MainActivity extends AppCompatActivity {
ExampleBroadcastReceiver exampleBroadcastReceiver = new ExampleBroadcastReceiver();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
#Override
protected void onStart() {
super.onStart();
IntentFilter filter = new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION);
registerReceiver(exampleBroadcastReceiver, filter);
}
#Override
protected void onStop() {
super.onStop();
unregisterReceiver(exampleBroadcastReceiver);
}
private void showInternetDisconnectedView(boolean disconnected){
// show or hide based on 'disconnected'
}
private class ExampleBroadcastReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
if (ConnectivityManager.CONNECTIVITY_ACTION.equals(intent.getAction())) {
boolean noConnectivity = intent.getBooleanExtra(
ConnectivityManager.EXTRA_NO_CONNECTIVITY, false);
showInternetDisconnectedView(noConnectivity);
}
}
}
}
You need to move Broadcast receiver code into Activity and on receiving internet connection events you can stop current in progress activity and make internet failure layout visible there only as it is part of Activity class. If it is required through out the Application, then create Base activity and handle this there to avoid duplicating code on every screen.

How to check the which activity is currently running while debugging the app

I am stuck with a project developed by someone else. Its a very big app. So for the purpose of understanding the code I want to know the flow, basically the name of the activity(the java file in the code) which is currently running in on my phone. I can put break-points in all activities, but is there any other way?
You can use adb for it.
In your terminal run adb shell dumpsys activity top.
Using ActivityLifecycleCallbacks, you don't need to add handling for all the activities. Do the registration once, it works for ALL activities, and that is it!
public class MyApplication extends Application implements
ActivityLifecycleCallbacks{
#Override
public void onCreate() {
super.onCreate();
}
#Override
public void onActivityStopped(Activity activity) {
Log.i("Tracking Activity Stopped", activity.getLocalClassName());
}
#Override
public void onActivityStarted(Activity activity) {
Log.i("Tracking Activity Started", activity.getLocalClassName());
}
#Override
public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
Log.i("Tracking Activity SaveInstanceState", activity.getLocalClassName());
}
#Override
public void onActivityResumed(Activity activity) {
Log.i("Tracking Activity Resumed", activity.getLocalClassName());
}
#Override
public void onActivityPaused(Activity activity) {
Log.i("Tracking Activity Paused", activity.getLocalClassName());
}
#Override
public void onActivityDestroyed(Activity activity) {
Log.i("Tracking Activity Destroyed", activity.getLocalClassName());
}
#Override
public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
Log.i("Tracking Activity Created", activity.getLocalClassName());
}
}
Note that you can identify which activity via activity.getLocalClassName().
Simple -
In each activity override onStart() method and print log like this -
#Override
protected void onStart() {
super.onStart();
Log.d("TAG -> ", "YOUR_ACTIVITY_NAME");
}
When activity start in your device, it will print log in logcat. Hope it will help!
From manifest figure out Launching activity and to find out methods and variables used.. u can use "Find Usages" ( Ctrl+G ).
If your application extends MultiDexApplication class here is a working solution.
In onCreate() method of your application class that extends MultiDexApplication add the following line to register the callbacks.
#Override
public void onCreate() {
super.onCreate();
registerActivityLifecycleCallbacks(new MyActivityLifecycleCallbacks());
}
Now make an inner class that implements ActivityLifecycleCallbacks as follow
private static final class MyActivityLifecycleCallbacks implements ActivityLifecycleCallbacks {
public void onActivityCreated(Activity activity, Bundle bundle) {
Log.v("Application","Created");
}
public void onActivityDestroyed(Activity activity) {
Log.v("Application","Destroyed");
}
public void onActivityPaused(Activity activity) {
Log.v("Application","Paused");
}
public void onActivityResumed(Activity activity) {
Log.v("Application","Resumed");
}
public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
Log.v("Application","onActivitySaveInstanceState");
}
public void onActivityStarted(Activity activity) {
Log.v("Application","Started");
}
public void onActivityStopped(Activity activity) {
Log.v("Application","Stopped");
}
}
Now you may use activity.getLocalClassName() in any overridden method you need.
This would be all you need. Happy Debugging :)

Greenrobot EventBus3 not posting to my subscribers

In my application, I pass a job into the job-queue and in my Job queue, I've registered my EventBus and I am trying to post the event with the hopes that my subscriber method would receive it. I have just recently migrated from Otto's EventBus and while this way had previously worked, it is not working for greenrobots EventBus 3.
Here is a sample case for what I'm trying to achieve:
TestPresenterImpl.class (This class has been instantiated the TestActivity.class)
#Override
public void addJob(JobData jobData) {
jobManager.addJobInBackground(new SendUpdateJob(jobData));
}
#Subscribe
#Override
public void onUpdate(JobAddedEvent event) {
if (event.getStatus() == 1) {
Log.i(LOG_TAG, "test");
}
}
#Override
public void onStart() {
mBus.getDefault().register(this);
}
#Override
public void onStop() {
mBus.getDefault().unregister(this);
}
SendUpdateJob.class (This is the class that handles the jobs in the queue using the android-priority-job queue previously maintained by Path)
#Override
public void onAdded() {
Log.i(LOG_TAG, "On added");
mBus.getDefault().register(this);
JobAddedEvent event = new JobAddedEvent();
event.setStatus(1);
mBus.getDefault().post(event);
}
Normally this works on Otto but since this is a slightly different, I want to know what I'm doing incorrectly. The error I get is: ..."SendJobUpdate and its super classes have no public methods with the #Subscribe annotation". Am I doing something wrong here?
I've also made sure that I'm importing import org.greenrobot.eventbus.Subscribe;
because I've noticed others have pointed out that they have imported googles subscribe.
Your EventBus.getDefault().register(this); should follow your Activity which your #Subscribe method is in, not in mBus.getDefault().post(event); Activity.
FirstActicity
public class FirstActicity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_home);
//register should in this activity
EventBus.getDefault().register(this);
}
#Subscribe(threadMode = ThreadMode.MainThread)
public void onEvent(MessageEvent event) {
//eventbus notify
Log.i("2hh", "main --- eventbus ---- updatedata");
queryData();
}
#Override
protected void onDestroy() {
if (EventBus.getDefault().isRegistered(this)) {
EventBus.getDefault().unregister(this);
}
}
SecondActivity(don't register in this activity beacuse you didn't hava any #Subscribe method)
public class SecondActivity extends AppCompatActivity implements{
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_add);
EventBus.getDefault().post(new MessageEvent("updateData"));
}
}

GoogleApiClient issue: GoogleApiClient is not connected yet

In this class,:
public class Presence implements ConnectionCallbacks,
OnConnectionFailedListener, LocationListener
I have the following constructor:
private Presence(Context context)
{
this.context = context;
gApiClient = new GoogleApiClient.Builder(context, this, this)
.addApi(LocationServices.API)
.build();
if (!gApiClient.isConnecting() && !gApiClient.isConnected())
{
gApiClient.connect();
}
} // of constructor()
I use it to return a Singleton instance:
public static synchronized Presence getInstance(Context context)
{
if (presenceSingleton == null)
presenceSingleton = new Presence(context);
return presenceSingleton;
}
The onConnected() looks like this:
#Override
public void onConnected(Bundle connectionHint)
{
Log.e(LOG_TAG, "In onConnected(), gApiClient.isConnected(): " +
gApiClient.isConnected());
createLocationRequest();
getLocation();
getSubLocality();
} // of onConnected()
Based on a setting the user can make in the app, I call the following method to put the app into a so-called auto-pilot mode, where it starts tracking the user's location:
public void startLocationUpdates()
{
// Prints 'false' in the logs:
Log.e(LOG_TAG, "In startLocationUpdates(), gApiClient.isConnected(): " + gApiClient.isConnected());
Intent locationChangeIntent = new Intent(context, LocationTracker.class);
pendingIntent = PendingIntent.getService(context, 188, locationChangeIntent, PendingIntent.FLAG_UPDATE_CURRENT);
// Crash points to the following line:
LocationServices.FusedLocationApi.requestLocationUpdates(gApiClient, locationRequest, pendingIntent);
} // of startLocationUpdates()
In the main activity, I make an instance of the above class in the onCreate():
public class MainClass extends AppCompatActivity implements
OnSharedPreferenceChangeListener
{
....
....
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
getAppSettings();
presence = Presence.getInstance(getApplicationContext());
....
....
startApp();
....
}
private void startApp()
{
if (pref_autoPilot)
presence.startLocationUpdates();
}
....
....
....
} // of class MainClass
When the user sets the auto pilot preference, the app crashes with the following exception:
java.lang.IllegalStateException: GoogleApiClient is not connected yet.
at the line indicated in the above method startLocationUpdates().
I read a lot of answers, but was unable to figure out a solution to this issue. Can you please point out what I am doing wrong? Is it that the Presence class should be in an AppCompatActivity or FragmentActivity or similar, and cannot be independent like in here? Please help me fix this nagging issue.
Many thanks in advance!
You should call presence.startLocationUpdates(); this method from onConnected() method. And check the condition befor calling, if your location is null. Before the connection happend of GoogleApiClient you can;t update location.
Follow the simple guidelines at Android Developers.
I think you missed the following part:
protected void onStart() {
mGoogleApiClient.connect();
super.onStart();
}
protected void onStop() {
mGoogleApiClient.disconnect();
super.onStop();
}
In your MainActivity you need to call connect and disconnect when required (in other words, when so called auto-pilot mode is on)
You should instantiate a client object in your Activity's onCreate(Bundle) method and then call connect() in onStart() and disconnect() in onStop(), regardless of the state.
For the sake of completeness, #Kedi...
Can you please point out what I am doing wrong?
gApiClient.connect() was not being called in the right place. Please see the accepted answer.
Is it that the Presence class should be in an AppCompatActivity or FragmentActivity or similar, and cannot be independent like in here?
It can be an independent class
Thanks every one for your kind help.

Automatically log Android lifecycle events using ActivityLifecycleCallbacks?

I am trying to automatically capture and log Android lifecycle events using ActivityLifecycleCallbacks, however documentation on this matter is scarce, to say the least:
public void registerActivityLifecycleCallbacks (Application.ActivityLifecycleCallbacks callback)
I don't want to have to extend the Activity class or override the existing lifecycle methods (onCreate, onResume, etc...) I'm looking to have a separate class listening for these events and acting accordingly.
Does anyone have any experience in this, or have links to good solid documentation or tutorials on how this works? Specifically, how to register for ActivityLifecycleCallbacks, and how to handle them?
I don't have any firsthand experience but judging from the API you can just write your own class that implements the Application.ActivityLifecycleCallbacks interface and register that class on the provided Application class instance
getApplicaton().registerActivityLifecycleCallbacks(yourCustomClass);
This class will receive the same callbacks as your individual activities. Good luck.
PS. This is API level 14 btw, so it won't work on older phones.
I did my own implementation of Application.ActivityLifecycleCallbacks. I'm using SherlockActivity, but for normal Activity class might work.
First, I'm creating an interface that have all methods for track the activities lifecycle:
public interface ActivityLifecycleCallbacks{
public void onActivityStopped(Activity activity);
public void onActivityStarted(Activity activity);
public void onActivitySaveInstanceState(Activity activity, Bundle outState);
public void onActivityResumed(Activity activity);
public void onActivityPaused(Activity activity);
public void onActivityDestroyed(Activity activity);
public void onActivityCreated(Activity activity, Bundle savedInstanceState);
}
Second, I implemented this interface in my Application's class:
public class MyApplication extends Application implements my.package.ActivityLifecycleCallbacks{
#Override
public void onCreate() {
super.onCreate();
}
#Override
public void onActivityStopped(Activity activity) {
Log.i("Tracking Activity Stopped", activity.getLocalClassName());
}
#Override
public void onActivityStarted(Activity activity) {
Log.i("Tracking Activity Started", activity.getLocalClassName());
}
#Override
public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
Log.i("Tracking Activity SaveInstanceState", activity.getLocalClassName());
}
#Override
public void onActivityResumed(Activity activity) {
Log.i("Tracking Activity Resumed", activity.getLocalClassName());
}
#Override
public void onActivityPaused(Activity activity) {
Log.i("Tracking Activity Paused", activity.getLocalClassName());
}
#Override
public void onActivityDestroyed(Activity activity) {
Log.i("Tracking Activity Destroyed", activity.getLocalClassName());
}
#Override
public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
Log.i("Tracking Activity Created", activity.getLocalClassName());
}
}
Third, I'm creating a class that extends from SherlockActivity:
public class MySherlockActivity extends SherlockActivity {
protected MyApplication nMyApplication;
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
nMyApplication = (MyApplication) getApplication();
nMyApplication.onActivityCreated(this, savedInstanceState);
}
protected void onResume() {
// TODO Auto-generated method stub
super.onResume();
nMyApplication.onActivityResumed(this);
}
#Override
protected void onPause() {
// TODO Auto-generated method stub
super.onPause();
nMyApplication.onActivityPaused(this);
}
#Override
protected void onDestroy() {
// TODO Auto-generated method stub
super.onDestroy();
nMyApplication.onActivityDestroyed(this);
}
#Override
protected void onStart() {
super.onStart();
nMyApplication.onActivityStarted(this);
}
#Override
protected void onStop() {
super.onStop();
nMyApplication.onActivityStopped(this);
}
#Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
nMyApplication.onActivitySaveInstanceState(this, outState);
}
}
Fourth, all class that extend from SherlockActivity, I replaced for MySherlockActivity:
public class MainActivity extends MySherlockActivity{
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
}
Now, in the logcat you will see the logs programmed in the Interface implementation made in MyApplication.
UPDATE
This implementation was tested from API Level 9 (Gingerbread), API Level 12 (Honeycomb) and API Level 17 (Jelly Bean) and works fine. Might works in Android's older versions.
Try this: http://engineering.meetme.com/2015/04/android-determine-when-app-is-opened-or-closed/#comment-202
It proposes an AppForegroundStateManager to which each activity reports through its onStop() and onStart() functions like this:
#Override
protected void onStart() {
super.onStart();
AppForegroundStateManager.getInstance().onActivityVisible(this);
}
#Override
protected void onStop() {
AppForegroundStateManager.getInstance().onActivityNotVisible(this);
super.onStop();
}
Your Application class implements a listener like this:
public class MyApplication extends Application {
#Override
public void onCreate() {
super.onCreate();
AppForegroundStateManager.getInstance().addListener(this);
}
#Override
public void onAppForegroundStateChange(AppForegroundStateManager.AppForegroundState newState) {
if (AppForegroundStateManager.AppForegroundState.IN_FOREGROUND.equals(newState)) {
// App just entered the foreground. Do something here!
Log.i(TAG, "App Just Entered the Foreground with launch mechanism of: " + mLaunchMechanism);
} else {
// App just entered the background. Set our launch mode back to the default of direct.
mLaunchMechanism = LaunchMechanism.DIRECT;
}
}
}
It also includes tips and tricks for determining how the app was opened - from a notification, a URL opening your app or directly from the Apps menu. This is done through an Enum in the Application class:
public enum LaunchMechanism {
DIRECT,
NOTIFICATION,
URL,
BACKGROUND
}
private LaunchMechanism mLaunchMechanism = LaunchMechanism.DIRECT;
public void setLaunchMechanism(LaunchMechanism launchMechanism) {
mLaunchMechanism = launchMechanism;
}
In our implementation of this, we have flags for when we start an activity that will launch a third-party activity, like if the user makes a phone call from our app or if a browser is launched. In the launching activity's onStop() we then do a check like this to only report the activity's not-visibility when those flags are false:
if(!flag_userLaunchedThirdPartyActivity){
AppForegroundStateManager.getInstance().onActivityNotVisible(this);
}
For checking whether or not the application goes into the background - for example when the device's screen goes dark or the user receives a phone call - it works like this:
public static boolean isApplicationGoingToBackground(final Context context) {
ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
List<RunningTaskInfo> tasks = am.getRunningTasks(1);
if (!tasks.isEmpty()) {
ComponentName topActivity = tasks.get(0).topActivity;
if (!topActivity.getPackageName().equals(context.getPackageName())) {
setLaunchMechanism(LaunchMechanism.BACKGROUND);
return true;
}
}
setLaunchMechanism(LaunchMechanism.DIRECT);
return false;
}
This solution is not dependent on an API level, so it should work all the way back to API level 1.
#Override
public void onCreate() {
super.onCreate();
registerActivityLifecycleCallbacks(MyApplication.this/*(Your Application Name)*/);
}
Only add this line on Application class and all works well.

Categories