ProximityAlert with a BroadcastReceiver not working - notifications

I am new to Android and have a problem with adding ProximityAlert with a BroadcastReceiver. I know that this topic has been taken up earlier as well but I am trying to add proximity alert to different locations and I am not sure if what I am trying to do is quite achievable this way or I am just doing it wrong.
Problem : I have tried to implement the code for adding ProximityAlert with a BroadcastReceiver, but its not working some how. Below is the snippet from my code (posted below) requesting all to please have a look and help me out with it.
I have this userLocations list. I am adding Proximity Alert to all the user mentioned location by running a for loop for the list. I only want to add a proximity Alert to the user location if that particular location has not been visited by the user before.
I then register the receiver in the addLocationProximity() method, which is called from the onResume() method. I unregisterReceiver the receiver in the onPause() method.
I have also used the onLocationChanged() method to populate a list (which I would be needing for later) based on the same logic which have been used to add the proximity alert.
Please do let me know if any of these steps have not been carried out correctly.
Thanks in advance.
package com.android.locationmang;
public class ViewAActivity extends ListActivity implements LocationListener{
private static final String PROX_ALERT_INTENT = "com.android.locationmang.PROX_ALERT_INTENT";
private static final long LOCAL_FILTER_DISTANCE = 1200;
public static List<UserLocation> notifiedLocationsList;
public static Location latestLocation;
PendingIntent pendingIntent;
Intent notificationIntent;
private LocationManager locationManager;
List<UserLocations> userLocations;
private IntentFilter filter;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
notifiedLocationsList = new ArrayList<UserLocation>();
userLocations = getUserLocations(); //Returns a list of user Locations stored by the user on the DB
filter = new IntentFilter(PROX_ALERT_INTENT);
}
private void setUpLocation() {
locationNotificationReceiver = new LocationNotificationReceiver();
locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 60, 5, this);
for (int i = 0; i < userLocation.size(); i++){
UserLocation userLocation = userLocation.get(i);
if(!(userLocation.isComplete())){
setProximityAlert(userLocation.getLatitude(),
userLocation.getLongitude(),
i+1,
i);
}
}
registerReceiver(locationNotificationReceiver, filter);
}
private void setProximityAlert(double lat, double lon, final long eventID, int requestCode){
// Expiration is 10 Minutes (10mins * 60secs * 1000milliSecs)
long expiration = 600000;
Intent intent = new Intent(this, LocationNotificationReceiver.class);
intent.putExtra(LocationNotificationReceiver.EVENT_ID_INTENT_EXTRA, eventID);
PendingIntent pendingIntent = PendingIntent.getBroadcast(getApplicationContext(), requestCode, intent, PendingIntent.FLAG_CANCEL_CURRENT);
locationManager.addProximityAlert(lat, lon, LOCAL_FILTER_DISTANCE, expiration, pendingIntent);
}
#Override
protected void onResume() {
super.onResume();
setUpLocation();
locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 60, 5, this);
}
#Override
protected void onPause() {
super.onPause();
locationManager.removeUpdates(this);
unregisterReceiver(locationNotificationReceiver);
}
public void onProviderDisabled(String provider) {}
public void onProviderEnabled(String provider) {}
public void onStatusChanged(String provider, int status, Bundle extras) {}
public boolean userLocationIsWithinGeofence(UserLocation userLocation, Location latestLocation, long localFilterDistance) {
float[] distanceArray = new float[1];
Location.distanceBetween(userLocation.getLatitude(), userLocation.getLongitude(), latestLocation.getLatitude(), latestLocation.getLongitude(), userLocation.getAssignedDate(),distanceArray);
return (distanceArray[0]<localFilterDistance);
}
public void onLocationChanged(Location location) {
if (location != null) {
latestLocation = location;
for (UserLocation userLocation : userLocations) {
if (!(userLocations.isVisited()) && userLocationIsWithinGeofence(userLocation, latestLocation, LOCAL_FILTER_DISTANCE)) {
notifiedLocationsList.add(userLocation);
}
}
}
}
}
Code for BroadcastReceiver
package com.android.locationmang;
public class LocationNotificationReceiver extends BroadcastReceiver {
private static final int NOTIFICATION_ID = 1000;
public static final String EVENT_ID_INTENT_EXTRA = "EventIDIntentExtraKey";
#SuppressWarnings("deprecation")
#Override
public void onReceive(Context context, Intent intent) {
String key = LocationManager.KEY_PROXIMITY_ENTERING;
long eventID = intent.getLongExtra(EVENT_ID_INTENT_EXTRA, -1);
Boolean entering = intent.getBooleanExtra(key, false);
if (entering) {
Log.d(getClass().getSimpleName(), "entering");
}
else{
Log.d(getClass().getSimpleName(), "exiting");
}
String ns = Context.NOTIFICATION_SERVICE;
NotificationManager mNotificationManager = (NotificationManager) context.getSystemService(ns);
Intent notificationIntent = new Intent(context, MarkAsCompleteActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, notificationIntent, 0);
Notification notification = createNotification();
notification.setLatestEventInfo(context, "Proximity Alert!", "You are near your point of interest.", pendingIntent);
mNotificationManager.notify(NOTIFICATION_ID, notification);
}
private Notification createNotification() {
Notification notification = new Notification();
notification.icon = R.drawable.ic_launcher;
notification.when = System.currentTimeMillis();
notification.flags |= Notification.FLAG_AUTO_CANCEL;
notification.flags |= Notification.FLAG_SHOW_LIGHTS;
notification.defaults |= Notification.DEFAULT_VIBRATE;
notification.defaults |= Notification.DEFAULT_SOUND;
notification.defaults |= Notification.DEFAULT_LIGHTS;
notification.ledARGB = Color.WHITE;
notification.ledOnMS = 1500;
notification.ledOffMS = 1500;
return notification;
}
}
Thanks and Regards

