1

Suppose the address www.foo.com/notification.txt is updated often with a formatted string that must be shown as a notification in an Android device. What's the best approach for getting that string?

I've tried several things. My last attempt was creating a class that extends a BroadcastReceiver and configuring ALARM_SERVICE to call it repeatedly:

AndroidManifest.xml:

 <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"></uses-permission>
 <receiver  android:process=":remote" android:name="Alarm"></receiver>
    <receiver android:name=".AutoStart">
        <intent-filter>
            <action android:name="android.intent.action.BOOT_COMPLETED"></action>
        </intent-filter>
    </receiver>

Alarm.java:

package br.com.mypackage.cfqm;
import java.io.BufferedReader;
import java.io.InputStreamReader;

import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.protocol.BasicHttpContext;
import org.apache.http.protocol.HttpContext;

import android.app.AlarmManager;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.net.Uri;
import android.os.StrictMode;
import android.preference.PreferenceManager;
import android.support.v4.app.NotificationCompat;
import android.support.v4.app.TaskStackBuilder;
import android.util.Log;
import android.widget.Toast;

public class Alarm extends BroadcastReceiver 
{    
    int period_ms = 5*60*1000;
    SharedPreferences prefs;
    String user;
    String pass;
    Context context;

    public void check_notifications(){
            //http request to get and parse the notifications
        String[] notifications = http_request("http://foo.com/notification.html")).split("\n");

        NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
        notificationManager.cancelAll();
        int notification_next_id = 0;


        for (String notification_line:notifications){
            String[] notification = notification_line.split(";");
            if (notification.length==3)
                notify(notification_next_id++,notification[0],notification[1],notification[2]);
        }
    }

    public void notify(Integer id,String title,String text,String url){
            //displays a single notification
        NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);

        NotificationCompat.Builder notificationBuilder =
            new NotificationCompat.Builder(context)
                .setSmallIcon(R.drawable.ic_action_search)
                .setAutoCancel(true)
                .setContentTitle(title)
                .setContentText(text);
        Intent resultIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));

        TaskStackBuilder stackBuilder = TaskStackBuilder.create(context);
        stackBuilder.addParentStack(Main.class);
        stackBuilder.addNextIntent(resultIntent);
        PendingIntent resultPendingIntent = stackBuilder.getPendingIntent(0,PendingIntent.FLAG_UPDATE_CURRENT);
        notificationBuilder.setContentIntent(resultPendingIntent);
        notificationManager.notify(id,notificationBuilder.build());
        Log.v("cfqm","notificado");

    }

    public String http_request(String url) {
            //makes a http request
        try {
            HttpClient httpClient = new DefaultHttpClient();
            HttpContext localContext = new BasicHttpContext();
            HttpGet httpGet = new HttpGet(url);
            HttpResponse response = httpClient.execute(httpGet, localContext);
            String result = ""; 

            BufferedReader reader = new BufferedReader(new InputStreamReader(response.getEntity().getContent()));
            String line = null;
            while ((line = reader.readLine()) != null)
              result += line + "\n";
            return result;
        }
        catch (Exception e){
            e.printStackTrace();
            return "";
        }

    }


     @Override
     public void onReceive(Context ctx, Intent intent) 
     {
         context = ctx;

         StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
         StrictMode.setThreadPolicy(policy); 

         // The function below will be called periodically
         check_notifications();
     }

     public void SetAlarm(Context context)
     {
         prefs = PreferenceManager.getDefaultSharedPreferences(context);
         user = prefs.getString("user","");
         pass = prefs.getString("pass","");

         AlarmManager am = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
         Intent i = new Intent(context, Alarm.class);
         PendingIntent pi = PendingIntent.getBroadcast(context, 0, i, 0);
         am.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(), period_ms, pi); // Millisec * Second * Minute
     }

     public void CancelAlarm(Context context)
     {
         Intent intent = new Intent(context, Alarm.class);
         PendingIntent sender = PendingIntent.getBroadcast(context, 0, intent, 0);
         AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
         alarmManager.cancel(sender);
     }
 }

I can make the function check_notifications to run repeatedly if all I do there is Log a string. But wheter I use http_request inside weird things happen, from the app crashing, to the whole system freezing. I understand I was supposed to run it async. But how?

Marcin Orlowski
  • 72,056
  • 11
  • 123
  • 141
MaiaVictor
  • 51,090
  • 44
  • 144
  • 286
  • That weird things like app crashing in most cases left **valuable** information about the cause in logs. Investigating LogCat output prior asking here usually helps. If you fail interpreting the logcat output, you may try to google it. If still no success, asking question quote logcat – Marcin Orlowski Dec 02 '12 at 22:20

1 Answers1

1

You have to use AsyncTask.

Android Documentation here: Async Class Its pretty simple.

Also if you want this to run periodically, consider using a Service(Service Class)

Also the app crashes because you are running something on main thread, and not in the background. So everything freezes until you got the result from webpage. And in situations of heavy load on that webpage you have to wait.

Async class Example:

 private class MyAsyncTask extends AsyncTask<URL, Integer, Integer> {

 protected Integer doInBackground(URL... urls) {
     int count = urls.length;
     long totalSize = 0;
//This is for many urls. If you download staff only from one url use url[0] instead of a for-loop. 
     for (int i = 0; i < count; i++) {
         //do something with url[i]
     }
     return 0; //or return some stats you can later use (eg how many bytes downloaded)
 }

 protected void onProgressUpdate(Integer... progress) {
//You can completely skip this method. It is to show a progress bar of how % is done
     setProgressPercent(progress[0]);


 }

 protected void onPostExecute(Integer result) {
//This is where everything finishes, and you got the result of your webpage

     showDialog("Downloaded " + result + " bytes");
 }
}

And then, create a new AsyncTask object, and start the task like this:

asyncTaskObj.execute(...);
Paschalis
  • 11,929
  • 9
  • 52
  • 82
  • I have no idea on how to modify that code to use the Async class (I'm not an Android developer, just making this simple app as an exeption, so sorry, really). What exactly should be done there. It was hard enough to make BroadcastReceiver to run periodically. So how do I make an AsyncTask, which is something completely different, run periodically, for example? – MaiaVictor Dec 02 '12 at 22:20
  • So I just have my `http_request` function to get the contents of that url, and my `notify` function, to display it using NotificationManager, inside doinBackground? Will it be completely fine, even if the HttpRequest is running Sync there? And to make it run periodically, I just have this http://stackoverflow.com/questions/6531950/how-to-execute-async-task-repeatedly-after-fixed-time-intervals on my Main function? – MaiaVictor Dec 02 '12 at 22:35
  • you have to put your HTTP-Requests on the `doInBackground`, and when everything finished, `onPostExecute` is called. So `onPostExecute`, put whatever you want to do when your task is done! Yes, you can use that link's code(to make it run periodically). The async task in the link you have me is 'PerformBackgroundTask'. So replace it with your AsyncTask class name. I hope i helped you! – Paschalis Dec 02 '12 at 22:38
  • 1
    great, thank you. I'll try it. Know you was already too helpful, but could you come back here later for if I have some doubt? – MaiaVictor Dec 02 '12 at 22:44
  • i will, as soon as i have seen a notification. – Paschalis Dec 02 '12 at 22:51
  • I'm getting a Null Pointer exception on the line `NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);`, probably because context is not defined inside onPostExecute. What now? – MaiaVictor Dec 03 '12 at 00:29
  • Have you figured it out? You should search how to get Contect inside of async task! – Paschalis Dec 04 '12 at 09:35