My Android App Uses CPU even after closed - android

My Application drains the battery.I have used services where a request is sent to url.The service is called from my class which extends Application.Below is my code.
public class GApplication extends Application {
private static final String TAG ="GApplication";
private HttpClient httpClient;
private DatabaseHelper databaseHelper;
#Override
public void onCreate(){
super.onCreate();
startService(new Intent(this, GService.class));
httpClient = createHttpClient();
databaseHelper = new DatabaseHelper(this);
}
#Override
public void onLowMemory(){
super.onLowMemory();
shutdownHttpClient();
}
#Override
public void onTerminate(){
super.onTerminate();
stopService(new Intent(this, GService.class));
shutdownHttpClient();
databaseHelper.close();
}
private void shutdownHttpClient(){
if(httpClient != null && httpClient.getConnectionManager() != null){
httpClient.getConnectionManager().shutdown();
}
}
public DatabaseHelper getDatabaseHelper(){
if(databaseHelper == null){
databaseHelper = new DatabaseHelper(this);
}
return databaseHelper;
}
public HttpClient getHttpClient(){
return httpClient;
}
public HttpClient createHttpClient(){
HttpParams params = new BasicHttpParams();
HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
HttpProtocolParams.setContentCharset(params, HTTP.DEFAULT_CONTENT_CHARSET);
HttpProtocolParams.setUseExpectContinue(params, true);
SchemeRegistry registry = new SchemeRegistry();
registry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
registry.register(new Scheme("https", PlainSocketFactory.getSocketFactory(), 443));
return new DefaultHttpClient(new ThreadSafeClientConnManager(params, registry), params);
}
public boolean isOnline(){
boolean isConnected = false;
try{
ConnectivityManager manager = (ConnectivityManager)getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo info = manager.getActiveNetworkInfo();
isConnected = (info != null && info.isAvailable() && info.isConnected());
}
catch(Exception e){
isConnected = false;
if(e.getMessage() != null) Log.e(TAG, e.getMessage());
}
return isConnected;
}
}
My Gservice Class
public class GService extends Service {
private static final String TAG = "Gservice";
public IBinder onBind(Intent intent) {
return null;
}
public void onCreate(){
super.onCreate();
Log.i(TAG, "starting GService");
if(isOnline()){
URI uri = URI.create("http://myserver/Android/UploadImage/newAlert.php");
new UpdateCheckAsyncTask(getHttpClient()).execute(uri);
}
}
boolean isOnline(){
return ((GApplication)getApplication()).isOnline();
}
HttpClient getHttpClient(){
return ((GApplication)getApplication()).getHttpClient();
}
DatabaseHelper getDatabaseHelper(){
return ((GApplication)getApplication()).getDatabaseHelper();
}
class UpdateCheckAsyncTask extends WebAsyncTaskBase{
public UpdateCheckAsyncTask(HttpClient httpClient) {
super(httpClient);
}
protected String doInBackground(URI... params) {
return getHttpContent(params[0]);
}
protected void onProgressUpdate(Integer... progress){
}
protected void onPostExecute(String result){
if(result == null){
Log.i(TAG, "Call returned null");
return;
}
try {
Log.i(TAG, "Processsing request");
JSONObject json = new JSONObject(result);
new BlogDbAsyncTask(getDatabaseHelper()).execute(json);
} catch (JSONException e) {
if(e.getMessage() != null) Log.e(TAG, e.getMessage());
}
}
class BlogDbAsyncTask extends DbAsyncTaskBase<JSONObject, Boolean, BlogInfo>{
public BlogDbAsyncTask(DatabaseHelper database) {
super(database);
}
#Override
protected BlogInfo doInBackground(JSONObject... json) {
BlogInfo blogInfo = new BlogInfo();
BlogDAO dao = new BlogDAO(GService.this, getDatabaseHelper());
try {
Log.i(TAG, "Adding new blog entry");
Blog blog = dao.Select(json[0].getInt("FeedId"));
if(blog.UID == null){
blog.UID = json[0].getInt("FeedId");
blog.Text = json[0].getString("Text");
blog.Title = json[0].getString("Header");
blog.PostedOn = json[0].getString("DisplayDate");
blog.PostedBy = "Gservice";
dao.Insert(blog);
blogInfo.Blog = blog;
blogInfo.IsNew = true;
}
} catch (JSONException e) {
if(e.getMessage() != null) Log.e(TAG, e.getMessage());
}
return blogInfo;
}
protected void onPostExecute(BlogInfo result){
}
}
class BlogInfo{
public Blog Blog;
public boolean IsNew;
}
}
Probably the Onterminate method is never called in GApplication class which makes the service run continuously.Please Suggest if any issues can be found with this code.Also Suggest how to stop service if onterminate is never called in device..Thanks in advance.

onTerminate isn't supposed to be called on real devices:
This method is for use in emulated process environments. It will never
be called on a production Android device, where processes are removed
by simply killing them; no user code (including this callback) is
executed when doing so.
you should consider using services instead, and use the appropriate one according to your needs.
if you wish to know when the app was "closed", you need to track the state of the activities. for example, you could have a global counter that counts the number of active activities. for each onCreate, you increase its value. for each onDestroy, you decrease its value. when it reaches 0, it means that no activity is currently active.
however, you should be warned that it's not quite accurate, since activities will be destroyed and re-created when the configuration has changed, so you will need to handle it too.
as i've mentioned, you should consider using a service instead. maybe bind to it on each activity that you need, and unbind when the activity was destroyed. maybe even make it run in the foreground and close it on demand... all depends on your requirements.

You need to use an IntentService instead of Service. This way the service will shut itself down once it completes the task.

Related

How to set a fixed time if AsyncTask is not finished

I have an asynctask and I'm looking to do a wait if the async is taking too long, I'm downloading some data of the database , but I don't want to have the user looping around the progressdialog, I want to set a fixed time, lets say I'm downloading a file but is taking forever, so I tell the user, "hey, check your internet connection and try again" I'm looking to do this with a timer, but I'm kinda stuck, this is where I do my asynctask
private class DownloadFilesTask extends AsyncTask<Void, Void, Void> {
String s;
public DownloadFilesTask(String s){
this.s = s;
}
#Override
protected Void doInBackground(Void... voids) {
DownloadMethod(s);
return null;
}
}
so let's say I want to execute that downloadmethod for a fixed time, 10 or 20 seconds, if the file is not downloaded at that time I return a message to the user saying that he needs to check for hes internet.
You can use handler to run after a definite amount time and maintain a boolean flag which you can update in postExecute function of async task.
In your activity/fragment class:
new Handler().postDelayed(new Runnable(){
public void run(){
//Check whether the flag has been updated or not
},1000)
You can use BroadcastReceiver to listen your internet connection. Here is an example:
public class NetworkControl extends BroadcastReceiver {
static boolean isConnected = false;
#Override
public void onReceive(final Context context, final Intent intent) {
isNetworkAvailable(context);
}
private boolean isNetworkAvailable(Context context) {
ConnectivityManager connectivity = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
if (connectivity != null) {
NetworkInfo[] info = connectivity.getAllNetworkInfo();
if (info != null) {
for (int i = 0; i < info.length; i++) {
if (info[i].getState() == NetworkInfo.State.CONNECTED) {
if(!isConnected){
isConnected = true;
Toast.makeText(context, "You're online!!", Toast.LENGTH_LONG).show();
}
return true;
}
}
}
}
isConnected = false;
Toast.makeText(context, "Connection interrupted.", Toast.LENGTH_LONG).show();
return false;
}
}
Also you need some permissions in AndroidManifest.xml
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
Then start the service in your activity.
IntentFilter filter = new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION);
receiver = new NetworkControl();
registerReceiver(receiver, filter);
If you are using HttpURLConnection to download the file then you can do something like this:
private class DownloadFilesTask extends AsyncTask<String, Integer, Integer> {
#Override
protected Integer doInBackground(String... ulr) {
URL url = null;
try {
url = new URL(ulr[0]);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setDoOutput(true);
connection.setConnectTimeout(2000); //Timeout
//...Other codes for downloading
return 101;
} catch (java.net.SocketTimeoutException e) {
return 102;
} catch (MalformedURLException e) {
return 103;
} catch (IOException e) {
return 104;
}
}
#Override
protected void onPostExecute(Integer result) {
if(result == 102) {
Toast.makeText(getApplicationContext(), "Connection Timeout.", Toast.LENGTH_LONG).show();
}
}
}
First thing I want to say that is, while running downloading task it's not a good practice, to message a user that check your internet connection or
no internet connection. Because in this condition, if user do switch off then on network connection then your downloading task restarts again and takes whole time again. So, avoid this types of messages.
Now about solution, after execute background task you can check your task is running or completed. If it takes too much time
then show a message. For example,
YourBackgroundTask task = new YourBackgroundTask();
task.execute();
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
if (task.getStatus == AsyncTask.Status.RUNNING){
Toast.makeText(this, "Please wait...", Toast.LENGTH_SHORT).show();
}
}
},20000); // time in milisecond
And if you want to repeat this, you can easily re-run handler.
Here is a basic idea you can try if it works
private class DownloadFilesTask extends AsyncTask<Void, Integer, Void> implements TimerTask{
String s;
Timer timer;
Object objectResult;
public DownloadFilesTask(String s){
this.s = s;
timer = new Timer();
}
#Override
protected Void doInBackground(Void... voids) {
objectResult = DownloadMethod();
return null;
}
private Object DownloadMethod() {
//here implement the download logic and return the object
return null;
}
#Override
protected void onProgressUpdate(Integer... progress) {
// your code to update progress
}
public void checkProgress(){
timer.schedule(this,2000);
}
#Override
public void run() {
if (objectResult!=null){
//download completed
}else{
//show dialog here and schedule a task again
timer.schedule(this,2000);
}
}
}

