In many cases, you have to update Service data to UI so as that user can recognize Service status (i.e: download file process), so we must put data through Intent and use BroadcastReceiver to "listen" Service status and display it to UI. With this project, I hope that you can understand this data tranfer process and as well as have more experiences in Android application programming!
1. Project Description
- There are 3 Fragments (pages) in ViewPager: DownLoadFragment, DateTimeFragment and a BlankFragment to "test".
- Includes 2 Services run in background: Download file Service (show it's status to DownloadFragment) and getting DateTime Service (show curent date/time to UI in DateTimeFragment).
2. Main Activity
Set ViewPager adapter in programmatically code (PagerActivity.java):
package info.devexchanges.services.ui;
import android.os.Bundle;
import android.support.v4.app.FragmentActivity;
import android.support.v4.view.ViewPager;
import info.devexchanges.services.R;
import info.devexchanges.services.adapter.ViewPagerAdapter;
public class PagerActivity extends FragmentActivity {
private ViewPager pager;
private ViewPagerAdapter adapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_pager);
pager = (ViewPager) findViewById(R.id.view_pager);
//init view pager adapter
adapter = new ViewPagerAdapter(getSupportFragmentManager());
pager.setAdapter(adapter);
}
}
3. Download Fragment and download file Service
For "listen" a Service status, provide a BroadcastReceiver object in Fragment and initialize it in onCreate() method. Therefore, create a new Intent with current Service:
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
broadcastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
updateProgressBar(intent);
}
};
intent = new Intent(getActivity(), DownloadService.class);
}
Register/unregister broadcast receiver in onStart()/onStop() of DownloadFragment LocalBroadcastManager instance:@Override
public void onStart() {
super.onStart();
if (isServiceRunning(DownloadService.class)) {
btnDownload.setVisibility(View.GONE);
}
LocalBroadcastManager.getInstance(getActivity()).registerReceiver((broadcastReceiver),
new IntentFilter(DownloadService.DOWNLOAD_ACTION)
);
}
@Override
public void onStop() {
super.onStop();
LocalBroadcastManager.getInstance(getActivity()).unregisterReceiver(broadcastReceiver);
}
Ofcourse, in this Fragment, we'll start download file after click Download Button:/**
* Handling button Download event
* @return
*/
private View.OnClickListener onStartDownloadListener() {
return new View.OnClickListener() {
@Override
public void onClick(View v) {
getActivity().startService(intent);
btnDownload.setVisibility(View.GONE);
//init BroadcastManager instance when service start
LocalBroadcastManager.getInstance(getActivity()).registerReceiver((broadcastReceiver),
new IntentFilter(DownloadService.DOWNLOAD_ACTION)
);
}
};
}
Another important method is updateProgressBar() to update percentage of download file process to ProgressBar and TextView: /**
* Update the percentage of download process to TextView and Progress Bar
* @param intent
*/
private void updateProgressBar(Intent intent) {
String progress = intent.getStringExtra(DownloadService.PERCENTAGE_STAMP);
if (progress != null ) {
progressBar.setProgress(Integer.parseInt(progress));
percentage.setText(progress + "%");
//stop download service when task completed
if (progress.equals("100")) {
getActivity().stopService(intent);
}
}
}
Adding some neccessary methods, we have full DownloadFragment.java code:package info.devexchanges.services.ui;
import android.app.ActivityManager;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.content.LocalBroadcastManager;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ProgressBar;
import android.widget.TextView;
import info.devexchanges.services.DownloadService;
import info.devexchanges.services.R;
public class DownLoadFragment extends Fragment {
private ProgressBar progressBar;
private TextView percentage;
private View btnDownload;
private Intent intent;
private BroadcastReceiver broadcastReceiver;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
broadcastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
updateProgressBar(intent);
}
};
intent = new Intent(getActivity(), DownloadService.class);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_down_load, container, false);
}
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
percentage = (TextView) view.findViewById(R.id.percent);
progressBar = (ProgressBar) view.findViewById(R.id.progress_bar);
btnDownload = (View) view.findViewById(R.id.btn_start);
btnDownload.setOnClickListener(onStartDownloadListener());
}
@Override
public void onStart() {
super.onStart();
if (isServiceRunning(DownloadService.class)) {
btnDownload.setVisibility(View.GONE);
}
LocalBroadcastManager.getInstance(getActivity()).registerReceiver((broadcastReceiver),
new IntentFilter(DownloadService.DOWNLOAD_ACTION)
);
}
@Override
public void onStop() {
super.onStop();
LocalBroadcastManager.getInstance(getActivity()).unregisterReceiver(broadcastReceiver);
}
/**
* Update the percentage of download process to TextView and Progress Bar
* @param intent
*/
private void updateProgressBar(Intent intent) {
String progress = intent.getStringExtra(DownloadService.PERCENTAGE_STAMP);
if (progress != null ) {
progressBar.setProgress(Integer.parseInt(progress));
percentage.setText(progress + "%");
//stop download service when task completed
if (progress.equals("100")) {
getActivity().stopService(intent);
}
}
}
/**
* Handling button Download event
* @return
*/
private View.OnClickListener onStartDownloadListener() {
return new View.OnClickListener() {
@Override
public void onClick(View v) {
getActivity().startService(intent);
btnDownload.setVisibility(View.GONE);
//init BroadcastManager instance when service start
LocalBroadcastManager.getInstance(getActivity()).registerReceiver((broadcastReceiver),
new IntentFilter(DownloadService.DOWNLOAD_ACTION)
);
}
};
}
/**
* Check if Service is running
* @param serviceClass
* @return true if one or more service is running in background thread
*/
private boolean isServiceRunning(Class serviceClass) {
ActivityManager manager = (ActivityManager) getActivity().getSystemService(Context.ACTIVITY_SERVICE);
for (ActivityManager.RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) {
if (serviceClass.getName().equals(service.service.getClassName())) {
return true;
}
}
return false;
}
}
In DownloadService.java, we provide an AsyncTask to download file trom URL, when it's running, in doInBackground(), calculating downloaded percentages, and write data to file at Internal Storage. In onProgressUpdate(), sending this data to BroadcastReceiver:/**
* Updating progress bar
*/
protected void onProgressUpdate(String... progress) {
// setting progress percentage
//put info through intent
intent = new Intent(DOWNLOAD_ACTION);
intent.putExtra(PERCENTAGE_STAMP, progress[0]);
//sending intent through BroadcastManager
broadcastManager.sendBroadcast(intent);
}
And this is full code of AsyncTask:Creating BroadcastReceiver instance in onCreate() method of Service and start AsyncTask in onStartCommand():
@Override
public void onCreate() {
super.onCreate();
//init Intent
broadcastManager = LocalBroadcastManager.getInstance(this);
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
new DownloadFileFromURLTask().execute(DOWNLOAD_LINK);
return START_STICKY;
}
Full code of DownloadService.java:This screen when app running:
4. DateTime Fragment and get current date/time Service
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
broadcastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
updateDataToUI(intent);
}
};
intent = new Intent(getActivity(), DateTimeService.class);
}
@Override
public void onStart() {
super.onStart();
getActivity().startService(intent);
LocalBroadcastManager.getInstance(getActivity()).registerReceiver((broadcastReceiver),
new IntentFilter(DateTimeService.DATE_TIME_ACTION)
);
}
@Override
public void onStop() {
super.onStop();
getActivity().stopService(intent);
LocalBroadcastManager.getInstance(getActivity()).unregisterReceiver(broadcastReceiver);
}
in updateDataToUI() method, we'll update Service data (current Date and Time) to TextViews. Full code of DateTimeFragment.java:package info.devexchanges.services.ui;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.content.LocalBroadcastManager;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import info.devexchanges.services.DateTimeService;
import info.devexchanges.services.R;
public class DateTimeFragment extends Fragment {
private TextView date;
private TextView time;
private Intent intent;
private BroadcastReceiver broadcastReceiver;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
broadcastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
updateDataToUI(intent);
}
};
intent = new Intent(getActivity(), DateTimeService.class);
}
@Override
public void onStart() {
super.onStart();
getActivity().startService(intent);
LocalBroadcastManager.getInstance(getActivity()).registerReceiver((broadcastReceiver),
new IntentFilter(DateTimeService.DATE_TIME_ACTION)
);
}
@Override
public void onStop() {
super.onStop();
getActivity().stopService(intent);
LocalBroadcastManager.getInstance(getActivity()).unregisterReceiver(broadcastReceiver);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_date_time, container, false);
}
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
date = (TextView) view.findViewById(R.id.date);
time = (TextView) view.findViewById(R.id.time);
}
/**
* Update date and time to textviews
*/
private void updateDataToUI(Intent intent) {
date.setText(intent.getStringExtra(DateTimeService.DATE_STAMP));
time.setText(intent.getStringExtra(DateTimeService.TIME_STAMP));
}
}
In DateTimeService,java, getting current system date/time and doing this work after every 1 second execute a Runnable method with a Handler. Put data through Intent and LocalBroadcastManager instance : private Runnable sendUpdatesToUI = new Runnable() {
public void run() {
getDateTimes();
handler.postDelayed(this, 1000); // 1 seconds
}
};
public void getDateTimes() {
calendar = Calendar.getInstance();
int seconds = calendar.get(Calendar.SECOND);
int minutes = calendar.get(Calendar.MINUTE);
int hours = calendar.get(Calendar.HOUR);
dateFormat = new SimpleDateFormat("dd-MM-yyyy");
String formattedDate = "Current Date: " + dateFormat.format(calendar.getTime());
String time = "Current Time: " + hours + ":" + minutes + ":" + seconds;
//put info through intent
intent = new Intent(DATE_TIME_ACTION);
intent.putExtra(TIME_STAMP, time);
intent.putExtra(DATE_STAMP, formattedDate);
broadcastManager.sendBroadcast(intent);
}
Like above Service, initial BroadcastReceiver and start it through onCreate/onStartCommand. Full code:package info.devexchanges.services;
import android.app.Service;
import android.content.Intent;
import android.os.Handler;
import android.os.IBinder;
import android.support.v4.content.LocalBroadcastManager;
import java.text.SimpleDateFormat;
import java.util.Calendar;
/**
* Created by Hong Thai
*/
public class DateTimeService extends Service {
private Calendar calendar;
private SimpleDateFormat dateFormat;
private Intent intent;
private final Handler handler = new Handler();
private LocalBroadcastManager broadcastManager;
public final static String TIME_STAMP = "Time";
public final static String DATE_STAMP = "Date";
public final static String DATE_TIME_ACTION = "info.devexchanges.dateservice";
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onCreate() {
super.onCreate();
broadcastManager = LocalBroadcastManager.getInstance(this);
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
handler.removeCallbacks(sendUpdatesToUI);
handler.postDelayed(sendUpdatesToUI, 1000); // 1 second
return START_STICKY;
}
@Override
public void onDestroy() {
super.onDestroy();
handler.removeCallbacks(sendUpdatesToUI);
}
private Runnable sendUpdatesToUI = new Runnable() {
public void run() {
getDateTimes();
handler.postDelayed(this, 1000); // 1 seconds
}
};
public void getDateTimes() {
calendar = Calendar.getInstance();
int seconds = calendar.get(Calendar.SECOND);
int minutes = calendar.get(Calendar.MINUTE);
int hours = calendar.get(Calendar.HOUR);
dateFormat = new SimpleDateFormat("dd-MM-yyyy");
String formattedDate = "Current Date: " + dateFormat.format(calendar.getTime());
String time = "Current Time: " + hours + ":" + minutes + ":" + seconds;
//put info through intent
intent = new Intent(DATE_TIME_ACTION);
intent.putExtra(TIME_STAMP, time);
intent.putExtra(DATE_STAMP, formattedDate);
broadcastManager.sendBroadcast(intent);
}
}
Our result when running:5. Some necessary files
A customize adapter based on FragmentPagerAdapter for ViewPager (ViewPagerAdapter.java):
package info.devexchanges.services.adapter;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentPagerAdapter;
import info.devexchanges.services.ui.BlankFragment;
import info.devexchanges.services.ui.DateTimeFragment;
import info.devexchanges.services.ui.DownLoadFragment;
/**
* Created by Hong Thai.
*/
public class ViewPagerAdapter extends FragmentPagerAdapter{
public ViewPagerAdapter(FragmentManager fm) {
super(fm);
}
@Override
public Fragment getItem(int i) {
if (i == 1) {
return new DateTimeFragment();
} else if (i == 0){
return new DownLoadFragment();
} else {
return new BlankFragment();
}
}
public CharSequence getPageTitle(int position) {
if (position == 0) {
return "Download";
} else if (position == 1) {
return "Date Time";
} else {
return "Blank Fragment";
}
}
@Override
public int getCount() {
return 3;
}
}
Providing WRITE_EXTERNAL_STORAGE and INTERNET permissions, register our services in AndroidManifest:



