I am testing a simple widget in android and using Alarms to update a TextView at regular intervals. The problem is that in the BroadcastReceiver class I cannot access the TextView element, which I want to get updated when the alarm expires. The class is being called properly because the Toast i have put there is giving the appropriate message. The following code is from the class where I configure the widget and set the timers.
public void onCreate(Bundle bundle) {
super.onCreate(bundle);
Intent intent = getIntent();
Bundle extras = intent.getExtras();
if(extras != null){
mWidgetId = extras.getInt(AppWidgetManager.EXTRA_APPWIDGET_ID, AppWidgetManager.INVALID_APPWIDGET_ID);
AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(WidgetConfigure.this);
RemoteViews views = new RemoteViews(WidgetConfigure.this.getPackageName(), R.layout.widget_layout);
views.setTextViewText(R.id.quote, "Widget Loaded From Activity");
appWidgetManager.updateAppWidget(mWidgetId, views);
setTimer(); //set the timers...
setResult();// set the result...
}
}
Now i want to update the same TextView when the BroadCastReceiver is called after the timer expires. I have tried the code provided in the ExampleAppWidget example provided in android api demos and that isnt working out. How can i set the required text?
You cannot directly change something in an Activity from a BroadcastReceiver. Because when a broadcast receiver get called, the activity maybe not exist. YOu can send messages to an activity (if the activity exists), or if the activity does not exist you can start it and put some flags in Intent
update:
Here is an ugly way:
class YourActivity extends xxxx {
private static YourActivity mInst;
public static YOurActivity instance() {
return mInst;
}
/// Do your task here.
public void setViewText(xxxx) ;
#Override
public void onStart() {
...
mInst = this;
}
#Override
public void onStop() {
...
mInst = null;
}
}
And in your BroadcastReceiver:
YOurActivity inst = YOurActivity.instance();
if(inst != null) { // your activity can be seen, and you can update it's context
inst.setViewText...
}
Related
I am trying to get actions performed on battery change. For that I have used the following code:
public class BatteryBroadcastReceiver extends
BroadcastReceiver {
DatabaseHelper db;
#Override
public void onReceive(Context context, Intent intent) {
db = new DatabaseHelper(context);
String cont1 = db.usercontact().toString();
String action = intent.getAction();
if (action != null && action.equals(Intent.ACTION_BATTERY_CHANGED)) {
int level = intent.getIntExtra(BatteryManager.EXTRA_LEVEL,-1);
int scale = intent.getIntExtra(BatteryManager.EXTRA_SCALE,-1);
int percentage = level * 100 / scale;
if(percentage <= 20){
// doing something like getting location
}
}
}
I have registered my broadcast in my activity:
public class Battery extends AppCompatActivity {
private BatteryBroadcastReceiver batteryReceiver = new BatteryBroadcastReceiver();
private IntentFilter intentFilter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_auto_location);
}
#Override
protected void onResume(){
super.onResume();
registerReceiver(batteryReceiver,intentFilter);
}
#Override
protected void onPause(){
unregisterReceiver(batteryReceiver);
super.onPause();
}
This general piece of code is working fine but it is restricting me to just this activity (may be because broadcast is registered in this activity). Like as long as this activity remains open I can perform some task but as I closes it, when battery gets low it perform no task. Now I don't know what to do. I have other activities too in my application and I want it to work even when I am not on this activity. Is there any way that I can register it in manifest so that it could work overall. I have tried doing that but then nothing happens on battery change. Thanks for help in advance :).
It is no longer possible to register for ACTION_BATTERY_CHANGED in the manifest. See https://developer.android.com/reference/android/content/Intent.html#ACTION_BATTERY_CHANGED
If you want to get triggered by this broadcast Intent in all of your activities, you can do this one of 2 ways:
Register and unregister the receiver in each and every one of your activities. You could simplify this by creating a BaseActivity that handles the register and unregister of the BroadcastReceiver and then extending all your activities from BaseActivity.
Register the receiver when your app starts in a custom Application class, or in onCreate() of your first Activity. Don't unregister the receiver. This causes a small memory leak, but I wouldn't worry about it.
I created a Broadcast Receiver (BR) in a service that will react to incoming SMS with specific number and body. I only need it to receive for a few seconds/minutes after user action, that's why I didn't registered it in manifest or activity (user may close it). BR has two parts, automatic (which works fine) and manual which should launch MainActivity and start a Dialog. I know that Dialog can't be started from BR and thats why I created a Listener, but my problem is that it is always null after service starts. It has value in onCreate of my MainActivity, but when service starts it changes to null, and I understand why (serivce re-initalize the Listener listener). I even tryed to put initialised listener value to SharedPrefs and restore it after, but when I try to store it with json it only stores null again. So how do I make my listener != null??? These are the relevant parts of my code:
MainActivity
onCreate {
SMSService smsReceiver = new SMSService();
smsReceiver.setListener(new SMSService.Listener() { //here listener from service is != null
#Override
public void onTextReceived(String s) {
dialogS(s); // totaly different dialog
}
});
...
mDialogBuilder = new AlertDialog.Builder(this);
...
.setPositiveButton(new OnClick...
Intent servisIntent = new Intent(MainActivity.this, SMSService.class);
startService(servisIntent);
...
}
SMSService
private Listener listener; // and here it get null which is the problem
public int onStartCommand(Intent intent, int flags, int startId) {
...
SMSReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
Intent i = new Intent(context, MainActivity.class);
context.startActivity(i);
if (listener != null) {
listener.onTextReceived("4333");
}
}
void setListener(Listener listener) {
this.listener = listener; }
interface Listener {
void onTextReceived(String text);
}
Btw I also tried to put smsReceiver.setListener block of code in my Dialog .setPossitive onClickListener after calling startService hoping it would initiate after service but nothing
Installing a listener mechanism with setter method in service is bad practice. You can use ResultReceiver to receive callback results from service. It is Parcelable, so it can be passed in an intent before service started
I have a simple application where I am trying to learn how to:
1) Call a web service
2) Parse the Data
3) Save it to SQLiteDatabase
4) Set-up a ContentObserver/Broadcaster to detect changes in an Activity and change the UI
So far, I have done everything but having trouble with step 4.
Code:
LaunchActivity which shows the layout containing the UI which I eventually want to change launches the Service class:
Intent intent = new Intent(this, DataService.class);
intent.putExtra("restMethodType", 0);
startService(intent);
The DataService class then runs the desired AsyncTask Rest Method:
public class DataService extends IntentService {
public DataService() {
super("DataService");
}
public DataService(String name) {
super(name);
}
#Override
protected void onHandleIntent(Intent intent) {
RestMethodType restMethodType = RestMethodType.values()[intent.getIntExtra("restMethodType", 0)];
switch (restMethodType) {
case UPCOMING_MATCH:
UpcomingMatchRestMethod restMethod = new UpcomingMatchRestMethod(getApplicationContext(), intent);
restMethod.execute();
break;
}
}
}
Within the onPostExecute method of the AsyncTask, I save the retrieved data in to the database and then broadcast the event:
long newRowId = database.insert(MatchContract.MatchEntry.TABLE_NAME, MatchContract.MatchEntry.COLUMN_NAME_LOCATION, values);
if(newRowId != -1){
mIntent.putExtra("matchId", newRowId);
LocalBroadcastManager.getInstance(mContext).sendBroadcast(mIntent);
}
Back in the LaunchActivity, I set-up a receiver object:
DataReceiver mDataReceiver;
#Override
protected void onResume() {
super.onResume();
IntentFilter intentFilter = new IntentFilter("What Goes In Here?");
registerReceiver(mDataReceiver, intentFilter);
}
This is what the receiver looks like:
private class DataReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
// Do Stuff like update the UI
// Make sure to wrap any View objects in runOnUIThread
}
}
So what goes in the IntentFilter? And what else am I missing? I followed the Google Docs but getting a little confused.
Thank you in advance.
I am able to receive C2DM message fine but I want to send the data to a running activity, i.e when the activity is running, if the receiver receives C2DM message it is to send the data to the running activity. The code of receiver is (no bugs in the code):
public class C2dmreceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
Log.w("C2DM", "Message Receiver called");
if ("com.google.android.c2dm.intent.RECEIVE".equals(action))
{
final String payload = intent.getStringExtra("key1");
Log.d("C2DM", "message = " + payload );
}
}}
I have tried like this inside the activity in an attempt to register the receiver in the activity so that the receiver can send data and the running activity can receive the data :-
C2dmreceiver c2dmr = new C2dmreceiver();
Registration.this.registerReceiver(c2dmr, new IntentFilter());
I don't know what to put inside the IntentFilter(), also what else I have to put in the code of the activity and the code of the receiver so that while the activity is running and some C2DM message comes the receiver can send the data to the running activity.
So, please tell me the code that is to put in the activity and in the receiver and may also be in the manifest so that the data from the receiver could be send to running activity.
Any advice is highly appreciated.
First of all it's not the best idea to subscribe c2dm receiver in activity. Do it in manifest. For passing data to activity you can create static string field in Activity and set you String there.
You can do something like this:
in Activity
public static YourActivity mThis = null;
#Override
protected void onResume() {
super.onResume();
mThis = this;
}
#Override
protected void onPause() {
super.onPause();
mThis = null;
}
In your BroadcastReceiver:
#Override
public void onReceive(Context context, Intent intent) {
...
if (YourActivity.mThis != null) {
((TextView)YourActivity.mThis.findViewById(R.id.text)).setText("received c2dm");
}
else {
...
}
When i have a broadcastReceiver say android.intent.action.MEDIA_BUTTON and i want to update the current activity's UI without creating a new activity, is there any good practice on this one?
What i know (might not be correct)
1) I can put the BroadcastReceiver in the same class as the activity and call the updateUI function after certain activity
2) Create a ContentObserver?
3) Communicate to a service created by the activity, use aidl. (I dont know how to get the current service if its registered from an activity)
4) Create a custom filter on the broadcastReceiver located on the same class as the activity, and use context.sendBroadcast(msg of custom filter) and in the custom filter call updateUI (same as one but more generic?)
The final flow is it would come from a BroadcastReceiver and ends up updating the UI without renewing the activity (unless the activity is dead?)
Kindly provide links/source code on your how you tackle this kind of problem. Thanks a lot in advance :)
The easiest way to provide this functionality is to put the broadcast receiver in you Activity and bind / unbind it using registerReceiver and unregisterreceiver:
public class MyActivity extends Activity {
private BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
MyActivity.this.receivedBroadcast(intent);
}
};
#Override
public void onResume() {
super.onResume();
IntentFilter iff = new IntentFilter();
iff.addAction("android.intent.action.MEDIA_BUTTON");
// Put whatever message you want to receive as the action
this.registerReceiver(this.mBroadcastReceiver,iff);
}
#Override
public void onPause() {
super.onPause();
this.unregisterReceiver(this.mBroadcastReceiver);
}
private void receivedBroadcast(Intent i) {
// Put your receive handling code here
}
}
Depending on the intent you wish to receive, you may need to add the appropriate permissions to your AndroidManifest.xml file.
What I recently had to do to change a Button's text after receiving data from a LocalBroadcastManager is to store the value in a private field and then do the UI stuff in my onResume() method.
public class myClass extends Activity {
private String myString;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// register to receive data
LocalBroadcastManager.getInstance(getActivity()).registerReceiver(receiver, new IntentFilter("myAction"));
}
private BroadcastReceiver receiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
// get the extra data included in the intent
myString = intent.getStringExtra("myString");
}
};
#Override
public void onResume() {
super.onResume();
System.out.println("onResume");
// do something to the UI
myButton.setText(myString != null ? myString : "Default");
}
}