Couldn't access value of variable in AsyncTask from onReceive - android

I have a Class (BroadcastReceiver) as
public class AlarmReceiverActivity extends BroadcastReceiver
{
public String memtypefrommainactivity="";
Context mContext;
#Override
public void onReceive(Context context, Intent intent)
{
context=mContext;
memtypefrommainactivity = intent.getStringExtra("memtypetobroadcast");
new CheckNewMessages(context).execute(memtypefrommainactivity);
}
And in the same class I have one Asynctask :
protected class CheckNewMessages extends AsyncTask<String,Void,String> {
public CheckNewMessages(Context context)
{
mContext=context;
}
#Override
protected void onPreExecute() {
}
#Override
public String doInBackground(String... params)
{
if(memtypefrommainactivity=="Retired".toString())
{
URL="xyz.com";
}
I didn't get the value of memtypefrommainactivity from both reference memtypefrommainactivity and params[0].

A BroadcastReceiver has an extremely short lifetime. Basically after onReceive() returns, the BroadcastReceiver is dead. As stated in the documentation, you cannot start asynchronous or long-running activities from a BroadcastReceiver and expect to get any callbacks. You need to use a Service instead of AsyncTask. Your BroadcastReceiver should start a Service to do the work, passing it the necessary parameters. Youc an probably do away with the BroadcastReceiver entirely and just have the AlarmManager start the Service directly.

Related

How to update the UI of Activity from BroadCastReceiver

I am learning Android concepts Activity and BroadCastReceiver. I want to update the content of Activity from the BroadtCastReceiver both are in different java class.
It is something like
MyActivity.java and MyBroadtCastReceiver.java
Is this possible to do this in Android ?
A BroadcastReceiver can be used in many ways but when it comes to something as specific as updating the UI components of an Activity, there is little advantage to declaring / defining a BroadcastReceiver in it's own Java class file.
Reasoning - the BroadcastReceiver has to have some prior "knowledge" of the Activity and what it is required to do in order to update the UI. In effect the BroadcastReceiver is tied to the Activity itself and it makes sense to declare / define it as an inner class.
Another important aspect is the Activity needs to be in a "running" (i.e., visible) state in order to guarantee manipulation of UI components. In this case, registering the receiver in onResume() and unregistering in onPause() will help prevent problems.
Using a generic template I'd do something like the following...
class MyActivity extends Activity {
boolean mIsReceiverRegistered = false;
MyBroadcastReceiver mReceiver = null;
// onCreate(...) here
#Override
protected void onResume() {
// Other onResume() code here
if (!mIsReceiverRegistered) {
if (mReceiver == null)
mReceiver = new MyBroadcastReceiver();
registerReceiver(mReceiver, new IntentFilter("YourIntentAction"));
mIsReceiverRegistered = true;
}
}
#Override
protected void onPause() {
if (mIsReceiverRegistered) {
unregisterReceiver(mReceiver);
mReceiver = null;
mIsReceiverRegistered = false;
}
// Other onPause() code here
}
private void updateUI(Intent intent) {
// Do what you need to do
}
private class MyBroadcastReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
updateUI(intent);
}
}
}
EDIT: A couple of extra notes...
The life-cycle of a BroadcastReceiver is between entering and leaving onReceive(...). Once it has returned from onReceive(...) the instance remains in a dormant state waiting for the next broadcast.
Directly related to point 1 - a BroadcastReceiver isn't designed for "heavy lifting". Basically the onReceive(...) method should be kept as simple as possible. Any methods it calls should also be as light-weight as possible...get in, do your stuff, get out then wait for the next broadcast. If updating the UI is going to take some time (perhaps updating a ListView by re-querying a database for a large amount of data for example), consider calling code which performs asynchronously (an AsyncTask for example).
Yes its possible. This is what i do.
Class i send the broadcast from (BackgroundActivity.java):
public static final String BROADCAST_BUFFER_SEND_CODE = "com.example.SEND_CODE";
onCreate(){
bufferIntentSendCode = new Intent(BROADCAST_BUFFER_SEND_CODE);
}
private void sendBufferingBroadcastSendCode() {
bufferIntentSendCode.putExtra("buffering", "1");
sendBroadcast(bufferIntentSendCode);
}
The class it will receive the broadcast(SendCode.java):
onResume(){
registerReceiver(broadcastBufferReceiver, new IntentFilter(BackgroundActivity.BROADCAST_BUFFER_SEND_CODE));
}
// set up broadcast receiver
private BroadcastReceiver broadcastBufferReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent bufferIntent) {
SendCode.this.LoadMessages(alarmNumber);
}
};
I unregister it in onPause
this.unregisterReceiver(broadcastBufferReceiver);
Register a new BroadcastReceiver object in your activity with same intent-filters as your MyBroadtCastReceiver. Since BroadcastReceiver and MyBroadtCastReceiver has same intent-filters both of their onReceive() will be invoked. Whatever update that you want to do in Activity can be done in onReceive of your BroadcastReceiver.
You can do like this:
public class MyActivity extends Activity{
// used to listen for intents which are sent after a task was
// successfully processed
private BroadcastReceiver mUpdateReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
new UpdateUiTask().execute();
}
};
#Override
public void onResume() {
registerReceiver(mUpdateReceiver, new IntentFilter(
YOUR_INTENT_ACTION));
super.onResume();
}
#Override
public void onPause() {
unregisterReceiver(mUpdateReceiver);
super.onPause();
}
// used to update the UI
private class UpdateUiTask extends AsyncTask<Void, Void, String> {
#Override
protected void onPreExecute() {
}
#Override
protected String doInBackground(Void... voids) {
Context context = getApplicationContext();
String result = "test";
// Put the data obtained after background task.
return result;
}
#Override
protected void onPostExecute(String result) {
// TODO: UI update
}
}
}
Squonk-s answer only works, if the Activity is active currently.
If you dont want to declare / define your BroadcastReceiver (BR) in an other Activity, or if you want to make some changes even if the app is not foreground, than your solution would look something like this.
First, you declare the BR, and save, or override the data needed to show in Acitvity.
public class MyBR extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
// override the data. Eg: save to SharedPref
}
}
Then in Activity, you show the data
TextView tv = findViewById(R.id.tv);
tv.setText(/*get the data Eg: from SharedPref*/);
And you should use a Timer to refresh the tv as well:
Timer timer = new Timer();
timer.schedule(new TimerTask() {
#Override
public void run() {
runOnUiThread(new Runnable() {
#Override
public void run() {
TextView tv = findViewById(R.id.tv);
tv.setText(/*get the data Eg: from SharedPref*/);
}
});
}
}, REFRESH_RATE, REFRESH_RATE);
REFRESH_RATE could be something like 1 second, but you decide.
try like this it may help you.
Define this method in activity's oncreate method in which you want to update ui,
BroadcastReceiver mMessageReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
//your code to update ui
}
};
LocalBroadcastManager.getInstance(this).registerReceiver(mMessageReceiver, new IntentFilter("giveyourappname"));
Define this action at place from where you want to update ui,
try{
ActivityManager am = (ActivityManager) this .getSystemService(ACTIVITY_SERVICE);
List<RunningTaskInfo> taskInfo = am.getRunningTasks(1);
ComponentName componentInfo = taskInfo.get(0).topActivity;
Log.d("Activity", "Current Activity ::" + taskInfo.get(0).topActivity.getClassName());
Log.d("Package", "Package Name : "+ componentInfo.getPackageName());
if(componentInfo.getPackageName().equals("your application package name")){
Intent intent = new Intent("giveyourappname");
//add data you wnat to pass in intent
LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
}
}catch(Throwable e){
e.printStackTrace();
}

Activity, Service and AsyncTask interfacing

I have one subclass of android.support.v4.app.FragmentActivity(MyActivity), one subclass of android.app.Service and one subclass(MyAsyncTask) of android.os.AsyncTask.
Sample Code:
MyActivity.java
onCreate(...) { // start MyService }
MyService.java
onStartCommand(...){ // execute MyAsyncTask }
MyAsyncTask.java
onPostExecute(String result) { // send result to MyActivity};
My question is, how can i send results from MyAsyncTask when success to MyActivity.
This is not easy to answer in a short paragraph. But basically what you want to do is use binding for your service.
It's certainly not a trivial task, but it's the elegant way to go. Besides of initiating your service with startService() you would additionally bind to your service. The binding mechanism allows your Activity to have a pointer to your Service class. With this pointer you can do whatever you want, including passing a pointer of the Activity itself to the Service, so the service would have a pointer to your Activity.
Once the Service has a pointer to your Activity, you can call any methods and set any variables you want, including setting the return value from your AsyncTask.
You can make a SingleInstance model with the MyActivity.
class MyActivity extends Activity{
private static MyActivity instance;
public static MyActivity getInstance(){
return instance;
}
public void onCreate(Bundle savedInstanceState) {
instance = this;
//xxx
}
public void onDestroy() {
instance = null;
///
}
public void doSomething(){}
}
Then you can call MyActivity.getInstance().doSomething();inside the onPostExecute
Some alternatives:
use an IntentService, which is basically a Service that handles asynchronous requests
send a broadcast from your AsyncTask's onPostExecute and receive it in you Activity (simple example here)
I have tried this structure and its works on my app. Hope its helpful.
Create the service class extended with async task and singleton ..
<service android:name=".myService" />
Service class
public class myService extends AsyncTask<String,String,String>
{
private Activity active = null;
protected myService () {}
public static myService getInstance(Activity activity) {
myService myTask = new myService ();
myTask.active = activity;
return myTask;
}
public startTask() {
//start the async task..
this.execute(new String[] {});
}
protected void onPostExecute(String result) {
//check result sucess cond and call
active.updateActivity(result)
}
}
Activity class
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
myService.getInstance(this).startTask();
}
public void updateActivity(result){
//do something on activity with result...
}
You can send result from service(MyAsyncTask.java and MyService.java) class to activity(myactivity) class through "Broadcast"
here is an example
in your onPostExecute(String result) method add those:
Intent intent = new Intent("your activity class[myactivity.java]");
intent.putExtra("RESULT", result)
sendBroadcast(intent);
and your myactivity class
receive sending broadcast like this:
private BroadcastReceiver receiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
String bundle = intent.getStrings();// get resulting string and do whatever you want.
}
}
don't forget to register and unregister broadcast in myactivity class, like:
#Override
protected void onResume() {
super.onResume();
registerReceiver(receiver, new IntentFilter("your service class"));
}
#Override
protected void onPause() {
super.onPause();
unregisterReceiver(receiver);
}
A way is to Bind your Activity to your service so that they can share a common communication channel.

