Service makes the UI freeze - android

My application has a database where queued items will be stored if it doesn't notice any connectivity to Wifi or mobile network, like 3G og 4G. My problem is:
I have a BroadcastReciever which is registrered this way:
#Override
public void onResume() {
super.onResume();
if(networkMonitor == null)
networkMonitor = new CaseQueueReceiver();
IntentFilter filter = new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION);
registerReceiver(networkMonitor, filter);
}
My BroadcastReciever is starting a Service to pick out items from this database and send them over either a webservice or mail. My BrodcastReciever is like this:
public class CaseQueueReceiver extends BroadcastReceiver {
boolean available;
QueueDB queueDB;
int count;
public CaseQueueReceiver() {
queueDB = new QueueDB(ContextHelper.context());
count = queueDB.countUnsentCases();
}
#Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(ConnectivityManager.CONNECTIVITY_ACTION)) {
NetworkInfo info = intent.getParcelableExtra(ConnectivityManager.EXTRA_NETWORK_INFO);
String typeName = info.getTypeName();
String subtypeName = info.getSubtypeName();
available = info.isAvailable();
Log.i("Network Monitor", "Network Type: " + typeName + ", subtype: " + subtypeName + ", available: " + available);
if (available && count > 0) {
Intent service = new Intent(context, SendQueuedCasesService.class);
context.startService(service);
}
}
}
}
As you can see if the internet connection is available and the database contains something, I will start a service to send these items in the database.
My Service looks like this:
public class SendQueuedCasesService extends Service {
boolean available;
DatabaseHandler db;
QueueDB queueDB;
HashMap<String, String> queueHashMap;
CreateTransaction transaction;
String pcn, file;
int sent;
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onCreate() {
super.onCreate();
db = new DatabaseHandler(ContextHelper.context());
queueDB = new QueueDB(ContextHelper.context());
queueHashMap = new HashMap<String, String>();
transaction = new CreateTransaction(ContextHelper.context());
queueDB = new QueueDB(this);
int count = queueDB.countUnsentCases();
Log.w("Unsent cases count: ", Integer.toString(count));
if (count > 0) {
queueHashMap = queueDB.getUnsetCases();
Iterator<Entry<String, String>> it = queueHashMap.entrySet().iterator();
while(it.hasNext()) {
Map.Entry pairs = it.next();
pcn = pairs.getKey().toString();
Log.w("PCN in Queued Cases: ", pcn);
file = pairs.getKey().toString();
Log.w("Nist File Path: ", file);
try
{
sent = transaction.createTransaction(pcn, file);
if(sent == -2)
{
queueDB.deleteUnSentCase(pcn);
db.updateDB(pcn, "");
}
else
break;
} catch(MailException e) {
Log.e("MailException: ", e.getMessage());
}
}
Intent i = new Intent(this, WorkflowChooser.getCurrentWorkflow());
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(i);
}
}
}
My problem is that when I start the application this will block the UI for a while and then show the UI. A other problems is that this service isn't triggered if I turn off and the on the WiFi again. Why is this happening?

My problem is that when I start the application this will block the UI for a while and then show the UI.
Service runs in UI thread. That's the problem.

You can try to use IntentService. It will handle all the threading for you automatically.

You should create an AsyncTask or a new thread which handles the Service.

Related

Update view when a push notification is received

