I am using DownloadManager to download multiple files (12 to be exact). I have setup a BroadcastReciever and when ACTION_DOWNLOAD_COMPLETE display an AlertDialog like this:
manager.enqueue(f1);
manager.enqueue(f2);
manager.enqueue(f3);
......
BroadcastReceiver receiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (DownloadManager.ACTION_DOWNLOAD_COMPLETE.equals(action)) {
//Display an alertdialog
}
}
};
registerReceiver(receiver, new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE));
However once the downloads complete, the dialog goes into a loop and keeps reappearing until a forcefully exit the app. Does anyone know why this is happening?
I have found that this is happening because it displays the alertdialog for each completed download. How can I make it show just once when all of the downloads are done?
Related
this is my first time posting here. I'm new to Java & using the Android SDK, and thought I'd start off by trying to write a simple app to filter text messages for "scammy" keywords, for an Innovation module in school.
The app began off by showing a small toast whenever a keyword ("FREEBIE" etc.) is flagged, but I've been trying to make a more noticeable indicator, such as through alert dialogs.
Not sure what I've been doing wrong, but the alert isn't displaying when a message containing the keyword is sent through, but toasts work fine though. I thought it might be an issue with the context, so I've tried context/this/getActivityContext etc., but I receive a "Builder cannot be applied to com.example.myapp.ReceiveSms" error.
package com.example.myapp;
import android.app.AlertDialog;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.os.Bundle;
import android.telephony.SmsMessage;
public class ReceiveSms extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals("android.provider.Telephony.SMS_RECEIVED")){
Bundle bundle = intent.getExtras();
SmsMessage[] msgs;
if (bundle != null) {
try {
Object[] pdus = (Object[]) bundle.get("pdus");
msgs = new SmsMessage[pdus.length];
for (int i = 0; i < msgs.length; i++) {
msgs[i] = SmsMessage.createFromPdu((byte[])pdus[i]);
String msgFrom = msgs[i].getOriginatingAddress();
String msgBody = msgs[i].getMessageBody();
if (msgBody.matches(".*\\bFREEBIE\\b.*")) {
AlertDialog.Builder builder = new AlertDialog.Builder(context.getApplicationContext());
builder.setTitle("Scam Message");
builder.setMessage("Scam Message");
builder.setCancelable(true);
builder.setNeutralButton(android.R.string.ok,
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
dialog.cancel();
}
});
AlertDialog alert = builder.create();
alert.show();
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
}
Basicly you can not show dialog in broadcast receiver . See this link for more details , https://stackoverflow.com/a/8766864/1079842
The problem is with the context passed to the dialog as they can only be displayed within an activity.
new AlertDialog.Builder(context.getApplicationContext());
You need to specify the activity that the AlertDialog will appear over not the application context. It would look something like this:
new AlertDialog.Builder(YourActivityClass.this);
Since the dialog is being created from a receiver (not it's designated use case), one solution, but not recommended is to create an activity for this specific dialog.
show an alert dialog in broadcast receiver after a system reboot
Showing AlertDialog in a BroadcastReceiver is not allowed, this should only happen in a context of an Activity.
Instead of showing an AlertDialog, I'd recommend using showing notifications instead.
public class ReceiveSms extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent arg1) {
// Add your desired logic here whether to show or not the notification
showNotification(context);
}
private void showNotification(Context context) {
PendingIntent pIntent = PendingIntent.getActivity(
context, 0,
new Intent(context, MyActivity.class), 0);
NotificationCompat.Builder builder =
new NotificationCompat.Builder(context)
.setSmallIcon(R.some.icon_here)
.setContentTitle("Your Notification Title")
.setContentText("Your Message");
builder.setContentIntent(pIntent);
builder.setAutoCancel(true);
NotificationManager notificationManager =
(NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.notify(1, builder.build()); // 1 denotes your notification id
}
}
This should help you further understand the alternatives on what you are trying to do.
Further reading
https://developer.android.com/training/notify-user/build-notification
ReceiveSms extends BroadcastReceiver
This is your BroadcastReceiver. BroadcastReceiver are defined for the purpose of getting system broadcasts on the different resources.
Example :
Internet is started by user
Sms is received
Call is coming
Sms has arrived
What is the BroadcastReceivers work
Just to let developers get the access to the triggers.
Why your Dialog alert not working, even if coded correctly ?
I will not correct the mistake in your dialog alert, As your programming approach is wrong. It is not working because, when the sms receives your app might be in foreground or background or nowhere.. And Even if present in background you needs to draw over other apps, permission.
When Dialog alert are used ?
Used in only when user is actively in the app and app is open in front of him. and not in Broadcastreceivers nor in the background. Broadcastreceivers works in background and you need to show System alert or a notification or simply a toast.
Remove your alertdialog and use below :
Toast.makeText(this, " SMS ARRIVED ", Toast.LENGTH_LONG).show();
Or
A System Alet
or
A Notification
Another problem in your approach :
You are not allowed to use READ_SMS or SEND_SMS or any SMS related operations as your app will be rejected if you tried to upload it on play store.
You need to use https://developers.google.com/identity/sms-retriever/user-consent/request
SMS-RETRIEVAR api for that purpose
Is there any way to create a service that runs forever on a background for Android user to check whether their screen on or off, etc?
I'm about to create an analytics, so I need to know when the user turn on or turn off their screen.
Thanks, I will appreciate all the input
You may use Android broadcast receiver to detect screen on and off.
Here is a good example of it
https://thinkandroid.wordpress.com/2010/01/24/handling-screen-off-and-screen-on-intents/
you may also follow this thread
https://stackoverflow.com/a/9478013/2784838
You need to create broadcast receiver and manage screen on or off status.
Declare receiver in manifest:
<receiver android:name=".DeviceWakeUpReceiver" />
public class DeviceWakeUpReceiver extends BroadcastReceiver {
private static final String TAG = "DeviceWakeUpService";
#Override
public void onReceive(Context context, Intent intent) {
Log.d(TAG, "onReceive() called");
if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) {
//End service when user phone screen off
} else if (intent.getAction().equals(Intent.ACTION_SCREEN_ON)) {
//Start service when user phone screen on
}
}
}
You cannot use a BroadcastReceiver for receiving screen off/on events.
Write a intent service which is started via boot complete listener and register for Intent.ACTION_SCREEN_OFF and Intent.ACTION_SCREEN_ON.
IntentFilter filter = new IntentFilter(Intent.ACTION_SCREEN_ON);
IntentFilter filter = new IntentFilter(Intent.ACTION_SCREEN_OFF);
registerReceiver(new ScreenOffOnReceiver(), filter);
class ScreenOffOnReiver extends BroadcastReceiver {
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) {
// Screen OFF
else if (intent.getAction().equals(Intent.ACTION_SCREEN_ON)) {
// Screen ON
}
}
}
I am going to implement a feature , where my application has to receive events of a camera from ( Event push server).
This server will push the events and my application has to receive and show in the notification bar.
e.g like the Facebook app or WhatsApp app, where in we receive the new message on the notification bar, even though the app is not in active state.
So to implement it:
What all pre requisetes i need. e.g information about the Event server?
Information on what protocol used in the server?
what is required on the Android side to implement this feature.
Please tell me how to proceed to implement on Android application side.
The programs like facebook using service to take events in background. Use JSON files for data interchange. Im using BroadcastReceiver to keep in touch with my activity. BroadcastReceiver its a very nice tool to communicate your service with activity.
Intent in = new Intent("SOMEACTION");
sendBroadcast(in);
Sending intent to you activity after handling response.
#Override
public void onResume() {
super.onResume();
// Register mMessageReceiver to receive messages.
LocalBroadcastManager.getInstance(this).registerReceiver(mMessageReceiver,
new IntentFilter("my-event"));
}
// handler for received Intents for the "my-event" event
private BroadcastReceiver mMessageReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
// Extract data included in the Intent
String message = intent.getStringExtra("message");
Log.d("receiver", "Got message: " + message);
}
};
#Override
protected void onPause() {
// Unregister since the activity is not visible
LocalBroadcastManager.getInstance(this).unregisterReceiver(mMessageReceiver);
super.onPause();
}
I'm doing similar to what discussed here:
Android BroadcastReceiver within Activity
I have application that runs with or without UI. When screen is off it's just working on background. When UI is on and visible - I would like to let user know that something just happened.
So, I followed samples in topic above and registered broadcast receiver on my Activity. I register onResume and unregister on onPause
private BroadcastReceiver uiNeedToBeUpdatedReceiver = new BroadcastReceiver()
{
#Override
public void onReceive(Context context, Intent intent)
{
// TODO Auto-generated method stub
Toast.makeText(BaseActivity.this, "received", Toast.LENGTH_LONG);
}
};
#Override
protected void onPause()
{
Log.d(LOG_TAG, "onPause");
super.onPause();
// TODO: Unregister broadcast receiver
unregisterReceiver(uiNeedToBeUpdatedReceiver);
}
#Override
protected void onResume()
{
Log.d(LOG_TAG, "onResume");
super.onResume();
// TODO: Register for broadcast events
IntentFilter filter = new IntentFilter();
filter.addAction("com.my.uineedtobeupdated");
registerReceiver(uiNeedToBeUpdatedReceiver, filter);
Inside my AsyncTask that runs on background I do this:
// Send broadcast - if UI active it will see it:
Intent broadcast = new Intent();
broadcast.setAction("com.my.uineedtobeupdated");
MyApplication.Me.sendBroadcast(broadcast);
Well, everyting works. I get broadcasts and I see in my debugger that I'm hitting line where Toast should show. But I don't see any toast popping up.
Is that threading issue? I though if I receive broadcast it shuld be on UI thread? Why do I observe this behavior?
It's important not only to create the Toast, but actually display it. The easy way:
Toast.makeText(BaseActivity.this, "received", Toast.LENGTH_LONG).show();
You can also, of course:
Toast myToast = Toast.makeText(BaseActivity.this, "received", Toast.LENGTH_LONG);
myToast.show();
Toast.makeText(BaseActivity.this, "received", Toast.LENGTH_LONG);
You are making a Toast, but you are not showing it. You need to call show on it, like this:
Toast.makeText(BaseActivity.this, "received", Toast.LENGTH_LONG).show();
So I've got 3 java files :
ServiceActivity - main activity where everything starts ( static int i is defined earlier in this file)
Elserwis - it is the service (it has a timer where I've passed the variable i -> it will be the hour since when the timer must turn on)
Sekundo - the intent where user puts the hour => >variable i<
Here is the fragment of code from main activity -> ServiceActivity:
private OnClickListener startListener = new OnClickListener() {
public void onClick(View v){
Intent intent = new Intent(getApplicationContext(), Sekundo.class);
startActivityForResult(intent,1337);
}
};
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data ) {
/* Place out code to react on Activity-Result here. */
super.onActivityResult(requestCode, resultCode, data);
if(requestCode == 1337){
i=data.getIntExtra("result",5);
Toast tost = Toast.makeText(getApplicationContext(), "ELO"+data.getIntExtra("result",0)+data.getIntExtra("result1",0), 1000);
tost.show();
startService(new Intent(SerwisActivity.this,Elserwis.class));
}
}
I think the problem is in the end, where startService lays (as a subfunction of onActivityResult)
If you need any other fragment of code I can paste it here, but the question is:
My app is running very slowly at the beginning when the timer starts, and the Toast shows for over 1 minute. Anyone know why?
EDIT:
public class Elserwis extends Service {
#Override
public IBinder onBind(Intent arg0) {
// TODO Auto-generated method stub
return null;
}
#Override
public void onCreate() {
super.onCreate();
okresowePowiadomienie();
Toast.makeText(getApplicationContext(),"Service LAUNCHED!", 1000).show();
}
Date data33 = new Date(111,11,SerwisActivity.i,2,25);
int d = data33.getDate();
Timer timer = new Timer();
public void okresowePowiadomienie(){
TimerTask timerTask = new TimerTask(){
public void run() {
NotificationManager notificationManager = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);
Notification notification = new Notification(R.drawable.ic_launcher,"OKRes",System.currentTimeMillis());
Intent notIntent = new Intent(getApplicationContext(), SerwisActivity.class);
PendingIntent contentIntent = PendingIntent.getActivity(getApplicationContext(), 0, notIntent, 0);
notification.setLatestEventInfo(getApplicationContext(),"Powiadomienie x:","Kliknij aby d:usunac ;)t:"+d,contentIntent);
notification.flags |= Notification.FLAG_AUTO_CANCEL;
notificationManager.notify(1335, notification);
// } };
}};
timer.scheduleAtFixedRate(timerTask ,data33 , 120000); }
#Override
public void onDestroy() {
super.onDestroy();
timer.cancel();
Toast.makeText(this, "Service dead!", Toast.LENGTH_LONG).show();
}
}
thats just alpha version of my code but final will be similar ( now it only passes information about the day to my service -> in final version it should pass hour and minute)
The "Service LAUNCHED!" toast stays on for ages, it crashes most of the time on AVD, on my real smartphone it just takes long but still it should work smoothly...
Basically the problem started when i moved startService from onClick() function TO the onActivityResult. It needs to stay there because service uses the int i (user types types int i in the new intent) to set the data for my timer(timer is in the Elserwis). I've updated my first post with the service code so u can get what i mean
I'm GUESSING that startService itself is not causing any blocking.
I'm GUESSING that you have code in startService that takes awhile to complete and causes your application UI to lock up.
If this is the case, then what you would need to do is create a new thread inside your service before running the code that causes the delay.
You need to keep any long-running blocks of code in a separate thread to not block the UI. I would be interested in the code that is in Elserwis.class because that would help identify where the problem actually lies. Or if you look at your code and figure it out based on what I said, then you need not post any more code.