Search code examples
androidbroadcastreceiverandroid-service

Collect data in a Service and send to Activity to update UI


Right now i have my main Activity which does the following: On creation it gathers data about the phone and running applications. I also do extra calculations and use different datatypes to store them to plot a graph (e.g i use a HashTable). i also have a handler that regathers the data and updates the charts and textviews every minute.

Now here comes the question. I am considering creating a Service (or IntentService?) to gather Data every minute and then send that data to the Activity so it can update the charts and whatnot.

1.For this approach who should use a handler , the activity , or the service ?

2.How can i make them communicate,will a BroadCastReceiver be the best solution?

3.If so, how do i send the data and what kind of data can i send ? For example i use aChartEngine to plot the graps. Basically i create a GraphicalView that holds the chart and then add it to a linearLayout. Can i send a GraphicalView from the Service and just add it to the LinearLayout inside the activity?

Can i send an entire list or a hashtable from the service to the main activity?

I am new to android development and i got stuck at this point, some tips and guides will help me alot. Thanks

LE: Stuff to collect inside the service

public void getAppResources() throws IOException{

    AndroidPowerCollector myCollector = new AndroidPowerCollector();

    //////Running apps///////
    ActivityManager actvityManager = (ActivityManager) this.getSystemService( ACTIVITY_SERVICE );
    List<RunningAppProcessInfo> myApps = actvityManager.getRunningAppProcesses();

    resourceTab.removeAllViews();

    if(cpu_Values.isEmpty() == false)
        cpu_Values.clear();

    if(gps_Values.isEmpty() == false)
        gps_Values.clear();

    if(wifi_Values.isEmpty() == false)
        wifi_Values.clear();

    double maxWIFI=0;
    double maxGPS=0;
    double maxCPU=0;

    highestDrainPackageCPU=null;
    highestDrainPackageGPS=null;
    highestDrainPackageWIFI=null;

    //////////////////////////////

    //Open file to save a log
    FileWriter file = new FileWriter(new File(log_path,"AppResources.txt"),true);

    //Get current time
    Calendar c = Calendar.getInstance();
    SimpleDateFormat sdf = new SimpleDateFormat("dd:MMMM:yyyy HH:mm:ss ");
    String date = sdf.format(c.getTime());

    file.write("TimeStamp:\t"+date+"\n");

    View delimitator;

    for(int i=0;i<myApps.size();i++){

        //Get App name or Package name
        PackageManager pm = this.getPackageManager();
        String name = null;
        try {
            name = (String) pm.getApplicationLabel(pm.getApplicationInfo((myApps.get(i)).processName, PackageManager.GET_META_DATA));
        } catch (NameNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        if(name == null)
            name=myApps.get(i).processName;

        TextView [] infoApp = new TextView[7];
        delimitator = new View(this);
        delimitator.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT,1));
        delimitator.setBackgroundColor(Color.parseColor("#50FFFFFF"));

        //////Setup textview//////////
        for(int j=0;j<7;j++){
            infoApp[j] = new TextView(this);
            infoApp[j].setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT,LayoutParams.WRAP_CONTENT));
            infoApp[j].setTextColor(Color.parseColor("#FFFFFF"));
        }

        //////Collect data/////

        PowerEvent current=myCollector.getPowerEvent(myApps.get(i).processName);

        infoApp[0].setText("App:\t"+name+"\nCPU Time\t"+String.format("%d",current.getCpuTime())+"ms");

        infoApp[1].setText("CPU Energy:\t"+String.format("%.2f",current.getCpuEnergy())+"mJ");

        infoApp[2].setText("GPS Time:\t"+String.format("%d",current.getGpsTime())+"ms");

        infoApp[3].setText("GPS Energy:\t"+String.format("%.2f",current.getGpsEnergy())+"mJ");

        infoApp[4].setText("Sent data WiFi:\t"+String.format("%d",TrafficStats.getUidTxBytes(myApps.get(i).uid))+"bytes");

        infoApp[5].setText("Recv data WiFi:\t"+String.format("%d",TrafficStats.getUidRxBytes(myApps.get(i).uid))+"bytes");

        if(current.getCpuEnergy() > 0){

            //Add CPU usage for PIE CHART
            BasicNameValuePair entry = new BasicNameValuePair(name, String.valueOf(Math.round(current.getCpuEnergy()*100.0)/100.0 ));
            cpu_Values.add(entry);

            //Add CPU usage for LINE CHART
            String packet=myApps.get(i).processName;

            if(tableCPU.containsKey(packet) == true){
                //Get existing values
                List<BasicNameValuePair> newList = new ArrayList<BasicNameValuePair>();
                newList = tableCPU.get(packet);
                //Add current value
                newList.add(new BasicNameValuePair(String.valueOf(realTime),String.valueOf(Math.round(current.getCpuEnergy()*100.0)/100.0)));
                //Replace value in hashtable
                tableCPU.put(packet,newList);
            }
            else{
                List<BasicNameValuePair> newList = new ArrayList<BasicNameValuePair>();
                //Add current value
                newList.add(new BasicNameValuePair(String.valueOf(realTime),String.valueOf(Math.round(current.getCpuEnergy()*100.0)/100.0)));
                tableCPU.put(packet, newList);
            }

            //Get highest draining package
            if(current.getCpuEnergy() > maxCPU){
                maxCPU=current.getCpuEnergy();
                highestDrainPackageCPU=packet;
            }
        }

        if(current.getGpsEnergy() > 0){
            //Add GPS usage for PIE CHART
            BasicNameValuePair entry = new BasicNameValuePair(name, String.valueOf(Math.round(current.getGpsEnergy()*100.0)/100.0 ));
            gps_Values.add(entry);

            //Add GPS usage for LINE CHART
            String packet=myApps.get(i).processName;

            if(tableGPS.containsKey(packet) == true){
                //Get existing values
                List<BasicNameValuePair> newList = new ArrayList<BasicNameValuePair>();
                newList = tableGPS.get(packet);
                //Add current value
                newList.add(new BasicNameValuePair(String.valueOf(realTime),String.valueOf(Math.round(current.getGpsEnergy()*100.0)/100.0)));
                //Replace value in hashtable
                tableGPS.put(packet,newList);
            }
            else{
                List<BasicNameValuePair> newList = new ArrayList<BasicNameValuePair>();
                //Add current value
                newList.add(new BasicNameValuePair(String.valueOf(realTime),String.valueOf(Math.round(current.getGpsEnergy()*100.0)/100.0)));
                tableGPS.put(packet, newList);
            }

            //Get package with highest GPS drain
            if(current.getGpsEnergy() > maxGPS){
                maxGPS=current.getGpsEnergy();
                highestDrainPackageGPS=packet;
            }
        }

        //transfer of 50KB over wifi =~ 920mJ
        double averageWifiEnergy=TrafficStats.getUidTxBytes(myApps.get(i).uid)+TrafficStats.getUidRxBytes(myApps.get(i).uid)/51200 * 920;

        infoApp[6].setText("WiFi Energy:\t"+String.format("%f",averageWifiEnergy)+"mJ");

        if(averageWifiEnergy > 0){
            //Add WIFI usage for PIE CHART
            BasicNameValuePair entry = new BasicNameValuePair(name, String.valueOf(averageWifiEnergy));
            wifi_Values.add(entry);

            //Add wifi usage for LINE CHART
            String packet=myApps.get(i).processName;

            if(tableWIFI.containsKey(packet) == true){
                //Get existing values
                List<BasicNameValuePair> newList = new ArrayList<BasicNameValuePair>();
                newList = tableWIFI.get(packet);
                //Add current value
                newList.add(new BasicNameValuePair(String.valueOf(realTime),String.valueOf(averageWifiEnergy)));
                //Replace value in hashtable
                tableWIFI.put(packet,newList);
            }
            else{
                List<BasicNameValuePair> newList = new ArrayList<BasicNameValuePair>();
                //Add current value
                newList.add(new BasicNameValuePair(String.valueOf(realTime),String.valueOf(averageWifiEnergy)));
                tableWIFI.put(packet, newList);
            }

            //Get highest Wifi draining package
            if(averageWifiEnergy > maxWIFI){
                maxWIFI=averageWifiEnergy;
                highestDrainPackageWIFI=packet;
            }
        }

        //add textviews to a linear layout
        for(int j=0;j<7;j++){
            resourceTab.addView(infoApp[j]);
        }
        resourceTab.addView(delimitator);

        //Write the log
        Log.d("LOGS","Write resource logs");
        for(int j=0;j<7;j++)
            file.write(infoApp[j].getText()+"\n"); 
    }
    file.close();
    realTime+=60;
}