I would like to update a view from within an open activity when the device receives a push notification.
When a push notification is received the updateBalance function is executed,
a mysql database is queried and an amount is returned.
public class MyFirebaseMessagingService extends FirebaseMessagingService {
private void updateBalance(String messageBody) {
h1 = new Handler(Looper.getMainLooper()) {
#Override
public void handleMessage(Message msg) {
bb = msg.getData();
String str = bb.getString("result");
Log.d(TAG,str);
Message msg=handler.obtainMessage()
}
};
t = new Thread(new MyRunnable(h1));
t.start();
try {
t.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
I have another class
public class MyRunnable implements Runnable {
private Handler h2;
public MyRunnable(Handler h) {
this.h2 = h;
}
#Override
public void run() {
String name = "w12";
BalanceActivity NB = new BalanceActivity(name);
Message m = Message.obtain();
Bundle b = new Bundle();
b.putString("result", "10");
m.setData(b);
h2.sendMessage(m);
}
}
I have a MainActivity that I would like to update after the amount is returned. How would I do this possibly with another Handler and Runnable.
public class MainActivity extends Activity {
TextView TV = (TextView) findViewById(package.name.R.id.Balance);
}
Try to check your activity is currently in foreground. if yes then create method where you can update your view.
public static boolean isServiceRunning(Context context) {
Log.i(TAG, "Checking if service is running");
ActivityManager activityManager = (ActivityManager)context.getSystemService(Context.ACTIVITY_SERVICE);
List<RunningServiceInfo> services = activityManager.getRunningServices(Integer.MAX_VALUE);
boolean isServiceFound = false;
for (int i = 0; i < services.size(); i++) {
if (Constants.PACKAGE.equals(services.get(i).service.getPackageName())){
if (Constants.BACKGROUND_SERVICE_CLASS.equals(services.get(i).service.getClassName())){
isServiceFound = true;
}
}
}
Log.i(TAG, "Service was" + (isServiceFound ? "" : " not") + " running");
return isServiceFound;
}
Make use of Broadcast Receivers. Register local broadcast receiver in activity. Broadcast data when notification received.

How to make app lock app in android?

I have to develop an app locker for Android where the user can block apps and other users can not access these apps without an access key.
I have installed an app but I don't know how to lock this app.
Please suggest me something.
This is not how stack overflow works. You can not ask a complete solution without even trying anything.
For the most basic version of your app, you need to perform three functions.
Get a list of all the installed apps on device and show them in a ListView with check box. If the user checks any app, add the app to a different list say BlockedAppsList(which will be the list of apps which user wants to block).
You can get all the apps installed using the following code:
final PackageManager pm = getPackageManager();
//get a list of installed apps.
List<ApplicationInfo> packages = pm.getInstalledApplications(PackageManager.GET_META_DATA);
for (ApplicationInfo packageInfo : packages) {
Log.d(TAG, "Installed package :" + packageInfo.packageName);
Log.d(TAG, "Source dir : " + packageInfo.sourceDir);
Log.d(TAG, "Launch Activity :" + pm.getLaunchIntentForPackage(packageInfo.packageName));
}
Check the which is the current opened app. You can check by using this code:
ActivityManager am = (ActivityManager) this.getSystemService(ACTIVITY_SERVICE);
List l = am.getRecentTasks(1, ActivityManager.RECENT_WITH_EXCLUDED);
Iterator i = l.iterator();
PackageManager pm = this.getPackageManager();
while (i.hasNext()) {
ActivityManager.RunningAppProcessInfo info = (ActivityManager.RunningAppProcessInfo)(i.next());
try {
CharSequence c = pm.getApplicationLabel(pm.getApplicationInfo(
info.processName, PackageManager.GET_META_DATA));
Log.w("LABEL", c.toString());
} catch (Exception e) {
// Name Not FOund Exception
}
}
Now check if the current app is present in the BlockedAppsList, if it is there, you can show any screen with a block message.
good luck!
Assuming that you store the package names of locked apps in a table called:
locks
and you want to call an activity named
PasswordActivity
when ever the users launch a locked app,
you can implement a polling mechanism like below:
public class CheckAppLaunchThread extends Thread {
private Context context;
private Handler handler;
private ActivityManager actMan;
private int timer = 100;
public static final String TAG = "App Thread";
public static String lastUnlocked;
// private String lastUnlocked;
public CheckAppLaunchThread(Handler mainHandler, Context context) {
this.context = context;
this.handler = mainHandler;
actMan = (ActivityManager) context
.getSystemService(Context.ACTIVITY_SERVICE);
this.setPriority(MAX_PRIORITY);
}
#Override
public void run() {
context.startService(new Intent(context, AppLockService.class));
Looper.prepare();
String prevTasks;
String recentTasks = "";
prevTasks = recentTasks;
Log.d("Thread", "Inside Thread");
while (true) {
try {
String topPackageName = "";
if(Build.VERSION.SDK_INT >= 21) {
UsageStatsManager mUsageStatsManager = (UsageStatsManager) context.getSystemService("usagestats");
long time = System.currentTimeMillis();
// We get usage stats for the last 10 seconds
List<UsageStats> stats = mUsageStatsManager.queryUsageStats(UsageStatsManager.INTERVAL_DAILY, time - 1000*5, time);
if(stats != null) {
SortedMap<Long,UsageStats> mySortedMap = new TreeMap<Long,UsageStats>();
for (UsageStats usageStats : stats) {
mySortedMap.put(usageStats.getLastTimeUsed(),usageStats);
}
if(mySortedMap != null && !mySortedMap.isEmpty()) {
topPackageName = mySortedMap.get(mySortedMap.lastKey()).getPackageName();
}
}
}
else {
topPackageName = actMan.getRunningAppProcesses().get(0).processName;
}
recentTasks = topPackageName;
Thread.sleep(timer);
if (recentTasks.length()==0 || recentTasks.equals(
prevTasks)) {
} else {
if (isAppLocked(recentTasks)) {
Log.d(TAG, "Locked " + recentTasks);
handler.post(new RequestPassword(context, recentTasks));
}
}
} catch (InterruptedException e) {
e.printStackTrace();
}
prevTasks = recentTasks;
}
}
class ToastRunnable implements Runnable {
String message;
public ToastRunnable(String text) {
message = text;
}
#Override
public void run() {
Toast.makeText(context, message, Toast.LENGTH_SHORT).show();
}
}
class RequestPassword implements Runnable {
private Context mContext;
private String pkgName;
public RequestPassword(Context mContext, String pkgName) {
this.mContext = mContext;
this.pkgName = pkgName;
}
#Override
public void run() {
Intent passwordAct = new Intent(context, PasswordActivity.class);
passwordAct.putExtra("PACKAGE_NAME", pkgName);
passwordAct.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK|Intent.FLAG_ACTIVITY_SINGLE_TOP);
this.mContext.startActivity(passwordAct);
}
}
private boolean isAppLocked(String packageName) {
if (packageName.equals(PasswordActivity.lastUnlocked)) {
return false;
}
PasswordActivity.lastUnlocked = null;
DatabaseHelper dbHelper = new DatabaseHelper(context);
SQLiteDatabase db = dbHelper.getReadableDatabase();
Cursor cursor = db.rawQuery("SELECT * FROM locks WHERE package_name=\'"
+ packageName + "\'", null);
boolean isLocked = false;
if (cursor.moveToNext()) {
isLocked = true;
}
cursor.close();
db.close();
dbHelper.close();
return isLocked;
}
}
Now you must call the above code from your service like this:
#Override
public void onCreate() {
handler = new Handler(getMainLooper());
context = getApplicationContext();
launchChecker = new CheckAppLaunchThread(handler, context);
super.onCreate();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
while (true) {
if (!launchChecker.isAlive())
launchChecker.start();
return START_STICKY;
}
}
Warning: Since Oreo, google has restricted background services and you must figure out a way to always keep your service alive. (that is not the scope of this question) for a clue on this, consider scheduling a JobService and a broadcast receiver that would reschedule your service when ever the android kills it.

android background service static field send same msg twice

I have a big problem that i couldn't find solution. Need your help.
When i try to send just one message in activity using service , it works.
But when i try to send 2 message following another( that means one after other ) , sends the message twice with the same publishTopic2 and pushMsg2.
Code is :
PushService.actionPush(getApplicationContext(),publishTopic1,pushMsg1);
PushService.actionPush(getApplicationContext(),publishTopic2,pushMsg2);
1- is this from the wrong usage of syncronized keyword ?
2- is it possibe to send two msg after another without
public class PushService
extends Service
{
// this is the log tag
public static final String TAG = "DemoPushService";
public static String IncomingText = "";
private static String PushMesaj = "";
// the IP address, where your MQTT broker is running.
private static final String MQTT_HOST = "";
// the port at which the broker is running.
private static int MQTT_BROKER_PORT_NUM = 1883;
// Let's not use the MQTT persistence.
private static MqttClientPersistence MQTT_PERSISTENCE = null;
// We don't need to remember any state between the connections, so we use a
// clean start.
private static boolean MQTT_CLEAN_START = true;
// Let's set the internal keep alive for MQTT to 15 mins. I haven't tested
// this value much. It could probably be increased.
private static short MQTT_KEEP_ALIVE = 60 * 15;
// Set quality of services to 0 (at most once delivery), since we don't want
// push notifications
// arrive more than once. However, this means that some messages might get
// lost (delivery is not guaranteed)
// private static int[] MQTT_QUALITIES_OF_SERVICE = { 0 } ;
private static int MQTT_QUALITY_OF_SERVICE = 2;
// The broker should not retain any messages.
// private static boolean MQTT_RETAINED_PUBLISH = false;
// MQTT client ID, which is given the broker. In this example, I also use
// this for the topic header.
// You can use this to run push notifications for multiple apps with one
// MQTT broker.
public static String MQTT_CLIENT_ID = "begining";
public static String SUBSCRIBE_TOPIC = "begining";
private static String PUBLISH_TOPIC = "begining";
// These are the actions for the service (name are descriptive enough)
private static final String ACTION_START = MQTT_CLIENT_ID + ".START";
private static final String ACTION_STOP = MQTT_CLIENT_ID + ".STOP";
private static final String ACTION_SUBSCRIBE = MQTT_CLIENT_ID
+ ".SUBSCRIBE";
private static final String ACTION_PUBLISH = MQTT_CLIENT_ID + ".PUBLISH";
private static final String ACTION_KEEPALIVE = MQTT_CLIENT_ID
+ ".KEEP_ALIVE";
private static final String ACTION_PUSHMESSAGE = MQTT_CLIENT_ID
+ ".PUSH_MESSAGE";
private static final String ACTION_PUSHMESSAGE2 = MQTT_CLIENT_ID
+ ".PUSH_MESSAGE";
private static final String ACTION_RECONNECT = MQTT_CLIENT_ID
+ ".RECONNECT";
// Connection log for the push service. Good for debugging.
private ConnectionLog mLog;
// Connectivity manager to determining, when the phone loses connection
private ConnectivityManager mConnMan;
// Notification manager to displaying arrived push notifications
private NotificationManager mNotifMan;
// Whether or not the service has been started.
private boolean mStarted;
// This the application level keep-alive interval, that is used by the
// AlarmManager
// to keep the connection active, even when the device goes to sleep.
private static final long KEEP_ALIVE_INTERVAL = 1000 * 60 * 28;
// Retry intervals, when the connection is lost.
private static final long INITIAL_RETRY_INTERVAL = 1000 * 10;
private static final long MAXIMUM_RETRY_INTERVAL = 1000 * 60 * 30;
// Preferences instance
private SharedPreferences mPrefs;
// We store in the preferences, whether or not the service has been started
public static final String PREF_STARTED = "isStarted";
// We also store the deviceID (target)
public static final String PREF_DEVICE_ID = "deviceID";
// We store the last retry interval
public static final String PREF_RETRY = "retryInterval";
// Notification title
public static String NOTIF_TITLE = "Hey !!!";
// Notification id
private static final int NOTIF_CONNECTED = 0;
// This is the instance of an MQTT connection.
private MQTTConnection mConnection;
private long mStartTime;
private static clsUser yourInfo;
public static clsOnlineUsers onlineUsers;
private static clsUser myInfo;
// Static method to start the service
public static void actionStart(Context ctx)
{
Intent i = new Intent(ctx, PushService.class);
i.setAction(ACTION_START);
ctx.startService(i);
}
public static void actionSubscribe(Context ctx)
{
Intent i = new Intent(ctx, PushService.class);
i.setAction(ACTION_SUBSCRIBE);
ctx.startService(i);
}
public static void actionPublish(Context ctx)
{
Intent i = new Intent(ctx, PushService.class);
i.setAction(ACTION_PUBLISH);
ctx.startService(i);
}
// Static method to stop the service
public static void actionStop(Context ctx)
{
Intent i = new Intent(ctx, PushService.class);
i.setAction(ACTION_STOP);
ctx.startService(i);
}
// Static method to send a keep alive message
public static void actionPing(Context ctx)
{
Intent i = new Intent(ctx, PushService.class);
i.setAction(ACTION_KEEPALIVE);
ctx.startService(i);
}
public static void actionPush(Context ctx, String publishTopic,
String pushMsg)
{
PUBLISH_TOPIC = publishTopic;
PushMesaj = pushMsg;
Intent i = new Intent(ctx, PushService.class);
i.setAction(ACTION_PUSHMESSAGE);
ctx.startService(i);
}
#Override
public void onCreate()
{
super.onCreate();
log("Creating service");
mStartTime = System.currentTimeMillis();
try {
mLog = new ConnectionLog();
Log.i(TAG, "Opened log at " + mLog.getPath());
} catch (IOException e) {
Log.e(TAG, "Failed to open log", e);
}
// Get instances of preferences, connectivity manager and notification
// manager
mPrefs = getSharedPreferences(TAG, MODE_PRIVATE);
mConnMan = (ConnectivityManager) getSystemService(CONNECTIVITY_SERVICE);
mNotifMan = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
mPrefs.edit().putLong(PREF_RETRY, INITIAL_RETRY_INTERVAL).commit();
mPrefs.edit().putBoolean(PREF_STARTED, false).commit();
/*
* If our process was reaped by the system for any reason we need to
* restore our state with merely a call to onCreate. We record the last
* "started" value and restore it here if necessary.
*/
handleCrashedService();
}
// This method does any necessary clean-up need in case the server has been
// destroyed by the system
// and then restarted
private void handleCrashedService()
{
if (wasStarted() == true) {
log("Handling crashed service...");
// stop the keep alives
// stopKeepAlives();
// Do a clean start
start();
}
}
#Override
public void onDestroy()
{
log("Service destroyed (started=" + mStarted + ")");
// Stop the services, if it has been started
if (mStarted == true) {
stop();
}
try {
if (mLog != null)
mLog.close();
} catch (IOException e) {
}
}
#Override
public synchronized void onStart(Intent intent, int startId)
{
super.onStart(intent, startId);
log("Service started with intent=" + intent);
if (intent == null) {
start();
return;
}
// Do an appropriate action based on the intent.
if (intent.getAction().equals(ACTION_STOP) == true) {
stop();
stopSelf();
} else if (intent.getAction().equals(ACTION_START) == true) {
start();
} else if (intent.getAction().equals(ACTION_KEEPALIVE) == true) {
keepAlive();
} else if (intent.getAction().equals(ACTION_PUBLISH) == true) {
publish();
} else if (intent.getAction().equals(ACTION_SUBSCRIBE) == true) {
subscribe();
} else if (intent.getAction().equals(ACTION_PUSHMESSAGE) == true) {
sendMessage();
} else if (intent.getAction().equals(ACTION_RECONNECT) == true) {
if (isNetworkAvailable()) {
reconnectIfNecessary();
}
}
}
private void subscribe()
{
// TODO Auto-generated method stub
try {
mConnection.subscribeToTopic(SUBSCRIBE_TOPIC);
} catch (MqttException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
private void publish()
{
try {
// Send a keep alive, if there is a connection.
if (mStarted == true && mConnection != null) {
mConnection.sendPushMessage(1);
}
} catch (MqttException e) {
log("MqttException: "
+ (e.getMessage() != null ? e.getMessage() : "NULL"), e);
mConnection.disconnect();
mConnection = null;
cancelReconnect();
}
}
#Override
public IBinder onBind(Intent intent)
{
return null;
}
// log helper function
private void log(String message)
{
log(message, null);
}
private void log(String message, Throwable e)
{
if (e != null) {
Log.e(TAG, message, e);
} else {
Log.i(TAG, message);
}
if (mLog != null) {
try {
mLog.println(message);
} catch (IOException ex) {
}
}
}
// Reads whether or not the service has been started from the preferences
private boolean wasStarted()
{
return mPrefs.getBoolean(PREF_STARTED, false);
}
// Sets whether or not the services has been started in the preferences.
private void setStarted(boolean started)
{
mPrefs.edit().putBoolean(PREF_STARTED, started).commit();
mStarted = started;
}
private synchronized void start()
{
log("Starting service...");
// Do nothing, if the service is already running.
if (mStarted == true) {
Log.w(TAG, "Attempt to start connection that is already active");
return;
}
// Establish an MQTT connection
connect();
// Register a connectivity listener
registerReceiver(mConnectivityChanged, new IntentFilter(
ConnectivityManager.CONNECTIVITY_ACTION));
}
private synchronized void stop()
{
// Do nothing, if the service is not running.
if (mStarted == false) {
Log.w(TAG, "Attempt to stop connection not active.");
return;
}
// Save stopped state in the preferences
setStarted(false);
// Remove the connectivity receiver
unregisterReceiver(mConnectivityChanged);
// Any existing reconnect timers should be removed, since we explicitly
// stopping the service.
cancelReconnect();
// Destroy the MQTT connection if there is one
if (mConnection != null) {
mConnection.disconnect();
mConnection = null;
}
}
private clsUser setUserInfo(String deviceId)
{
clsUser u = new clsUser();
dbUser du = new dbUser(getApplicationContext(), dbUser.DATABASE_NAME,
null, dbUser.DATABASE_VERSION);
Cursor c1 = du.Getby(null, null, null, null, null, null, null, null,
null, deviceId, null, null, null);
u = du.setProperties(c1);
c1.close();
du.close();
return u;
}
//
private synchronized void connect()
{
log("Connecting...");
// Create a new connection only if the device id is not NULL
if (MQTT_CLIENT_ID == null) {
log("Device ID not found.");
} else {
try {
MQTT_CLIENT_ID = Config.id(getApplication());
myInfo = setUserInfo(MQTT_CLIENT_ID);
mConnection = new MQTTConnection(MQTT_HOST, "user/"
+ MQTT_CLIENT_ID + "/#");
} catch (MqttException e) {
// Schedule a reconnect, if we failed to connect
log("MqttException: "
+ (e.getMessage() != null ? e.getMessage() : "NULL"));
if (!isNetworkAvailable()) {
scheduleReconnect(mStartTime);
}
}
setStarted(true);
}
}
private synchronized void keepAlive()
{
try {
// Send a keep alive, if there is a connection.
if (mStarted == true && mConnection != null) {
mConnection.sendKeepAlive();
}
} catch (MqttException e) {
log("MqttException: "
+ (e.getMessage() != null ? e.getMessage() : "NULL"), e);
mConnection.disconnect();
mConnection = null;
cancelReconnect();
}
}
private void sendMessage()
{
try {
// Send a keep alive, if there is a connection.
if (mStarted == true && mConnection != null) {
mConnection.sendPushMessage(); // this does the job
}
} catch (MqttException e) {
log("MqttException: "
+ (e.getMessage() != null ? e.getMessage() : "NULL"), e);
mConnection.disconnect();
mConnection = null;
cancelReconnect();
}
}
// Schedule application level keep-alives using the AlarmManager
private void startKeepAlives()
{
Intent i = new Intent();
i.setClass(this, PushService.class);
i.setAction(ACTION_KEEPALIVE);
PendingIntent pi = PendingIntent.getService(this, 0, i, 0);
AlarmManager alarmMgr = (AlarmManager) getSystemService(ALARM_SERVICE);
alarmMgr.setRepeating(AlarmManager.RTC_WAKEUP,
System.currentTimeMillis() + KEEP_ALIVE_INTERVAL,
KEEP_ALIVE_INTERVAL, pi);
}
// Remove all scheduled keep alives
private void stopKeepAlives()
{
Intent i = new Intent();
i.setClass(this, PushService.class);
i.setAction(ACTION_KEEPALIVE);
PendingIntent pi = PendingIntent.getService(this, 0, i, 0);
AlarmManager alarmMgr = (AlarmManager) getSystemService(ALARM_SERVICE);
alarmMgr.cancel(pi);
}
// We schedule a reconnect based on the starttime of the service
public void scheduleReconnect(long startTime)
{
// the last keep-alive interval
long interval = mPrefs.getLong(PREF_RETRY, INITIAL_RETRY_INTERVAL);
// Calculate the elapsed time since the start
long now = System.currentTimeMillis();
long elapsed = now - startTime;
log(String.valueOf(elapsed));
// Set an appropriate interval based on the elapsed time since start
if (elapsed < interval) {
interval = Math.min(interval * 4, MAXIMUM_RETRY_INTERVAL);
} else {
interval = INITIAL_RETRY_INTERVAL;
}
log("Rescheduling connection in " + interval + "ms.");
// Save the new internval
mPrefs.edit().putLong(PREF_RETRY, interval).commit();
// Schedule a reconnect using the alarm manager.
Intent i = new Intent();
i.setClass(this, PushService.class);
i.setAction(ACTION_RECONNECT);
PendingIntent pi = PendingIntent.getService(this, 0, i, 0);
AlarmManager alarmMgr = (AlarmManager) getSystemService(ALARM_SERVICE);
alarmMgr.set(AlarmManager.RTC_WAKEUP, now + interval, pi);
}
// Remove the scheduled reconnect
public void cancelReconnect()
{
Intent i = new Intent();
i.setClass(this, PushService.class);
i.setAction(ACTION_RECONNECT);
PendingIntent pi = PendingIntent.getService(this, 0, i, 0);
AlarmManager alarmMgr = (AlarmManager) getSystemService(ALARM_SERVICE);
alarmMgr.cancel(pi);
}
private synchronized void reconnectIfNecessary()
{
if (mStarted == true && mConnection == null) {
log("Reconnecting...");
connect();
}
}
private class MQTTConnection
implements MqttCallback
{
MqttClient mqttClient = null;
MqttConnectOptions conOpt;
String myDeviceId;
// Creates a new connection given the broker address and initial topic
public MQTTConnection(String brokerHostName, String initTopic)
throws MqttException
{
// Create connection spec
}
private void publish(String topicName, int qos, String payload,
boolean retained) throws MqttException
{
}
/*
* Sends a message to the message broker, requesting that it be
* published to the specified topic.
*/
private void publishToTopic(String topicName, String message)
throws MqttException
{
if ((mqttClient == null) || (mqttClient.isConnected() == false)) {
// quick sanity check - don't try and publish if we don't have
// a connection
log("No connection to public to");
} else {
publish(topicName, MQTT_QUALITY_OF_SERVICE, message, false);
}
}
/*
* Send a request to the message broker to be sent messages published
* with the specified topic name. Wildcards are allowed.
*/
private void subscribeToTopic(String topicName1) throws MqttException
{
if ((mqttClient == null) || (mqttClient.isConnected() == false)) {
// quick sanity check - don't try and subscribe if we don't have
// a connection
log("Subscribtion failed : Connection error" + "No connection");
} else {
mqttClient.subscribe(topicName1, 0);
Log.v(TAG, "Subscribe To : " + topicName1);
}
}
public void sendPushMessage(int sira) throws MqttException
{
publishToTopic(PUBLISH_TOPIC, PushMesaj);
}
}
}
When you call actionPush(), it does the following:
PUBLISH_TOPIC = publishTopic;
PushMesaj = pushMsg;
which saves the arguments in private static variables and then calls startService. If you do this twice, you will overwrite the private static variables with the second set of arguments.
You need to understand that the call to startService() is not synchronous. It doesn't start the service immediately and call onStart() before the method returns. The service will get started and the call to onStart() will occur sometime later (timing isn't under your control here).
You want to put these parameters in the Intent that you use to start the service, and retrieve the arguments from the Intent in onStart(). You can't reliably use static variables to do this.
EDIT: ADD CODE DETAILS
Change actionPush() to this:
static final String EXTRA_TOPIC = "EXTRA_TOPIC";
static final String EXTRA_MESSAGE = "EXTRA_MESSAGE";
public static void actionPush(Context ctx, String publishTopic,
String pushMsg)
{
Intent i = new Intent(ctx, PushService.class);
i.setAction(ACTION_PUSHMESSAGE);
i.putExtra(EXTRA_TOPIC, publishTopic);
i.putExtra(EXTRA_MESSAGE, pushMsg);
ctx.startService(i);
}
and in onStart() you can get the arguments out of the Intent like this:
String topic = intent.getStringExtra(EXTRA_TOPIC);
String message = intent.getStringExtra(EXTRA_MESSAGE);
I'm not going to rewrite the entire program for you. You'll have to figure out now what to do with the arguments. Maybe you can now store them in private static variables, but I don't know enough about your program to be able to say if that will work. A better solution would be to pass the arguments through the various methods that you've defined until they get down to the methods where they are used.

How to create a Service to download XMPP contacts?

In my app i am using XMPP for chatting, in this i have to create a service to download all the contacts from the XMPP sever to my DataBase. i am doing like below code now, it takes much time to get all contacts, i don't have interest user let to wait to complete download all contacts.
Due to this reason i want to use a service to do this job in background and then store them in DB, i will use provider to update the contacts if database have a new contact.
I know how to create a service but here i am unable to pass parameter like Roster and XMPP connection to service, these parameters are required to download contacts from XMPP server.
please anybody guide me how to solve this problem.
this is the code i am using now.
public class GmailXmppClient {
public GmailXmppClient(ChatAccountsFragment _fragment, Context _context) {
this.fragment = _fragment;
this.context = _context;
ConnectionConfiguration config = new ConnectionConfiguration(server_host, SERVER_PORT, SERVICE_NAME);
m_connection = new XMPPConnection(config);
try {
m_connection.connect();
} catch (XMPPException e) {
e.printStackTrace();
}
}
public Roster getRoster() {
Log.i(TAG, " getRoster ");
return m_connection.getRoster();
}
public boolean Login(String uname, String pass ) throws XMPPException {
m_connection.login(uname, pass);
this.fragment.Gtalk_logInComplete(uname, m_connection);
this.setPacketFilters();
Presence presence = new Presence(Presence.Type.available);
Log.i("ID", "" + presence);
m_connection.sendPacket(presence);
return true;
}
public void disconnect() {
m_connection.disconnect();
}
}
From the above code after this code
this.fragment.Gtalk_logInComplete(uname, m_connection);
this code will run to get contacts from xmpp server
private void getConts() {
Roster roster = colors_xmpp_client.getRoster();
String file_name;
for (RosterEntry entry : roster.getEntries()) {
if (entry.getType() == ItemType.to || entry.getType() == ItemType.both) {
boolean yes = Contact_data_source.checkUsername(entry.getUser());
Log.i(TAG, "Con=" + yes);
if (!yes) {
String na = entry.getUser();
String[] me = na.split("#");
Bitmap buddy_img = buddyImage(entry, _connection);
if (buddy_img != null)
file_name = Store(buddy_img);
else
file_name = "";
if (entry.getName() == null)
Contact_data_source.createContact( entry.getUser(), entry.getUser(), Uname, file_name, UsedStrings.SipAccount, me[0] );
else
Contact_data_source.createContact( entry.getName(), entry.getUser(), Uname, file_name, UsedStrings.SipAccount, me[0] );
} else {
Log.i(TAG, "Con=exist");
}
}
}
return null;
}
You can use the following flow:
1) start Activity, bind RosterService
2) register ContentObserver with desired context (application context, or activity)
context.getContentResolver().registerContentObserver(uriRosterChanged, true, contentObserver);
3) send this context and contentObserver to RosterService
4) in service: get contact and store it into db and !!! >>
5) in service: context.getContentResolver().notifyChange(uriRosterChanged, contentObserver)
6) repeat i.4 for the next contact
i.5 -> will fire contentObserver.onChange method, so here you may refresh your contacts list
How 2 send parameters to service 2 ways described with extras and direct method call (setRosterNConnection()):
Activity code:
...
RosterService mService;
#Override public void onCreate(Bundle savedInstanceState) {
...
Intent intent = new Intent(this, RosterService.class);
intent.putExtra("Key", "Value");
bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
...
}
...
Roster mRoster ;
XMPPConnection mConnection;
...
private ServiceConnection mConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className,
IBinder service) {
LocalBinder binder = (LocalBinder) service;
mService = binder.getService();
mService.setRosterNConnection(mRoster, mConnection);
mService.doJob();
}
public void onServiceDisconnected(ComponentName arg0) {
mService = null;
}
};
...
RosterService code:
// some class LocalBinder extends Binder{...} if some needs
private LocalBinder mBinder = new LocalBinder(); // class LocalBinder extends Binder{...}
...
#Override
public IBinder onBind(Intent intent) {
Bundle extras = intent.getExtras();
if(extras == null)
Log.d("RosterService","extras is empty");
else
{
Log.d("RosterService","extras not empty");
String key = (String) extras.get("Key");
...
}
return mBinder;
}
...
public void setRosterNConnection (Roster roster , XMPPConnection connection){
...
}
...
public void doJob(){
// get and save contacts
...
}
Maybe you can do it in a AsyncTask.
AsyncTask just will do the work on another thread, just if user close your activity the asyncTask will be stopped.