Android sockets reconnect to server

I'm building a android app that using connection with Java server (on computer).
I have a problem- when I find that there is no connection with the server, I'm trying to reconnect to the server but it doesn't work.
Here is the Client class code:
public class Client extends AsyncTask {
private final int port = 1978;
private final String ip = "192.168.14.22";
private Socket socket;
private DataOutputStream output;
private DataInputStream input;
public Client() {
}
#Override
protected Object doInBackground(Object[] objects) {
try {
socket = new Socket(ip, port);
output = new DataOutputStream(socket.getOutputStream());
input = new DataInputStream(socket.getInputStream());
Log.d("Network c1", "Connected");
} catch (IOException e) {
socket = null;
Log.d("Network c1", "Not connected");
}
return null;
}
public boolean checkConnection() {
if (output == null)
return false;
try {
output.writeUTF("abc");
return true;
} catch (IOException e) {
return false;
}
}
#Override
protected void onProgressUpdate(Object[] values) {
}
}
And the Activity code:
public class LogInActivity extends AppCompatActivity {
Client client;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_log_in);
client = new Client();
client.execute();
//I used timer because it didn't work without it- That saied always 'not connected' message/Toast
new CountDownTimer(5, 0) {
public void onTick(long millisUntilFinished) {
}
public void onFinish() {
check();
}
}.start();
}
private void check() {
boolean isProcess;
isProcess = !checkConnection();
if (isProcess) {
AlertDialog.Builder builder = new AlertDialog.Builder(this, R.style.Theme_AppCompat_Dialog_Alert);
builder.setTitle(getResources().getString(R.string.app_name));
builder.setMessage("Unable connect to the library");
builder.setPositiveButton("Try Again", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialogInterface, int i) {
//See note 1.
check();
}
});
builder.setCancelable(false);
builder.show();
}
}
public boolean checkConnection() {
if (client.checkConnection()) {
Toast.makeText(getApplicationContext(), "Connected to the library", Toast.LENGTH_SHORT).show();
return true;
} else {
Toast.makeText(this, "Unable connect to the library", Toast.LENGTH_SHORT).show();
return false;
}
}
}
Note 1:
The problem is here.
This Dialog need to be shown until the server/Library connected.
If the server is on before the app turned on, the check() method works well and says 'Connected successful' and the Dialog doesn't show.
But if when the app started, the server was unreachable, and turned on later (And became reachable)- the check() method don't work and always shows the Dialog.
What is the problem?
By the way, I tried to restart the client AsyncTask Class, but i didn't succeed.
(I tried to do close(true) to it, and after do excute() to it again, but the cancel() method didn't worked, and was a error that said that after a AsyncTask Class excuted, it can't excute again)
Thanks.
You should not check for connectivity periodically (every couple of seconds like you do in this code).
Instead you should let the OS do this for you, it will be more reliable and more efficient in terms of battery and CPU.
Take a look at this answer