Interaction between Activity and Sticky Service

i have an Activity and a Sticky Service. The Activity needs to show some values in it´s UserInterface depending on the values of the Sticky Service. So whenever the Service changes his data, the Activity needs to update it´s UserInterface.
But how should the Service notify the Activity to change it´s values??
Please remind that the Activity sometimes isn´t alive, only the Service is Sticky.
Use LocalBroadcasts
in your service class:
public class LocalMessage extends IntentService{
private Intent broadcast;
public static final String BROADCAST = "LocalMessage.BROADCAST";
public LocalMessage(String name) {
super(name);
broadcast = new Intent(name);
}
#Override
protected void onHandleIntent(Intent intent) {
if (broadcast != null) LocalBroadcastManager.getInstance(context).sendBroadcast(broadcast);
}
}
and here is method inside service to broadcast
private void sendLocalMessage(){
(new LocalMessage(LocalMessage.BROADCAST)).onHandleIntent(null);
}
In your activity:
private void registerBroadcastReciever() {
IntentFilter filter = new IntentFilter(YourService.LocalMessage.BROADCAST);
LocalBroadcastManager.getInstance(getApplicationContext()).registerReceiver(receiver, filter);
}
private BroadcastReceiver receiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
//doSmth
}
};
in your activity onDestroy() method unregister receiver;