Android - Passing changing data from BroadcastReceiver to another Object?

I have a Wifi class that has a couple of broadcast receivers that listen out for changes in Wifi connection state, Wifi Rssi levels etc...
I want to be able to pass this data to another "Engine" Object and still keep the data changing dynamically.
I currently create a Wifi object within the "Engine" class and run its methods, the data is then dynamically displayed fine in Log statements in the log cat.
My problem is trying to get the dynamically changing data to the Engine, when I try to get data over it gets the first value and leaves it at that without ever updating.
So I was wondering what my options are on how to do this?
Below is my current code setup if that is any help:
Wifi Class
public Wifi(Context context){
mainWifi = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
}
public int getCurrentWifiState() {
return currentWifiState;
}
public void setCurrentWifiState(int currentWifiState) {
this.currentWifiState = currentWifiState;
}
public String getConnectedSSID() {
return connectedSSID;
}
public void setConnectedSSID(String connectedSSID) {
this.connectedSSID = connectedSSID;
}
public int getConnectedLevel() {
return connectedLevel;
}
public void setConnectedLevel(int connectedLevel) {
this.connectedLevel = connectedLevel;
}
//method to do a scan and receive info about all access points available
public List<ScanResult> scan(final Context context){
receiverWifi = new WifiReceiver();
mainWifi = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
context.registerReceiver(receiverWifi, new IntentFilter(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION));
mainWifi.startScan();
Log.d("WIFI DEBUG","\nStarting Scan...\n");
wifiList = mainWifi.getScanResults();
return wifiList;
}
class WifiReceiver extends BroadcastReceiver {
public void onReceive(Context c, Intent intent) {
sb = new StringBuilder();
wifiList = mainWifi.getScanResults();
ListIterator<ScanResult> results = wifiList.listIterator();
while (results.hasNext()) {
ScanResult info = results.next();
String wifiInfo = "Name: " + info.SSID + "; capabilities = " + info.capabilities + "; sig str = " + info.level + "dBm";
Log.v("WiFi", wifiInfo);
Log.d("Signal Level", "Signal Level : " + mainWifi.calculateSignalLevel(info.level, 5));
}
}
}
//method to listen for changes in the level of the wifi connection
public void initializeWiFiListener(Context context){
Log.d("WIFI", "executing initializeWiFiListener");
String connectivity_context = Context.WIFI_SERVICE;
final WifiManager wifi = (WifiManager)context.getSystemService(connectivity_context);
if(!wifi.isWifiEnabled()){
if(wifi.getWifiState() != WifiManager.WIFI_STATE_ENABLING){
//wifi.setWifiEnabled(true);
}
}
rssiListener = new BroadcastReceiver(){
#Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if(WifiManager.RSSI_CHANGED_ACTION.equals(action)){
WifiInfo data = mainWifi.getConnectionInfo();
Log.d("WIFI", "RSSI has changed");
if(mainWifi.getConnectionInfo()!=null){
setConnectedSSID(data.getSSID());
setConnectedLevel(data.getRssi());
Log.d("WIFI", "new RSSI = " + data.getSSID()+ " " + data.getRssi() + "dBm");
}
}
}
};
//leak here - need to de reg receiver
context.registerReceiver(rssiListener, new IntentFilter(WifiManager.RSSI_CHANGED_ACTION));
}
//method to listen for changes in the connection to a wifi access point
public void changeWiFiListener(Context context){
Log.d("WIFI", "executing initializeWiFiListener");
String connectivity_context = Context.WIFI_SERVICE;
final WifiManager wifi = (WifiManager)context.getSystemService(connectivity_context);
if(!wifi.isWifiEnabled()){
if(wifi.getWifiState() != WifiManager.WIFI_STATE_ENABLING){
//wifi.setWifiEnabled(true);
}
}
wifiChangeListener = new BroadcastReceiver(){
#Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if(WifiManager.WIFI_STATE_CHANGED_ACTION.equals(action)){
Log.d("WIFI", "WIFI has changed");
int wifiState = intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE, -1);
Log.d("WIFI", "WIFI State = " + wifiState);
setCurrentWifiState(wifiState);
}
}
};
//Leak here - not unregistering receiver
context.registerReceiver(wifiChangeListener, new IntentFilter(WifiManager.WIFI_STATE_CHANGED_ACTION));
}
public WifiReceiver getReceiverWifi() {
return receiverWifi;
}
public void setReceiverWifi(WifiReceiver receiverWifi) {
this.receiverWifi = receiverWifi;
And my Engine Code:
public Engine(Context aContext){
context = aContext;
cm = new CallManager(aContext);
wifiManager = new Wifi(context);
wifiManager.initializeWiFiListener(context);
wifiManager.changeWiFiListener(context);
clc = new CallLogController();
}
public void controlCalls(){
int currentWifiState = wifiManager.getCurrentWifiState();
cm.monitorOutgoingCalls(context, currentWifiState, clc);
}
public void unRegAllRecievers(){
wifiManager.unregRegisters(context);
cm.unRegReciever(context);
}
public void doWifiScan(){
scanTask = new TimerTask() {
public void run() {
handler.post(new Runnable() {
public void run() {
wifiManager.scan(context);
Log.d("TIMER", "Timer set off");
}
});
}};
t.schedule(scanTask, 300, 30000);
}
public void stopScan(){
scanTask.cancel();
t.cancel();
//boolean tf = scanTask.cancel();
//Log.d("TIMER", "Timer True or False? : " + tf);
}
}
So I'm just wondering what would be the best solution to make sure the data from the Wifi class is constantly updated in the engine when it receives changes from the broadcast receiver?
depends if your class, the one that should be notified of the latest state.
If it's a class that is not created in an Activity and is static (singletone or Application based) then you should probably have the Reciver update the singletone class.
If it's Activity based, you need stick Broadcasts, and once the broadcast is recieved remove the sticky broadcast.

Categories

Resources