How to get network status changes with BroadcastReceiver?

When I change from wi-fi to 3g or vice versa the my AsyncTask will cause a error. So I want to trace this and restart the loading progress(or stop and proceed the asynctask if possible) when this happens. I looked it up on google and find that the BroadcastReceiver onReceive is called when this happens. The problem now is that I still don't get the exact moment when this happens.
Oncreate
registerReceiver(mConnReceiver,new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION));
AsyncTask point of error(it's called on the HttpClient line):
#Override
protected String doInBackground(String... params)
{
HttpClient httpclient = new DefaultHttpClient();
HttpPost httppost = new HttpPost(params[0]);
try
{
if(!isCancelled())//I have set this after I found the error
{
HttpResponse response = httpclient.execute(httppost);
jsonResult = inputStreamToString(
response.getEntity().getContent()).toString();
}
}
The broadcastreceiver
private BroadcastReceiver mConnReceiver = new BroadcastReceiver()
{
#Override
public void onReceive(Context context, Intent intent)
{
boolean noConnectivity = intent.getBooleanExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, false);
NetworkInfo changes = intent.getParcelableExtra(ConnectivityManager.EXTRA_NETWORK_INFO);
Log.w("current", "" + changes);
if(noConnectivity)
{
task.cancel(true);
task2.cancel(true);
task3.cancel(true);
}
Log.w("taskIsCanceled","" + task.isCancelled());
}
};
So I have two problems tracing the event of the error and restarting or stopping and proceeding the asynctaskes. I have 3 asynctaskes which take turns.
When I switch from 3g to wi-fi the noConnectivity boolean always returns that I have connection. While when I go from wi-fi to 3g it first returns that I dont and shortly after that I have(so that it connected).
You can use reflections to monitor mobile data changes.
public class NetworkStateReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
if(intent.getExtras() != null){
final ConnectivityManager mConnectivityManager = (ConnectivityManager)context.getSystemService(Context.CONNECTIVITY_SERVICE);
boolean mobileDataEnabled = false;
try{
Class cmClass = Class.forName(mConnectivityManager.getClass().getName());
Method method = cmClass.getDeclaredMethod("getMobileDataEnabled");
method.setAccessible(true); // Make the method callable
mobileDataEnabled = (Boolean)method.invoke(mConnectivityManager);
} catch(Exception e){
return;
}
Toast.makeText(BackroundService.this, "Data state changed", Toast.LENGTH_LONG).show();
}
}
}