You are creating a broadcast Intent with an action string, and your <receiver> element does not have the corresponding <intent-filter>. Change:
Intent intent = new Intent(PROX_ALERT_INTENT);
to:
Intent intent = new Intent(this, LocationNotificationReceiver.class);

Related

How to make Notification drop down and not only show on Status Bar?

I'm doing a notification on android and want it to drop-down instead of only showing on the status bar, but I can't seem to make it work. I've tried changing priority, importance of the channel, etc, but it won't work. Can someone help?
The code is this:
public class MainActivity4 extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main4);
createNotificationChannel();
}
public void showTopDownNotif(View v) {
int icon = R.drawable.alarm_icon;
String title = "Próxima alarman en: ";
String text = "15 min";
NotificationCompat.Builder builder = new NotificationCompat.Builder(this, "nchannel");
builder.setSmallIcon(icon);
builder.setContentTitle(title);
builder.setContentText(text);
builder.setPriority(NotificationCompat.PRIORITY_MAX);
builder.setAutoCancel(true);
builder.setDefaults(NotificationCompat.DEFAULT_ALL);
builder.setVisibility(NotificationCompat.VISIBILITY_PUBLIC);
NotificationManagerCompat notifManager = NotificationManagerCompat.from(this);
notifManager.notify(1, builder.build());
}
private void createNotificationChannel() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
CharSequence name = "NotifChannel";
String description = "Canal de notificaciones";
int importance = NotificationManager.IMPORTANCE_HIGH;
NotificationChannel channel = new NotificationChannel("nchannel", name, importance);
channel.setDescription(description);
NotificationManager notificationManager = getSystemService(NotificationManager.class);
notificationManager.createNotificationChannel(channel);
}
}
}

Android: How to fix BroadcastReceiver in JobIntentService?

