A seemingly simple requirement - to update UI from an IntentService. In the shot below, when the Start Service button is clicked, I need to show a ProgressBar above the only TextView and after a delay, remove the ProgressBar.
Found a lot of answers on SO, but somehow unable to still crack it. I understand from this that LocalBroadcastManager is a good way to go. I have also tried following this, (an approach with Handlers), but it fails to show the ProgressBar too. Finally, based on this answer, here's what I have ended up with. The output I've managed so far is just the Toasts appearing in succession, after all the logging is done.
Greatly appreciate if you could point out where I am going wrong, been struggling for quite some time now. Many thanks in advance!
MainActivity updated
public class MainActivity extends AppCompatActivity
{
private static final String TAG = "MainActivity";
private ProgressBar pb;
private MyBroadcastReceiver myBroadcastReceiver;
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
pb = (ProgressBar) findViewById(R.id.pb);
myBroadcastReceiver = new MyBroadcastReceiver();
LocalBroadcastManager.getInstance(this).registerReceiver(myBroadcastReceiver, new IntentFilter("ACTION"));
}
private void updateUI(boolean show)
{
if (show)
pb.setVisibility(View.VISIBLE);
else
pb.setVisibility(View.GONE);
// Toast.makeText(this, "UI Updated...", Toast.LENGTH_LONG).show();
}
public void startIt(View view)
{
Intent intent = new Intent(this, NanisIntentService.class);
startService(intent);
}
public class MyBroadcastReceiver extends BroadcastReceiver
{
#Override
public void onReceive(final Context context, Intent intent)
{
String action = intent.getAction();
Log.e(TAG, "In onReceive(): " + action);
if (action.equals("ACTION"))
{
updateUI(true);
} // of if (action = "ACTION")
else if (action.equals("NOITCA"))
{
updateUI(false);
} // of else of if (action = "ACTION")
} // of onReceive()
} // of class MyBroadcastReceiver
}
IntentService updated
public class NanisIntentService extends IntentService
{
private static final String TAG = "NanisIntentService";
public NanisIntentService()
{
super("NanisIntentService");
}
#Override
protected void onHandleIntent(Intent intent)
{
Log.e(TAG, "In onHandleIntent(): Intent is being serviced");
LocalBroadcastManager.getInstance(testing.com.myintentservice.NanisIntentService.this).sendBroadcast(new Intent().setAction("ACTION"));
int i = 0;
while (i <= 50)
{
try
{
Thread.sleep(50);
i++;
Log.e("", "" + i);
} catch (InterruptedException e)
{
e.printStackTrace();
}
}
}
#Override
public void onDestroy()
{
super.onDestroy();
LocalBroadcastManager.getInstance(testing.com.myintentservice.NanisIntentService.this).sendBroadcast(new Intent().setAction("NOITCA"));
Log.e(TAG, "In onDestroy(): The service has been destroyed");
}
}
#Override
public void onStart(Intent intent, int startId)
{
super.onStart(intent, startId);
LocalBroadcastManager.getInstance(testing.com.myintentservice.NanisIntentService.this).sendBroadcast(new Intent().setAction("ACTION"));
}
#Override
public void onDestroy()
{
super.onDestroy();
LocalBroadcastManager.getInstance(testing.com.myintentservice.NanisIntentService.this).sendBroadcast(new Intent().setAction("NOITCA"));
Log.e(TAG, "In onDestroy(): The service has been destroyed");
}
}
#Override
public void onDestroy()
{
super.onDestroy();
LocalBroadcastManager.getInstance(testing.com.myintentservice.NanisIntentService.this).sendBroadcast(new Intent().setAction("NOITCA"));
Log.e(TAG, "In onDestroy(): The service has been destroyed");
}
}
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="#dimen/activity_vertical_margin"
android:paddingLeft="#dimen/activity_horizontal_margin"
android:paddingRight="#dimen/activity_horizontal_margin"
android:paddingTop="#dimen/activity_vertical_margin"
tools:context="testing.com.myintentservice.MainActivity">
<ProgressBar
android:id="#+id/pb"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_above="#+id/tv"
android:layout_centerHorizontal="true"
android:indeterminate="true"
android:visibility="gone"/>
<TextView
android:id="#+id/tv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:text="Hello IntentService!"
android:textColor="#1298CE"
android:textSize="32sp"/>
<Button
android:id="#+id/bt"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:text="Start Service"
android:onClick="startIt"/>
</RelativeLayout>
AndroidManifest
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:supportsRtl="true"
android:theme="#style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<service android:name="testing.com.myintentservice.NanisIntentService"/>
</application>
First, you are tying up the main application thread for ~2.5 seconds. This will freeze your UI during this period of time. Do not do this.
Second, you are calling updateUI() once before the ~2.5 seconds, and once after. Since you are tying up the main application thread during that time, this will have the same visual effect as calling updateUI() twice in succession after the delay. updateUI() toggles the ProgressBar visibility, so two calls will cancel each other out, leaving you in the same state as you started.
I need to show a ProgressBar above the only TextView and after a delay, remove the ProgressBar.
Showing a ProgressBar for 2.5 seconds, irrespective of any actual work being done, is rather arbitrary.
That being said, call updateUI() once, then use pb.postDelayed() to schedule a Runnable to run 2500 milliseconds later, where the run() method in the Runnable calls updateUI() the second time. This avoids you blocking the main application thread, so it allows the first updateUI() call to take effect, while still giving you the 2.5-second duration.
Thanks so much, #CommonsWare! Finally got it to work. It needed two receivers for the two different actions, which I discovered here.
For the benefit of those looking for the final working code...
MainActivity
NanisIntentService
Result screens:- after clicking and after processing
Pardon any copy-paste ghosts in the code, it is after all a PoC, albeit functional.
Related
I have an application that detects if internet is available or not.
I have changed the behaviour of the back button to avoid closing the application when pressed. The issue I'm facing is that when I have 4G or WIFI running and I run the app, it detects that internet is available, however, when I press the back button, the app is put on the background and internet is no longer detected by it.
I noticed that if I remove the permissions in the manifest file, the application works fine, it detects internet both when it is running and when put on background, but I need those permissions for making http post requests later.
Any help on this please?
Thanks.
MainActivity.java
public class MainActivity extends AppCompatActivity {
Timer timer;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
init();
}
#Override
public void onBackPressed() {
this.moveTaskToBack(true);
}
private void init() {
timer = new Timer();
Tasker task = new Tasker(MainActivity.this, timer);
task.execute();
}
}
Tasker .java
public class Tasker extends AsyncTask<Void,Void,String> {
final Handler handler = new Handler();
static Timer timer;
Context context;
Toast toast;
private TimerTask doAsynchronousTask;
public Tasker(MainActivity context, Timer timer) {
this.timer = timer;
this.context = context;
}
#Override
protected void onPreExecute() {
}
#Override
protected String doInBackground(Void... voids) {
doTimerTask();
return null;
}
#Override
protected void onPostExecute(String response) {
}
private void showToast(String message){
toast = Toast.makeText(context, message, Toast.LENGTH_LONG);
toast.setGravity(Gravity.CENTER, 0, 0);
if(!((Activity) context).isFinishing()){
toast.show();
}
}
private void doTimerTask() {
doAsynchronousTask = new TimerTask() {
#Override
public void run() {
handler.post(new Runnable() {
#SuppressWarnings("unchecked")
public void run() {
if(haveNetworkConnection()){
showToast("Online");
}else{
showToast("Offline");
}
}
});
}
};
timer.schedule(doAsynchronousTask, 0, 10000);
}
private boolean haveNetworkConnection() {
ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo activeNetwork = cm.getActiveNetworkInfo();
boolean isConnected = activeNetwork != null && activeNetwork.isConnectedOrConnecting();
return isConnected;
}
}
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.e.myapplication">
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:roundIcon="#mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="#style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
</manifest>
Actually, it may not be your desirable answer, but I think there is a way simpler way to do what you really want to do using a Broadcast receiver. you don't need to check network state using the timer. here's the link
I would suggest you to use a WorkManager or AlarmManager, or even Services for background related periodic tasks.
Using the Timer-AsyncTask combination is not a feasible approach and it could lead to many problems, one of which being it could easily be terminated by Android once it's in background.
My top pick would be WorkManager as it handles the condition for the tasks for you nicely, for example, if you want to only launch your task if there's internet connection, then you simply add a Work Constraint to your work request like this
Constraint networkConstraint = new Constraints.Builder()
.setRequiredNetworkType(NetworkType.CONNECTED)
.build();
workRequest.setConstraints(constraints)
And your task will only be executed if the network is connected. BTW, they don't need to be manually re-set after reboot like AlarmManagers does.
However, there are downsides to it, one of them being the perodic requests can only occur every 15 minutes, which you can circumvent (though not recommended) by setting more one time work requests in each perodic request with smaller intervals of delayed start time.
Anyways, stop using the AsyncTask approach you are using now, and use one of the "legitimate" approaches Android approves to do background tasks, I recommend WorkManager, but based on your situation, you can choose whatever approach you like as long as it's meant to work in background.
I'm trying to run some simple calculation in an App and I want it to always run, even if the App is not visible/active. I've looked up some possibilities and ended up using the ASyncTask. However, when I try to execute it, it's actually not running in the background. It's not running at all to be precise.
So my question is: is the AsyncTask really the best way to do this calculation or should I rather use a Service or something else? And if the ASyncTask is the right way to do it, what am I doing wrong?
Here is the relevant code:
public class MainActivity extends AppCompatActivity implements SensorEventListener{
long startTime = System.nanoTime();
public class resetSpm extends AsyncTask<Void, Void, Void> {
#Override
protected Void doInBackground(Void... voids) {
if((System.nanoTime() - startTime) > 2000000000) {
//some simple calculation
}
return null;
}
}
#Override
public void onStart() {
super.onStart();
new resetSpm().execute();
}
}
I've also tried to put the execute in the OnCreate with no result.
The if((System.nanoTime() - startTime) > 2000000000) {...} is there instead of a timer because I set the startTime to some other time as well.
This part's task should be to reset a value every 2 seconds without anything happening.
Thanks in advance.
EDIT: So I've set up a Service but without any result.
This is the code to that:
public class SpmResetService extends Service {
#Override
public void onCreate() {
Log.v("spmService", System.currentTimeMillis() + "spmService has been created.");
}
#Override
public int onStartCommand(Intent intent, int flags, int startedId) {
Log.v("spmService", System.currentTimeMillis() + "spmService has been started.");
if((System.nanoTime() - startTime) > 2000000000) {
//my calculation
}
stopSelf();
return Service.START_STICKY;
}
#Override
public IBinder onBind(Intent intent) {
Log.v("spmService", System.currentTimeMillis() + "spmService has been bound.");
return null;
}
#Override
public void onDestroy() {
Log.v("spmService", System.currentTimeMillis() + "spmService has been destroyed.");
}
}
I've then started it in the onCreate like this:
Intent spmReset = new Intent(this, SpmResetService.class);
startService(spmReset);
I have also edited the manifest with
<service
android:name="SpmResetService"
>
</service>
But here it tells me that this Service's name cannot be resolved.
Firstly you should look into Services which are specifically made for this purpose.
You cannot handle UI from the doInBackground, this is possible from the onPostExecute method.
Also can you put a debug message in the doInBackground method so as to see if the task is getting executed or not. Ideally you should use the debugger for this but just for now Log statements should do.
protected Void doInBackground(Void... voids) {
Log.d("MyApp", "In doInBackground");
if((System.nanoTime() - startTime) > 2000000000) {
//some simple calculation
Log.d("MyApp", "Executing if block");
}
return null;
}
Also make sure the condition you are checking is true, which in this case is seems to be false.
I am working on an Android app that is behaving oddly. One of the first things this app does upon start up, is to start a listening thread that listens to a "server" app, on the same device, to get data. Once this data is received by the listening thread, I use it to update the main view. This, however only works if my app is started after the server app.
First a few details. My app and the server app are on the same device. They communicate with each other via UDP (the server app is a port of a Windows application). My app uses fragments, but the view I want to update is not within a fragment. Now some code.
content_main.xml
<RelativeLayout>
<LinearLayout>
<ImageView
android:id="#+id/my_image_id"
android:src="#drawable/my_image" />
</LinearLayout>
<LinearLayout>
<!-- fragment code here -->
</LinearLayout>
</RelativeLayout>
MainActivity.java
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState){
Listener myListener = new Listener(this);
Thread listenerThread = new Thread(myListener);
listenerThread.setName("My Listener Thread");
listenerThread.start();
}
}
Listener.java
public class Listener implements Runnable {
public Listener (Activity mainActivity) {this.mainActivity = mainActivity;}
private Activity mainActivity;
private ImageView myImageView;
private NewData newData;
#Override
public void run(){
while(true){
// Here is where my app gets the data from the server via UDP.
// This always works, I am always getting the correct data.
myImageView = (ImageView) mainActivity.findViewById(R.id.my_image_id);
mainActivity.runOnUiThread(new Runnable(){
#Override
public void run(){
if(newData == 1){
myImageView.setImageResource(R.drawable.new_image_01);
} else if(newData == 2){
myImageView.setImageResource(R.drawable.new_image_02);
} else {
myImageView.setImageResource(R.drawable.error_image);
}
}
});
}
}
}
Like I said, if I start my app after the server app, then this all works perfectly. The images always changes when the new data changes. However, if I start my app before the server app, or if I restart the server app while my app is still running, then the images never changes, even though I am still getting the correct data from the server app.
What can I do to make sure the view can update at any time?
EDIT: I moved where I get the view to outside of the while loop (as a test) and now the code doesn't work at all.
I gave it a try. apparently your code is working alright, if the thread starts after the activity is been initialized, i don't really know how your server app works so i tried to mimic something like this.
public class TestThreadActivity extends AppCompatActivity {
private Button restart_Button;
private ImageView imageView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_test_thread);
Toolbar toolbar = (Toolbar) findViewById(R.id.my_custom_toolbar);
setSupportActionBar(toolbar);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
initializeUI();
}
private void initializeUI() {
restart_Button = (Button) findViewById(R.id.TestThreadActivity_restart_button);
imageView = (ImageView) findViewById(R.id.TestThreadActivity_imageView);
final Listener myListener = new Listener(this);
restart_Button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
imageView.setImageResource(R.drawable.piccolo);
final Thread listenerThread = new Thread(myListener);
listenerThread.setName("My Listener Thread");
listenerThread.start();
}
});
}
public class Listener implements Runnable {
public Listener (Activity mainActivity) {this.mainActivity = mainActivity;}
private Activity mainActivity;
private ImageView myImageView;
int newData = 0;
#Override
public void run(){
while(true){
// Here is where my app gets the data from the server via UDP.
// This always works, I am always getting the correct data.
newData = (new Random()).nextInt(3);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
myImageView = (ImageView) mainActivity.findViewById(R.id.TestThreadActivity_imageView);
mainActivity.runOnUiThread(new Runnable(){
#Override
public void run(){
System.out.println("newData: "+newData);
if(newData == 1){
myImageView.setImageResource(R.drawable.gohan);
} else if(newData == 2){
myImageView.setImageResource(R.drawable.goku);
} else {
myImageView.setImageResource(R.drawable.piccolo);
}
}
});
}
}
}
}
activity_test_thread.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context="activities.list.first.TestThreadActivity">
<include layout="#layout/my_custom_toolbar" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="4dp"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<Button
android:id="#+id/TestThreadActivity_restart_button"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_margin="4dp"
android:layout_weight="0.5"
android:text="Start"
android:contentDescription="this will restart the thread"
android:textAllCaps="false" />
</LinearLayout>
<ImageView
android:id="#+id/TestThreadActivity_imageView"
android:layout_width="match_parent"
android:layout_height="200dp"
android:src="#drawable/gohan" />
</LinearLayout>
</LinearLayout>
Output
I have found as a common issue in any of my apps that the user may accidentally perform several clicks on the same button causing multiple executions of the onClick listener logic. Typically, my business logic for those onClickListeners usually consists of launching of a heavy-process AsynTask that performs an HTTP request and later modifies the UI.
My way to prevent multiple executions of the asyntask was to unable the button at the beginning of the listener method and enable it again as a first statement of the onPostExecute. That has generally worked for me or at least I have not received any issue regarding to this situation.
Recently, a colleague has pointed me a potential problem of this unable-enable-button method. As shown in the below code that consists of two buttons '+' and '-', quick and alternative presses on those buttons causes a crash the application by an ArrayOutOfIndex exception.
That fact has made me think about my way of managing the concurrency of the onClickListener events and if it is really possible to have the situation in which a second asyntask may be launches prior to the finalization of the first asyntask using the aforementioned method.
What are your suggestions to handle this situation?
For those suggestions that recommend to apply some logic rejecting the second launches of the asyntask until the completion of the first asyntask, is it is really worth to generally apply that logic for a common used application in which the buttons perform an http request?.
CrashActivity.java
public class CrashActivity extends Activity {
private int mNumbers[] = { 1, 2, 3, 4, 5 };
private int position = 0;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
final TextView result = (TextView) findViewById(R.id.resultTextView);
final Button minusBtn = (Button) findViewById(R.id.minus_button);
final Button plusBtn = (Button) findViewById(R.id.plus_button);
minusBtn.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
minusBtn.setEnabled(false);
plusBtn.setEnabled(true);
result.setText("" + mNumbers[--position]);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
minusBtn.setEnabled((position > 0));
}
});
plusBtn.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
plusBtn.setEnabled(false);
minusBtn.setEnabled(true);
result.setText("" + mNumbers[position++]);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
plusBtn.setEnabled((position <= 4));
}
});
minusBtn.setEnabled(false);
}
}
main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<Button
android:id="#+id/minus_button"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="-" />
<Button
android:id="#+id/plus_button"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="+" />
<TextView
android:id="#+id/resultTextView"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="hello stackoverflow!" />
</LinearLayout>
A solution that would guarantee that both methods do not try to update the UI at the same time would be to synchronize the UI update code. You could either create a synchronized method or an Object that acts as a lock for a block of code. Example:
public synchronized void updateUI() {
// ...
}
or
private Object mLock = new Object();
public void updateUI() {
// ...
synchronized (mLock) {
// Critical code here.
}
// ...
}
Expanding this to make sure that task 1 completes before task 2, completes before task 3, etc., you would need to somehow keep track of which started first. Note: synchronization occurs on the UI thread in this example.
private List<AsyncTask> mRunningTasks = new ArrayList<AsyncTask>();
public void onClick(View v) {
v.setEnabled(false);
if (v == task1View) {
Task1 task = new Task1();
mRunningTasks.add(task);
task.execute();
}
else if (v == task2View) {
Task2 task = new Task2();
mRunningTasks.add(task);
task.execute();
}
// ...
}
// Copy and paste for each necessary task.
private Task1 extends AsyncTask<Void, Void, Void> {
protected Void doInBackground(Void... v) {
// Run task 1 code here.
while (this != mRunningTasks.get(0)) {
wait(1000);
}
return v[0];
}
protected void onPostExecute(Void v) {
updateUI();
mRunningTasks.remove(0);
task1View.setEnabled(true);
}
}
public void updateUI() {
// UI update code here.
}
I'm trying to have my Activity update an ImageView whenever a boolean value changes in another class.
Therefore i have some sort of timer that starts on my first onCreate()
private void startTimer() {
mHandler.removeCallbacks(mUpdateTimeTask);
mHandler.postDelayed(mUpdateTimeTask, 2000); // first run after 2 secs
}
private Runnable mUpdateTimeTask = new Runnable() {
public void run() {
connectionControl.checkNetworkState();
System.out.println("online?: " + connectionControl.isOnline());
mHandler.postDelayed(this, 15000); // repeat every x/1000 secs
}
};
My class ConnectionControl has a boolean, that gets set to either true or false whether my app can reach a specific http-host.
Now my question is: how can i achieve a automatic change on the ImageView in my Activity to display the boolean's value?
I already looked at Observer-Pattern, EventListener, BroadcastReciever but I'm stuck at finding the right solution.
Also, i want to use the listening in other Activities.
What has worked so far was starting/stopping the timer-thing for each activity and have the ImageView update inside the run() method. But my guess is, there has to be a way around the redundancy.
I think you are in search of AsyncTask , by using it you can made a call to webservice asynchronously and after the successful call to the webservice, we can process the fetched data.
Just go through this article: http://developer.android.com/resources/articles/painless-threading.html.
I think you needs this: (from android.com)
public void onClick(View v) {
new DownloadImageTask().execute("http://example.com/image.png");
}
private class DownloadImageTask extends AsyncTask<String, Void, Bitmap> {
protected Bitmap doInBackground(String... urls) {
return loadImageFromNetwork(urls[0]);
}
protected void onPostExecute(Bitmap result) {
mImageView.setImageBitmap(result);
}
}
For more info about AsyncTask , here is link: http://developer.android.com/reference/android/os/AsyncTask.html
Here is how I did it.
I made a layout file for the custom titlebar thing, that has an ImageView.
<merge xmlns:android="http://schemas.android.com/apk/res/android">
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent" android:layout_height="wrap_content">
<ImageView android:id="#+id/title_statusimg"
android:layout_width="wrap_content" android:layout_height="wrap_content"
android:src="#drawable/connected" android:layout_centerVertical="true"
android:layout_alignParentRight="true" />
</RelativeLayout>
</merge>
I include this in every activities layout file i want to use it.
<include layout="#layout/titlebar" />
Also, i made a StatusActivity that extends Activity. It receives a Broadcast that is send from whenever an background thread detects a change in the connectivity to the webserver.
public class StatusActivity extends Activity {
private String CONNECTION_STATUS = "app.CONNECTION_STATUS";
private ImageView conn;
#Override
protected void onResume() {
super.onResume();
IntentFilter iFilter = new IntentFilter(CONNECTION_STATUS);
registerReceiver(mBroadcastReceiver, iFilter);
conn = (ImageView) findViewById(R.id.title_statusimg);
if (ConnectionControl.isOnline()) {
conn.setImageResource(R.drawable.connected);
} else {
conn.setImageResource(R.drawable.nconnected);
}
}
#Override
protected void onPause() {
super.onPause();
unregisterReceiver(mBroadcastReceiver);
}
private BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
if (ConnectionControl.isOnline()) {
conn.setImageResource(R.drawable.connected);
} else {
conn.setImageResource(R.drawable.nconnected);
}
}
};
}
Every Activity that shall use this Status-Image extends StatusActivity instead of Activity.
Hope i covered everything, atleast for me it's working.