onServiceConnected sometimes not called after bindService on some devices

I've looked at a number of other threads with similar titles, and none seem to cover my problem. So, here goes.
I'm using the Google market expansion files (apkx) library and sample code, with a few modifications. This code relies on receiving callbacks from a service which handles background downloading, licence checks etc.
I have a bug where the service doesn't get correctly attached, which results in a softlock. To make this more unhelpful, this bug never happens on some devices, but occurs about two thirds of the time on other devices. I believe it to be independent of Android version, certainly I have two devices running 2.3.4, one of which (a Nexus S) doesn't have the problem, the other (an HTC Evo 3D) does.
To attempt to connect to the service, bindService is called and returns true. OnBind then gets called as expected and returns a sensible value but (when the bug occurs) onServiceConnected doesn't happen (I've waited 20 minutes just in case).
Has anyone else seen anything like this? If not, any guesses for what I might have done to cause such behaviour? If no-one has any thoughts, I'll post some code tomorrow.
EDIT: Here's the relevant code. If I've missed anything, please ask.
Whilst adding this code, I found a minor bug. Fixing it caused the frequency of the problem I'm trying to solve to change from 2 times in 3 to about 1 time in 6 on the phone I'm testing it on; no idea about effects on other phones. This continues to suggest to me a race condition or similar, but I've no idea what with.
OurDownloaderActivity.java (copied and changed from Google sample code)
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
...
//Test the licence is up to date
//if (current stored licence has expired)
{
startLicenceCheck();
initializeDownloadUI();
return;
}
...
}
#Override
protected void onResume() {
if (null != mDownloaderClientStub) {
mDownloaderClientStub.connect(this);
}
super.onResume();
}
private void startLicenceCheck()
{
Intent launchIntent = OurDownloaderActivity.this
.getIntent();
Intent intentToLaunchThisActivityFromNotification = new Intent(OurDownloaderActivity
.this, OurDownloaderActivity.this.getClass());
intentToLaunchThisActivityFromNotification.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK |
Intent.FLAG_ACTIVITY_CLEAR_TOP);
intentToLaunchThisActivityFromNotification.setAction(launchIntent.getAction());
if (launchIntent.getCategories() != null) {
for (String category : launchIntent.getCategories()) {
intentToLaunchThisActivityFromNotification.addCategory(category);
}
}
// Build PendingIntent used to open this activity from Notification
PendingIntent pendingIntent = PendingIntent.getActivity(OurDownloaderActivity.this,
0, intentToLaunchThisActivityFromNotification,
PendingIntent.FLAG_UPDATE_CURRENT);
DownloaderService.startLicenceCheck(this, pendingIntent, OurDownloaderService.class);
}
initializeDownloadUI()
{
mDownloaderClientStub = DownloaderClientMarshaller.CreateStub
(this, OurDownloaderService.class);
//do a load of UI setup
...
}
//This should be called by the Stub's onServiceConnected method
/**
* Critical implementation detail. In onServiceConnected we create the
* remote service and marshaler. This is how we pass the client information
* back to the service so the client can be properly notified of changes. We
* must do this every time we reconnect to the service.
*/
#Override
public void onServiceConnected(Messenger m) {
mRemoteService = DownloaderServiceMarshaller.CreateProxy(m);
mRemoteService.onClientUpdated(mDownloaderClientStub.getMessenger());
}
DownloaderService.java (in Google market expansion library but somewhat edited )
//this is the onBind call that happens fine; the value it returns is definitely not null
#Override
public IBinder onBind(Intent paramIntent) {
return this.mServiceMessenger.getBinder();
}
final private IStub mServiceStub = DownloaderServiceMarshaller.CreateStub(this);
final private Messenger mServiceMessenger = mServiceStub.getMessenger();
//MY CODE, derived from Google's code
//I have seen the bug occur with a service started by Google's code too,
//but this code happens more often so is more repeatably related to the problem
public static void startLicenceCheck(Context context, PendingIntent pendingIntent, Class<?> serviceClass)
{
String packageName = serviceClass.getPackage().getName();
String className = serviceClass.getName();
Intent fileIntent = new Intent();
fileIntent.setClassName(packageName, className);
fileIntent.putExtra(EXTRA_LICENCE_EXPIRED, true);
fileIntent.putExtra(EXTRA_PENDING_INTENT, pendingIntent);
context.startService(fileIntent);
}
#Override
protected void onHandleIntent(Intent intent) {
setServiceRunning(true);
try {
final PendingIntent pendingIntent = (PendingIntent) intent
.getParcelableExtra(EXTRA_PENDING_INTENT);
if (null != pendingIntent)
{
mNotification.setClientIntent(pendingIntent);
mPendingIntent = pendingIntent;
} else if (null != mPendingIntent) {
mNotification.setClientIntent(mPendingIntent);
} else {
Log.e(LOG_TAG, "Downloader started in bad state without notification intent.");
return;
}
if(intent.getBooleanExtra(EXTRA_LICENCE_EXPIRED, false))
{
//we are here due to startLicenceCheck
updateExpiredLVL(this);
return;
}
...
}
}
//MY CODE, based on Google's, again
public void updateExpiredLVL(final Context context) {
Context c = context.getApplicationContext();
Handler h = new Handler(c.getMainLooper());
h.post(new LVLExpiredUpdateRunnable(c));
}
private class LVLExpiredUpdateRunnable implements Runnable
{
LVLExpiredUpdateRunnable(Context context) {
mContext = context;
}
final Context mContext;
#Override
public void run() {
setServiceRunning(true);
mNotification.onDownloadStateChanged(IDownloaderClient.STATE_LVL_UPDATING);
String deviceId = getDeviceId(mContext);
final APKExpansionPolicy aep = new APKExpansionPolicy(mContext,
new AESObfuscator(getSALT(), mContext.getPackageName(), deviceId));
// Construct the LicenseChecker with a Policy.
final LicenseChecker checker = new LicenseChecker(mContext, aep,
getPublicKey() // Your public licensing key.
);
checker.checkAccess(new LicenseCheckerCallback() {
...
});
}
}
DownloaderClientMarshaller.java (in Google market expansion library)
public static IStub CreateStub(IDownloaderClient itf, Class<?> downloaderService) {
return new Stub(itf, downloaderService);
}
and the Stub class from the same file:
private static class Stub implements IStub {
private IDownloaderClient mItf = null;
private Class<?> mDownloaderServiceClass;
private boolean mBound;
private Messenger mServiceMessenger;
private Context mContext;
/**
* Target we publish for clients to send messages to IncomingHandler.
*/
final Messenger mMessenger = new Messenger(new Handler() {
#Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_ONDOWNLOADPROGRESS:
Bundle bun = msg.getData();
if ( null != mContext ) {
bun.setClassLoader(mContext.getClassLoader());
DownloadProgressInfo dpi = (DownloadProgressInfo) msg.getData()
.getParcelable(PARAM_PROGRESS);
mItf.onDownloadProgress(dpi);
}
break;
case MSG_ONDOWNLOADSTATE_CHANGED:
mItf.onDownloadStateChanged(msg.getData().getInt(PARAM_NEW_STATE));
break;
case MSG_ONSERVICECONNECTED:
mItf.onServiceConnected(
(Messenger) msg.getData().getParcelable(PARAM_MESSENGER));
break;
}
}
});
public Stub(IDownloaderClient itf, Class<?> downloaderService) {
mItf = itf;
mDownloaderServiceClass = downloaderService;
}
/**
* Class for interacting with the main interface of the service.
*/
private ServiceConnection mConnection = new ServiceConnection() {
//this is the critical call that never happens
public void onServiceConnected(ComponentName className, IBinder service) {
// This is called when the connection with the service has been
// established, giving us the object we can use to
// interact with the service. We are communicating with the
// service using a Messenger, so here we get a client-side
// representation of that from the raw IBinder object.
mServiceMessenger = new Messenger(service);
mItf.onServiceConnected(
mServiceMessenger);
mBound = true;
}
public void onServiceDisconnected(ComponentName className) {
// This is called when the connection with the service has been
// unexpectedly disconnected -- that is, its process crashed.
mServiceMessenger = null;
mBound = false;
}
};
#Override
public void connect(Context c) {
mContext = c;
Intent bindIntent = new Intent(c, mDownloaderServiceClass);
bindIntent.putExtra(PARAM_MESSENGER, mMessenger);
if ( !c.bindService(bindIntent, mConnection, 0) ) {
if ( Constants.LOGVV ) {
Log.d(Constants.TAG, "Service Unbound");
}
}
}
#Override
public void disconnect(Context c) {
if (mBound) {
c.unbindService(mConnection);
mBound = false;
}
mContext = null;
}
#Override
public Messenger getMessenger() {
return mMessenger;
}
}
DownloaderServiceMarshaller.java (in Google market expansion library, unchanged)
private static class Proxy implements IDownloaderService {
private Messenger mMsg;
private void send(int method, Bundle params) {
Message m = Message.obtain(null, method);
m.setData(params);
try {
mMsg.send(m);
} catch (RemoteException e) {
e.printStackTrace();
}
}
public Proxy(Messenger msg) {
mMsg = msg;
}
#Override
public void requestAbortDownload() {
send(MSG_REQUEST_ABORT_DOWNLOAD, new Bundle());
}
#Override
public void requestPauseDownload() {
send(MSG_REQUEST_PAUSE_DOWNLOAD, new Bundle());
}
#Override
public void setDownloadFlags(int flags) {
Bundle params = new Bundle();
params.putInt(PARAMS_FLAGS, flags);
send(MSG_SET_DOWNLOAD_FLAGS, params);
}
#Override
public void requestContinueDownload() {
send(MSG_REQUEST_CONTINUE_DOWNLOAD, new Bundle());
}
#Override
public void requestDownloadStatus() {
send(MSG_REQUEST_DOWNLOAD_STATE, new Bundle());
}
#Override
public void onClientUpdated(Messenger clientMessenger) {
Bundle bundle = new Bundle(1);
bundle.putParcelable(PARAM_MESSENGER, clientMessenger);
send(MSG_REQUEST_CLIENT_UPDATE, bundle);
}
}
private static class Stub implements IStub {
private IDownloaderService mItf = null;
final Messenger mMessenger = new Messenger(new Handler() {
#Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_REQUEST_ABORT_DOWNLOAD:
mItf.requestAbortDownload();
break;
case MSG_REQUEST_CONTINUE_DOWNLOAD:
mItf.requestContinueDownload();
break;
case MSG_REQUEST_PAUSE_DOWNLOAD:
mItf.requestPauseDownload();
break;
case MSG_SET_DOWNLOAD_FLAGS:
mItf.setDownloadFlags(msg.getData().getInt(PARAMS_FLAGS));
break;
case MSG_REQUEST_DOWNLOAD_STATE:
mItf.requestDownloadStatus();
break;
case MSG_REQUEST_CLIENT_UPDATE:
mItf.onClientUpdated((Messenger) msg.getData().getParcelable(
PARAM_MESSENGER));
break;
}
}
});
public Stub(IDownloaderService itf) {
mItf = itf;
}
#Override
public Messenger getMessenger() {
return mMessenger;
}
#Override
public void connect(Context c) {
}
#Override
public void disconnect(Context c) {
}
}
/**
* Returns a proxy that will marshall calls to IDownloaderService methods
*
* #param ctx
* #return
*/
public static IDownloaderService CreateProxy(Messenger msg) {
return new Proxy(msg);
}
/**
* Returns a stub object that, when connected, will listen for marshalled
* IDownloaderService methods and translate them into calls to the supplied
* interface.
*
* #param itf An implementation of IDownloaderService that will be called
* when remote method calls are unmarshalled.
* #return
*/
public static IStub CreateStub(IDownloaderService itf) {
return new Stub(itf);
}