I have an Activity with an AlarmManager that fires a BroadcastReceiver. The BroadcastReceiver fires a JobIntentService to send a Notification to the user.
When the user taps "CLEAR ALL" or swipes to dismiss the Notification, I want the setDeleteIntent() to reset a counter variable "totalMessages" to zero that I set up in a SharedPreferences file. It is not resetting to zero. What am I missing here?
public class AlarmService extends JobIntentService {
static final int JOB_ID = 9999;
public static final String NOTIFICATIONS_COUNTER = "NotificationsCounter";
private static final int REQUEST_CODE_DELETE_INTENT = 1;
int totalMessages = 0;
static void enqueueWork(Context context, Intent work) {
enqueueWork(context, AlarmService.class, JOB_ID, work);
}
#Override
protected void onHandleWork(#NonNull Intent intent) {
IntentFilter filter = new IntentFilter();
filter.addAction("notification_cleared");
registerReceiver(receiver, filter);
sendNotification();
}
private void sendNotification() {
int notifyID = 1;
NotificationManager notificationManager = (NotificationManager) this.getSystemService(Context.NOTIFICATION_SERVICE);
SharedPreferences sp = getSharedPreferences(NOTIFICATIONS_COUNTER, Context.MODE_PRIVATE);
totalMessages = sp.getInt("total-messages", 0); //initialize to 0 if it doesn't exist
SharedPreferences.Editor editor = sp.edit();
editor.putInt("total-messages", ++totalMessages);
editor.apply();
NotificationCompat.Builder mBuilder =
new NotificationCompat.Builder(this, NOTIFICATION_CHANNEL_ID)
.setDefaults(Notification.DEFAULT_ALL)
.setSmallIcon(R.drawable.ic_announcement_white_24dp)
.setContentText("")
Intent i = new Intent(this, AlarmService.class);
i.setAction("notification_cleared");
PendingIntent deleteIntent = PendingIntent.getBroadcast(this,REQUEST_CODE_DELETE_INTENT,i,PendingIntent.FLAG_CANCEL_CURRENT);
mBuilder.setDeleteIntent(deleteIntent);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
mBuilder.setSubText(String.valueOf(totalMessages));
}
else {
mBuilder.setNumber(totalMessages);
}
if (notificationManager != null) {
notificationManager.notify(notifyID, mBuilder.build());
}
}
private final BroadcastReceiver receiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (action != null) {
if (action.equals("notification_cleared")) {
// Reset the Notifications counter ("total-messages") to zero since the user
// clicked on "CLEAR ALL" Notification or swiped to delete a Notification.
SharedPreferences sp1 = getSharedPreferences(NOTIFICATIONS_COUNTER, Context.MODE_PRIVATE);
SharedPreferences.Editor editor = sp1.edit();
editor.clear();
editor.apply();
totalMessages = sp1.getInt("total-messages", 0); //initialize to 0 if it doesn't exist
editor.putInt("total-messages", totalMessages);
editor.apply();
}
}
}
};
#Override
public void onDestroy() {
super.onDestroy();
unregisterReceiver(receiver);
}
}
The problem is that your broadcast receiver's implementation to clear notifications is within the life-cycle of job. JobIntentService is tasked to show notification and go away thus the broadcast receiver. But when the user clicks on the CLEAR from notification, the pending intent is broadcasted but then there's no one to listen to it.
For a solution, I would suggest you to create a separate broadcast receiver and register it in your AndroidManifest.xml. By then your broadcast will always be listened and you can perform what ever within..

netty different channelpool and exception process

I am new to netty and I have a problem using my netty program.
in initConnection method I want to make a different channelpool for each group.
when user group A come in my sendToMessage I want to create channelPool A
like this way user group B come in my sendToMessage I want to create channelPool B and next time if user group A come in again, i will return channelPool A
Is it right to try doing this? Is it possible?
FixedChannelPool error handling
tell me how can I FixedChannelPool error handling? Could I use acquireTimeoutMillis over time.how?
Here is my code
#Service
public class NettyPoolService {
public static final AttributeKey<CompletableFuture<String>> FUTURE = AttributeKey.valueOf("future");
private static final StringDecoder stringDecoder = new StringDecoder(CharsetUtil.UTF_8);
private static final StringEncoder stringEncoder = new StringEncoder(CharsetUtil.UTF_8);
private static ChannelPool channelPool;
private static EventLoopGroup eventLoopGroup;
#Value("${host}")
private String host;
#Value("${port}")
private String port;
#Value("${connection.count}")
private String numberOfConnections;
#Value("${thread.count}")
private String numberOfThreads;
private synchronized void initConnection (String host, int port, int numberOfThreads, int numberOfConnections,String userGroup) {
if ( (channelPool != null) && (eventLoopGroup != null) ) {
return;
}
System.out.println("#############################################");
System.out.println("initConnection start");
eventLoopGroup = new NioEventLoopGroup(numberOfThreads);
Bootstrap bootstrap = new Bootstrap();
bootstrap.option(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT);
bootstrap.option(ChannelOption.SO_KEEPALIVE, true);
//bootstrap.option(ChannelOption.WRITE_BUFFER_HIGH_WATER_MARK, 32 * 1024);
//bootstrap.option(ChannelOption.WRITE_BUFFER_LOW_WATER_MARK, 8 * 1024);
//bootstrap.option(ChannelOption.TCP_NODELAY, true);
bootstrap.group(eventLoopGroup).channel(NioSocketChannel.class).remoteAddress(host, port);
int acquireTimeoutMillis = 10000;
int maxPendingAcquires = Integer.MAX_VALUE;
channelPool = new FixedChannelPool(bootstrap,
new AbstractChannelPoolHandler() {
public void channelCreated(Channel ch) throws Exception {
ChannelPipeline pipeline = ch.pipeline();
// decoders
pipeline.addLast("framer", new DelimiterBasedFrameDecoder(8192, Delimiters.lineDelimiter()));
pipeline.addLast("stringDecoder", stringDecoder);
// encoders
pipeline.addLast("stringEncoder", stringEncoder);
// business logic handler
pipeline.addLast("clientHandler", new ClientPoolHandler(channelPool));
}
},
ChannelHealthChecker.ACTIVE,//eventloop
AcquireTimeoutAction.NEW, //timeout
acquireTimeoutMillis, //
numberOfConnections, //
maxPendingAcquires); //
System.out.println("initConnection End");
System.out.println("#############################################");
}//initConnection
public void sendToMessage(String message,String GroupId) {
System.out.println("=============GroupId=============:"+GroupId);
if (channelPool == null) {
initConnection(host, Integer.parseInt(port.trim()), Integer.parseInt(numberOfThreads.trim()), Integer.parseInt(numberOfConnections.trim()) );
}
final CompletableFuture<String> future = new CompletableFuture<String>();
Future<Channel> channelFuture = channelPool.acquire();
System.out.println("=============channelFuture.get()=============:"+channelFuture.toString());
channelFuture.addListener(new FutureListener<Channel>() {
public void operationComplete(Future<Channel> f) {
if (f.isSuccess()) {
Channel channel = f.getNow();
channel.attr(NettyPoolClientService.FUTURE).set(future);
channel.writeAndFlush(message, channel.voidPromise());
}
}
});
channelFuture.syncUninterruptibly();
}//sendToBnp
}