Solution

  • Services don't come up with any UI so you will have to bind them/or use broadcast with activites.which in turn display the values in the UI after communicating with each other .To start a service from an activity .

    serviceIntent = new Intent(this, Music_service.class);
    
    serviceIntent.putParcelableArrayListExtra("sentAudioLink", songdetails);//here "sentAudioLink //is the key which needs to be same in the service ,so that you can send 
            serviceIntent.putExtra("postion_service", position);
    
    
                startService(serviceIntent);
    

    now the service has started....

    inside the service read the data which had been passed earlier

    songdetails = intent.getParcelableArrayListExtra("sentAudioLink");
            position = intent.getIntExtra("postion_service", 0);
            //note "sentAudioLink",its the key value,or the identifier which remains the same on sending and receiving
    

    But sending data using the above method just sends the value only once that is during the start of the service,but in your case you would constantly want to send and receive the data....

    so inside the service whatever you are calculating needs to be constantly sent to the activity so that UI can be updated and other things can be done ,in that case you will also like to use a broadcast

    public static final String BROADCAST_BUFFER = "source.justanothermusicplayer.broadcastbuffer";
    
    bufferIntent = new Intent(BROADCAST_BUFFER);;//You can put any value into Broadcast_Buffer ,it is just a unique identifier for each broadcast
    and then now that you hav initialized the intent its time to put values into it and send them using a broadcast
    

    ///

    bufferIntent.putExtra("buffering", "2");
            sendBroadcast(bufferIntent);
    

    put the above two lines inside a method which is called whenever a change happens,say when a button is clicked or timerischanged for e.g

    Ontimerchanged(){
    
    bufferIntent.putExtra("buffering", thevalueoftimer);//buffering is the key again...
            sendBroadcast(bufferIntent);
    }
    

    now go inside the activity again register the broadcast inside the activity

    registerReceiver(broadcastReceiver, new IntentFilter(
                        Music_service.BROADCAST_BUFFER));//remeber the "BROADCAST_BUFFER" we created in the service??this is the same ...if you use BROADCAST_BUFFER2 or something like that or any other thing,it won't work.
    

    now create this method

    private BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {
            @Override
            public void onReceive(Context context, Intent serviceIntent) {
                Anymethod(serviceIntent);//serviceIntent has the values that are being passed...in your case value of timer etc.recieve the values in the method
                //TODO 
            }
        };
    
    //
     AnyMethod(){
                //receiving the values here......
    
    
    
    String valueoftimer = serviceIntent.getStringExtra("buffering");//again the key needs to be same
    
    //now that you have received the values ,you can set them up in a textview....
    
    }
    

    if my answer was helpful upvote and accept it please