Communication between C2DM BroadcastReceiver and multiple activities

I have an Android application which uses C2DM services (aka push).
I have a separate class which implements the registration process and which receives the data (and extends BroadcastReceiver).
I want to communicate this data to the activity which currently is in the foreground. The activity currently in the foreground may differ depending on user action.
What's the best way to communicate in between the receiver and the current activity?
Thanks.
I solved this problem by sending out a new broadcast from the C2DMReceiver class, which looked something like this.
The C2DMReceiver class:
public class C2DMReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals("com.google.android.c2dm.intent.REGISTRATION")) {
handleRegistration(context, intent);
} else if (intent.getAction().equals("com.google.android.c2dm.intent.RECEIVE")) {
handleMessage(context, intent);
}
}
private void handleRegistration(Context context, Intent intent) {
// handle registration
}
private void handleMessage(Context context, Intent intent) {
Intent i = new Intent("push");
i.putExtras(intent);
// context.sendOrderedBroadcast(i, null);
context.sendBroadcast(i);
}
}
Another class I called PushReceiver. This is the class that will extend BroadcastReceiver and receive the broadcast sent by C2DMReceiver.
public class PushReceiver extends BroadcastReceiver {
public PushReceiver() {
}
#Override
public void onReceive(Context context, Intent intent) {
// do stuff
abortBroadcast();
}
public static class PushFilter extends IntentFilter {
private static final int DEFAULT_PUSH_PRIORITY = 1;
public PushFilter() {
this(DEFAULT_PUSH_PRIORITY);
}
public PushFilter(int priority) {
super("push");
setPriority(priority);
}
}
}
And the activity class, in this case called MyActivity. This should work well if you are using a base activity class that all other activities extend. That way every activity registers the receiver. By doing the register/unregister in onResume/onPause, you should be able to guarantee that only the current activity receives the broadcast. If not, you can send an ordered broadcast from C2DMReceiver and use priority in the PushFilter.
public class MyActivity extends Activity {
private PushReceiver pushReceiver;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// your onCreate method
pushReceiver = new PushReceiver();
}
public void onResume() {
super.onResume();
// your onResume method
registerReceiver(pushReceiver, new PushReceiver.PushFilter());
}
public void onPause() {
super.onPause();
// your onPause method
unregisterReceiver(pushReceiver);
}
}
In my case, I wrote the PushReceiver constructor to take a View and then "did stuff" with the view in the onReceive method. Without knowing more about what your trying to do, I can't elaborate on this, but hopefully this can provide a decent template to work from.

Is it possible to call a non activity class from a BroadcastReceiver, If yes how we can do?

I have one BroadcastReceiver,it notify when phone state is changed, at that time i wan't to get a data from CallLog.Calls(this reside in my non activity class) and save it to my SQLite database.But now i facing a problem when calling a class.
Since i am new to android, any help or idea will be appreciated.
Thanks in advance
You could start an IntentService from your BroadcastReceiver and from there do whatever you want.
public class UpdateReceiver extends BroadcastReceiver {
private static Context mContext;
#Override
public void onReceive(Context context, Intent intent) {
mContext = context;
context.startService(new Intent(context, UpdateService.class));
}
public static class UpdateService extends IntentService {
public UpdateService() {
super("UpdateService");
}
#Override
protected void onHandleIntent(Intent intent) {
// Do whatever you want from here
Logic.doSomething(mContext);
}
}
}
Add the service to your manifest.
<service android:name="com.example.UpdateReceiver$UpdateService" />

Categories

Resources