NativeExpressAdView java.lang.IndexOutOfBoundsException: Invalid index 0, size is 0

I am working on android app which fetch data using RecyclerView and Retrofit for parsing JSON Url. I had following tutorial on this Github
My project on Android Studio has no Errors and I'm able to run the Application. But when I open the MainActivity it crashes.
Error that i am get
java.lang.IndexOutOfBoundsException: Invalid index 0, size is 0
This is the following line is on setUpAndLoadNativeExpressAds
final NativeExpressAdView adView = (NativeExpressAdView) mRecyclerViewItems.get(i);
This is MainActivity
public class MainActivity extends AppCompatActivity{
public static final int ITEMS_PER_AD = 3;
private static final int NATIVE_EXPRESS_AD_HEIGHT = 150;
private static final String AD_UNIT_ID = ADMOB_NATIVE_MENU_ID;
private StartAppAd startAppAd = new StartAppAd(this);
private RecyclerView mRecyclerView;
private List<Object> mRecyclerViewItems = new ArrayList<>();
private KontenAdapter kontenAdapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mRecyclerView = (RecyclerView) findViewById(R.id.recycler_view);
// Use this setting to improve performance if you know that changes
// in content do not change the layout size of the RecyclerView.
mRecyclerView.setHasFixedSize(true);
// Specify a linear layout manager.
RecyclerView.LayoutManager layoutManager = new LinearLayoutManager(this);
mRecyclerView.setLayoutManager(layoutManager);
// mRecyclerViewItems = new ArrayList<>();
// Update the RecyclerView item's list with menu items and Native Express ads.
// addMenuItemsFromJson();
loadJSON();
// initData();
setUpAndLoadNativeExpressAds();
}
/**
* Adds Native Express ads to the items list.
*/
private void addNativeExpressAds() {
// Loop through the items array and place a new Native Express ad in every ith position in
// the items List.
for (int i = 0; i <= mRecyclerViewItems.size(); i += ITEMS_PER_AD) {
final NativeExpressAdView adView = new NativeExpressAdView(MainActivity.this);
mRecyclerViewItems.add(i, adView);
}
}
/**
* Sets up and loads the Native Express ads.
*/
private void setUpAndLoadNativeExpressAds() {
mRecyclerView.post(new Runnable() {
#Override
public void run() {
final float scale = MainActivity.this.getResources().getDisplayMetrics().density;
// Set the ad size and ad unit ID for each Native Express ad in the items list.
for (int i = 0; i <= mRecyclerViewItems.size(); i += ITEMS_PER_AD) {
final NativeExpressAdView adView = (NativeExpressAdView) mRecyclerViewItems.get(i);
final CardView cardView = (CardView) findViewById(R.id.ad_card_view);
final int adWidth = cardView.getWidth() - cardView.getPaddingLeft()
- cardView.getPaddingRight();
AdSize adSize = new AdSize((int) (adWidth / scale), NATIVE_EXPRESS_AD_HEIGHT);
adView.setAdSize(adSize);
adView.setAdUnitId(AD_UNIT_ID);
}
// Load the first Native Express ad in the items list.
loadNativeExpressAd(0);
}
});
}
/**
* Loads the Native Express ads in the items list.
*/
private void loadNativeExpressAd(final int index) {
if (index >= mRecyclerViewItems.size()) {
return;
}
Object item = mRecyclerViewItems.get(index);
if (!(item instanceof NativeExpressAdView)) {
throw new ClassCastException("Expected item at index " + index + " to be a Native"
+ " Express ad.");
}
final NativeExpressAdView adView = (NativeExpressAdView) item;
// Set an AdListener on the NativeExpressAdView to wait for the previous Native Express ad
// to finish loading before loading the next ad in the items list.
adView.setAdListener(new AdListener() {
#Override
public void onAdLoaded() {
super.onAdLoaded();
// The previous Native Express ad loaded successfully, call this method again to
// load the next ad in the items list.
loadNativeExpressAd(index + ITEMS_PER_AD);
}
#Override
public void onAdFailedToLoad(int errorCode) {
// The previous Native Express ad failed to load. Call this method again to load
// the next ad in the items list.
Log.e("MainActivity", "The previous Native Express ad failed to load. Attempting to"
+ " load the next Native Express ad in the items list.");
loadNativeExpressAd(index + ITEMS_PER_AD);
}
});
// Load the Native Express ad.
adView.loadAd(new AdRequest.Builder().build());
}
private void loadJSON() {
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://api.myjson.com/") //https://api.myjson.com/bins/v4dzd
.addConverterFactory(GsonConverterFactory.create())
.build();
RequestInterface request = retrofit.create(RequestInterface.class);
Call<JSONResponse> call = request.getJSON();
call.enqueue(new Callback<JSONResponse>() {
#Override
public void onResponse(Call<JSONResponse> call, Response<JSONResponse> response) {
JSONResponse jsonResponse = response.body();
mRecyclerViewItems = new ArrayList<Object>(Arrays.asList(jsonResponse.getKonten()));
addNativeExpressAds();
RecyclerView.Adapter adapter = new KontenAdapter(mRecyclerViewItems, getApplicationContext());
mRecyclerView.setAdapter(adapter);
}
#Override
public void onFailure(Call<JSONResponse> call, Throwable t) {
Log.d("Error", t.getMessage());
}
});
}
/**
* Adds {#link KontenItem}'s from a JSON file.
*/
private void addMenuItemsFromJson() {
try {
String jsonDataString = readJsonDataFromFile();
JSONArray menuItemsJsonArray = new JSONArray(jsonDataString);
for (int i = 0; i < menuItemsJsonArray.length(); ++i) {
JSONObject menuItemObject = menuItemsJsonArray.getJSONObject(i);
String menuItemName = menuItemObject.getString("name");
String menuItemDescription = menuItemObject.getString("description");
String menuItemPrice = menuItemObject.getString("price");
String menuItemCategory = menuItemObject.getString("category");
String menuItemImageName = menuItemObject.getString("photo");
String menuItemUrl = menuItemObject.getString("url");
KontenItem kontenItem = new KontenItem(menuItemName, menuItemDescription, menuItemPrice,
menuItemCategory, menuItemImageName, menuItemUrl);
mRecyclerViewItems.add(kontenItem);
}
} catch (IOException | JSONException exception) {
Log.e(MainActivity.class.getName(), "Unable to parse JSON file.", exception);
}
}
/**
* Reads the JSON file and converts the JSON data to a {#link String}.
*
* #return A {#link String} representation of the JSON data.
* #throws IOException if unable to read the JSON file.
*/
private String readJsonDataFromFile() throws IOException {
InputStream inputStream = null;
StringBuilder builder = new StringBuilder();
try {
String jsonDataString = null;
inputStream = getResources().openRawResource(R.raw.menu_items_json);
BufferedReader bufferedReader = new BufferedReader(
new InputStreamReader(inputStream, "UTF-8"));
while ((jsonDataString = bufferedReader.readLine()) != null) {
builder.append(jsonDataString);
}
} finally {
if (inputStream != null) {
inputStream.close();
}
}
return new String(builder);
}
}
This is MyAdapter
public class KontenAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
// A menu item view type.
private static final int MENU_ITEM_VIEW_TYPE = 0;
// The Native Express ad view type.
private static final int NATIVE_EXPRESS_AD_VIEW_TYPE = 1;
// An Activity's Context.
private final Context mContext;
// The list of Native Express ads and menu items.
private final List<Object> mRecyclerViewItems;
public KontenAdapter(List<Object> recyclerViewItems, Context context) {
this.mContext = context;
this.mRecyclerViewItems = recyclerViewItems;
}
/**
* The {#link MenuItemViewHolder} class.
* Provides a reference to each view in the menu item view.
*/
public class MenuItemViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener{
private TextView menuItemName;
private TextView menuItemDescription;
private TextView menuItemPrice;
private TextView menuItemCategory;
private ImageView menuItemImage;
private TextView menuItemUrl;
MenuItemViewHolder(View view) {
super(view);
menuItemImage = (ImageView) view.findViewById(R.id.menu_item_image);
menuItemName = (TextView) view.findViewById(R.id.menu_item_name);
menuItemPrice = (TextView) view.findViewById(R.id.menu_item_price);
menuItemCategory = (TextView) view.findViewById(R.id.menu_item_category);
menuItemDescription = (TextView) view.findViewById(R.id.menu_item_description);
menuItemUrl = (TextView) view.findViewById(R.id.menu_item_url);
view.setOnClickListener(this);
}
#Override
public void onClick(View v) {
Intent detailIntent = new Intent(v.getContext(), PostActivity.class);
detailIntent.putExtra("name",menuItemName.getText().toString() );
detailIntent.putExtra("url", menuItemUrl.getText().toString());
mContext.startActivity(detailIntent);
}
}
/**
* The {#link NativeExpressAdViewHolder} class.
*/
public class NativeExpressAdViewHolder extends RecyclerView.ViewHolder {
NativeExpressAdViewHolder(View view) {
super(view);
}
}
#Override
public int getItemCount() {
return mRecyclerViewItems.size();
}
/**
* Determines the view type for the given position.
*/
#Override
public int getItemViewType(int position) {
return (position % MainActivity.ITEMS_PER_AD == 0) ? NATIVE_EXPRESS_AD_VIEW_TYPE
: MENU_ITEM_VIEW_TYPE;
}
/**
* Creates a new view for a menu item view or a Native Express ad view
* based on the viewType. This method is invoked by the layout manager.
*/
#Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) {
switch (viewType) {
case MENU_ITEM_VIEW_TYPE:
View menuItemLayoutView = LayoutInflater.from(viewGroup.getContext()).inflate(
R.layout.menu_item_container, viewGroup, false);
return new MenuItemViewHolder(menuItemLayoutView);
case NATIVE_EXPRESS_AD_VIEW_TYPE:
// fall through
default:
View nativeExpressLayoutView = LayoutInflater.from(
viewGroup.getContext()).inflate(R.layout.native_express_ad_container,
viewGroup, false);
return new NativeExpressAdViewHolder(nativeExpressLayoutView);
}
}
/**
* Replaces the content in the views that make up the menu item view and the
* Native Express ad view. This method is invoked by the layout manager.
*/
#Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
int viewType = getItemViewType(position);
switch (viewType) {
case MENU_ITEM_VIEW_TYPE:
MenuItemViewHolder menuItemHolder = (MenuItemViewHolder) holder;
KontenItem kontenItem = (KontenItem) mRecyclerViewItems.get(position);
// Get the menu item image resource ID.
String imageName = kontenItem.getImageName();
int imageResID = mContext.getResources().getIdentifier(imageName, "drawable",
mContext.getPackageName());
// Add the menu item details to the menu item view.
menuItemHolder.menuItemImage.setImageResource(imageResID);
menuItemHolder.menuItemName.setText(kontenItem.getName());
menuItemHolder.menuItemPrice.setText(kontenItem.getPrice());
menuItemHolder.menuItemCategory.setText(kontenItem.getCategory());
menuItemHolder.menuItemDescription.setText(kontenItem.getDescription());
menuItemHolder.menuItemUrl.setText(kontenItem.getInstructionUrl());
break;
case NATIVE_EXPRESS_AD_VIEW_TYPE:
// fall through
default:
NativeExpressAdViewHolder nativeExpressHolder =
(NativeExpressAdViewHolder) holder;
NativeExpressAdView adView =
(NativeExpressAdView) mRecyclerViewItems.get(position);
ViewGroup adCardView = (ViewGroup) nativeExpressHolder.itemView;
// The NativeExpressAdViewHolder recycled by the RecyclerView may be a different
// instance than the one used previously for this position. Clear the
// NativeExpressAdViewHolder of any subviews in case it has a different
// AdView associated with it, and make sure the AdView for this position doesn't
// already have a parent of a different recycled NativeExpressAdViewHolder.
if (adCardView.getChildCount() > 0) {
adCardView.removeAllViews();
}
if (adView.getParent() != null) {
((ViewGroup) adView.getParent()).removeView(adView);
}
// Add the Native Express ad to the native express ad view.
adCardView.addView(adView);
}
}
}
KontenItem.java
class KontenItem {
private final String name;
private final String description;
private final String price;
private final String category;
private final String imageName;
private final String instructionUrl;
public KontenItem(String name, String description, String price, String category,
String imageName, String instructionUrl) {
this.name = name;
this.description = description;
this.price = price;
this.category = category;
this.imageName = imageName;
this.instructionUrl = instructionUrl;
}
public String getName() {
return name;
}
public String getDescription() {
return description;
}
public String getPrice() {
return price;
}
public String getCategory() {
return category;
}
public String getImageName() {
return imageName;
}
public String getInstructionUrl() {
return instructionUrl;
}
}
Thanks in advance!
You are calling addNativeExpressAds() and
for (int i = 0; i <= mRecyclerViewItems.size(); i += ITEMS_PER_AD) {
final NativeExpressAdView adView = (NativeExpressAdView) mRecyclerViewItems.get(i);
in different threads. So, mRecyclerViewItems.get(i) is used before its initialization.
I would suggest to use
#Override
public void onResponse(Call<JSONResponse> call, Response<JSONResponse> response) {
JSONResponse jsonResponse = response.body();
mRecyclerViewItems = new ArrayList<Object>(Arrays.asList(jsonResponse.getKonten()));
addNativeExpressAds();
RecyclerView.Adapter adapter = new KontenAdapter(mRecyclerViewItems, getApplicationContext());
mRecyclerView.setAdapter(adapter);
setUpAndLoadNativeExpressAds(); // << ADD THIS METHOD HERE AND REMOVE THE OTHER CALLING
}
Your problem is that mRecyclerViewItems is a zero based array/collection. Yet in setUpAndLoadNativeExpressAds() you will iterate even if you have no elements, and then ask for element 0.
for (int i = 0; i <= mRecyclerViewItems.size(); i += ITEMS_PER_AD) {
final NativeExpressAdView adView = (NativeExpressAdView) mRecyclerViewItems.get(i);
..
}
you should instead
for (int i = 0; i < mRecyclerViewItems.size(); i += ITEMS_PER_AD) {
..
}

Using LocationListener (with google play service) as service consume too much battery (Android 4.4.2)

I have a service that returns the current position every 30 seconds, my problem is that the service consumes about 40% of the battery. The GPS icon is always active, even if I increase the time interval. I see this problem with my Nexus 4 android 4.4.2. Once the callback OnLocationChanged is called, the GPS is awake all the time and this consumes the entire battery. With my other Phone Nexus One android 2.2.3 , I do not see this problem, the GPS turns on every 30 seconds and turns off. And I have no battery consommation. The service use Location Request, with .setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY), excepted to use GPS and Network and is not the case. I thinks there is a problem with android 4.4.2 or is Google play service
Here my service code:
public class MyServiceGpsDebug extends Service implements
GooglePlayServicesClient.ConnectionCallbacks,
GooglePlayServicesClient.OnConnectionFailedListener,LocationListener
{
IBinder mBinder = new LocalBinder();
private LocationClient mLocationClient;
private LocationRequest mLocationRequest;
// Flag that indicates if a request is underway.
private boolean mInProgress;
private Boolean servicesAvailable = false;
public class LocalBinder extends Binder
{
public MyServiceGpsDebug getServerInstance()
{
return MyServiceGpsDebug.this;
}
}
#Override
public void onCreate()
{
super.onCreate();
mInProgress = false;
// Create the LocationRequest object
mLocationRequest = LocationRequest.create();
// Use high accuracy
mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
// Set the update interval to 5 seconds
mLocationRequest.setInterval(Constants.UPDATE_INTERVAL);
// Set the fastest update interval to 1 second
mLocationRequest.setFastestInterval(Constants.FASTEST_INTERVAL);
servicesAvailable = servicesConnected();
mLocationClient = new LocationClient(this, this, this);
}
private boolean servicesConnected()
{
// Check that Google Play services is available
int resultCode = GooglePlayServicesUtil.isGooglePlayServicesAvailable(this);
// If Google Play services is available
if (ConnectionResult.SUCCESS == resultCode)
{
return true;
}
else
{
return false;
}
}
public int onStartCommand (Intent intent, int flags, int startId)
{
super.onStartCommand(intent, flags, startId);
if(!servicesAvailable || mLocationClient.isConnected() || mInProgress)
return START_STICKY;
setUpLocationClientIfNeeded();
if(!mLocationClient.isConnected() || !mLocationClient.isConnecting() && !mInProgress)
{
appendLog(DateFormat.getDateTimeInstance().format(new Date()) + ": Started", Constants.LOG_FILE);
mInProgress = true;
mLocationClient.connect();
}
return START_STICKY;
}
private void setUpLocationClientIfNeeded()
{
if(mLocationClient == null)
mLocationClient = new LocationClient(this, this, this);
}
#Override
public void onLocationChanged(Location location)
{
// Report to the UI that the location was updated
String msg = Double.toString(location.getLatitude()) + "," + Double.toString(location.getLongitude());
Log.d("debug", msg);
// Toast.makeText(this, msg, Toast.LENGTH_SHORT).show();
appendLog(msg, Constants.LOCATION_FILE);
}
#Override
public IBinder onBind(Intent intent)
{
return mBinder;
}
public String getTime()
{
SimpleDateFormat mDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
return mDateFormat.format(new Date());
}
public void appendLog(String text, String filename)
{
File logFile = new File(filename);
if (!logFile.exists())
{
try
{
logFile.createNewFile();
}
catch (IOException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
}
try
{
//BufferedWriter for performance, true to set append to file flag
BufferedWriter buf = new BufferedWriter(new FileWriter(logFile, true));
buf.append(text);
buf.newLine();
buf.close();
}
catch (IOException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
}
#Override
public void onDestroy()
{
// Turn off the request flag
mInProgress = false;
if(servicesAvailable && mLocationClient != null)
{
mLocationClient.removeLocationUpdates(this);
// Destroy the current location client
mLocationClient = null;
}
// Display the connection status
// Toast.makeText(this, DateFormat.getDateTimeInstance().format(new Date()) + ": Disconnected. Please re-connect.", Toast.LENGTH_SHORT).show();
appendLog(DateFormat.getDateTimeInstance().format(new Date()) + ": Stopped", Constants.LOG_FILE);
super.onDestroy();
}
#Override
public void onConnected(Bundle bundle)
{
// Request location updates using static settings
mLocationClient.requestLocationUpdates(mLocationRequest, this);
appendLog(DateFormat.getDateTimeInstance().format(new Date()) + ": Connected", Constants.LOG_FILE);
}
#Override
public void onDisconnected()
{
// Turn off the request flag
mInProgress = false;
// Destroy the current location client
mLocationClient = null;
// Display the connection status
// Toast.makeText(this, DateFormat.getDateTimeInstance().format(new Date()) + ": Disconnected. Please re-connect.", Toast.LENGTH_SHORT).show();
appendLog(DateFormat.getDateTimeInstance().format(new Date()) + ": Disconnected", Constants.LOG_FILE);
}
#Override
public void onConnectionFailed(ConnectionResult connectionResult)
{
mInProgress = false;
if (connectionResult.hasResolution())
{
// If no resolution is available, display an error dialog
} else {
}
}
public final class Constants
{
// Milliseconds per second
private static final int MILLISECONDS_PER_SECOND = 1000;
// Update frequency in seconds
private static final int UPDATE_INTERVAL_IN_SECONDS = 60;
// Update frequency in milliseconds
public static final long UPDATE_INTERVAL = MILLISECONDS_PER_SECOND * UPDATE_INTERVAL_IN_SECONDS;
// The fastest update frequency, in seconds
private static final int FASTEST_INTERVAL_IN_SECONDS = 60;
// A fast frequency ceiling in milliseconds
public static final long FASTEST_INTERVAL = MILLISECONDS_PER_SECOND * FASTEST_INTERVAL_IN_SECONDS;
// Stores the lat / long pairs in a text file
public static final String LOCATION_FILE = "sdcard/location.txt";
// Stores the connect / disconnect data in a text file
public static final String LOG_FILE = "sdcard/log.txt";
/**
* Suppress default constructor for noninstantiability
*/
private Constants() {
throw new AssertionError();
}
}
}
I have similar problem with Nexus 4. My app has a service which uses location updates (fusion location or android providers, not both). Everything works OK for all android phones but in Nexus4 after some time the phone gets hot and slow even if i kill the app (through DDMS, 100% stopped). The only solution is to kill Google play services .
I think that there is a bug in play services for nexus 4. There is a dirty solution to kill Google Play Services every 30mins for example if phone=nexus4, but i do not know if it is possible