Android Local Service Architecture

I'm trying to implement a service to handle the communication with the server for the following code. I don't know much about the design architecture for these.
Here is my service class
public class BgService extends Service {
private static final String TAG = BgService.class.getSimpleName();
private Timer timer;
SendJsonRequest sjr;
private TimerTask updateTask = new TimerTask(){
#Override
public void run(){
try{
SendJsonRequest sjr = new SendJsonRequest();
sjr.carMake();
Log.i(TAG, "LOOK AT ME");
}
catch(Exception e){
Log.w(TAG,e);
}
}
};
#Override
public IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
return null;
}
#Override
public void onCreate(){
super.onCreate();
Log.i(TAG, "Service creating");
timer = new Timer("Server listening timer");
timer.schedule(updateTask, 1000L, 60*1000L);
}
#Override
public void onDestroy(){
super.onDestroy();
Log.i(TAG, "Service Destroying");
timer.cancel();
timer = null;
}
}
Here is my SendJsonRequest class
public class SendJsonRequest{
private static final String TAG = "SendJsonRequest";
private static String URL = "xxxxxxxxx";
private static String infoRec;
public static void createJsonObj(String path, Map x){
infoRec = CreateJsonRequest.jsonRequest(URL+path, x );
System.out.println(infoRec);
}
public static void carMake(){
String path = "/CarMake";
Map<String, Object> z = new HashMap<String,Object>();
z.put("Name", "Ford");
z.put("Model", "Mustang");
createJsonObj(path, z);
}
}
Here is my CreateJsonObject class
public class CreateJsonRequest {
public static String jsonRequest(String URL, Map<String,Object> params){
try{
DefaultHttpClient httpClient = new DefaultHttpClient();
HttpPost httpPost = new HttpPost(URL);
JSONObject holder = new JSONObject();
for (Map.Entry<String, Object> m : params.entrySet()){
try {
holder.put(m.getKey(), m.getValue());
}
catch (JSONException e) {
Log.e("Hmmmm", "JSONException : "+e);
}
}
StringEntity se;
se = new StringEntity(holder.toString());
httpPost.setEntity(se);
httpPost.setHeader("Accept", "text/json");
httpPost.setHeader("Content-type", "text/json");
HttpResponse response = (HttpResponse) httpClient.execute(httpPost);
HttpEntity entity = response.getEntity();
if(entity != null){
InputStream is = entity.getContent();
Header contentEncoding = response.getFirstHeader("Content-Encoding");
String result= convertToString(is);
is.close();
System.out.println(result);
return result;
}
}
catch(Exception e)
{
e.printStackTrace();
}
return null;
}
Sorry for the massive amount of code. How I implemented my service is obviously not correct, I just have no clue where to start to get a service handling the json requests to the server. Thanks in advance.
To be more clear, this did work on a button click, now I'm trying to get it to all run in the background with the service. So I guess my question is what goes where in the service?
My activity successfully starts the service, the service would work and print "look at me" to the logcat every minute. Then I added the try{ sjr.carMake()} and it catches an exception.
You can use a broadcast receiver. This is a way to have your code start at certain times indicated by Android OS - for example, you can have it start when Android finished booting up (this is where I run my services usually.
The best way is to use the AlarmManager class, and tell your service how often to run.
Tell us more about what you're trying to do, and what the problem is, and we can give you a more concise answer...
UPDATE:
Have you created an entry in the manifest.xml file for the service?
UPDATE
Here is how I'm doing it in my application. This is your "hook" to the OS. It's going to fire when it finishes booting (don't forget to make in entry in the manifest for this!)
public class TmBroadcastReceiver extends BroadcastReceiver {
#Override
public void onReceive(final Context context, final Intent bootintent) {
try{
Log.i("Taskmotion-ROBOT", "Robot Broadcast signal received on Boot. Trying to start Alarm scheduler");
Intent mServiceIntent = new Intent(context, ServiceAlarm.class);
context.startService(mServiceIntent);
}
catch(Exception e)
{
Log.i("Taskmotion", "Failed to start service...");
}
}
}
This Broadcast receiver calls a service that implements the AlarmManager class. The alarm manager sets up a schedule to run my service at a specified interval. Note that the alarms are deleted when the phone is shut down - but then recreated again when process is repeated as the phone boots back up and runs the BroadcastReceiver again.
public class ServiceAlarm extends Service {
private PendingIntent mAlarmSender;
#Override
public void onCreate() {
try{
Log.i("Taskmotion-ROBOT", "Setting Service Alarm Step 1");
mAlarmSender = PendingIntent.getService(this.getApplicationContext(),
0, new Intent(this.getApplicationContext(), BackgroundService.class), 0);
}
catch(Exception e)
{
Log.i("Taskmotion-ROBOT", "Problem at 1 :" + e.toString());
}
long firstTime = SystemClock.elapsedRealtime();
Log.i("Taskmotion-ROBOT", "Setting Service Alarm Step 2");
// Schedule the alarm!
AlarmManager am = (AlarmManager)getSystemService(ALARM_SERVICE);
am.setRepeating(AlarmManager.ELAPSED_REALTIME,
firstTime, AlarmManager.INTERVAL_HOUR, mAlarmSender);
this.stopSelf();
}
#Override
public IBinder onBind(Intent arg0) {
// TODO Auto-generated method stub
return null;
}
}
I haven't refactored this code yet, it was my first go at it. I see now that I'm looking at it again that I could probably do the scheduling inside the BroadcastReceiver, but for the sake of getting you something that works, I'll continue.
As indicated by AlarmManager.INTERVAL_HOUR, my service will run once an hour. The service that I want to run is defined in the pendingIntent (BackgroundService.class). This is where you put your own service class.
I reworked your service class for you, and removed the timer (functionality replaced by the BroadcastReceiver & AlarmManager).
public class BgService extends Service {
private static final String TAG = BgService.class.getSimpleName();
SendJsonRequest sjr;
#Override
public IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
return null;
}
#Override
public void onCreate(){
super.onCreate();
Log.i(TAG, "Service creating");
//DO YOUR WORK WITH YOUR JSON CLASS HERE
//**************************************
//Make sure to call stopSelf() or your service will run in the background, chewing up
//battery life like rocky mountain oysters!
this.stopSelf();
}
#Override
public void onDestroy(){
super.onDestroy();
}
}

Categories

Resources