Update Activity's UI when it is not visible [Another activity is in foreground] - android-activity

Is it ok to update an Activity when it is not in the foreground. I am not asking if it can be done from a background thread.
Consider this:
I have two activities Activity-A and Activity-B.
I start an AsyncTask from Activity-A and then go to Activity-B. Now after sometime, the AsyncTask finishes and in the onPostExecute() method, I try to update the images that are in Activity-A. All this is happening when Activity-B is in the foreground.
Is the above scenario reasonable or do I have to wait till Activity-A is in the foreground to update its UI?
If I can safely update the UI in the above scenario, what should I do when Activity-A is killed or finished and the AsyncTask still completes and tries to update the UI? [Assuming I have to do a check for isFinishing before updating the UI]
The above is a simplified version of what I am trying to do. I actually have a Custom ImageView that loads images from the server and updates itself when the request is done. So I am wondering what scenarios I have to worry about if the view is updating itself when the activity is not in foreground or has finished/destroyed.
EDIT:
Here is a sample that is working.
public class MainActivity extends Activity implements OnClickListener {
ImageView mImageView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mImageView = (ImageView) findViewById(R.id.iv_image);
findViewById(R.id.btn_activity_2).setOnClickListener(this);
}
#Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.btn_activity_2:
new BackGroundTask().execute();
startActivity(new Intent(MainActivity.this, Activity2.class));
break;
}
}
private class BackGroundTask extends AsyncTask<Void, Void, Void> {
#Override
protected Void doInBackground(Void... params) {
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return null;
}
#Override
protected void onPostExecute(Void result) {
super.onPostExecute(result);
mImageView.setImageResource(R.drawable.ic_launcher);
}
}
}
The Layout is just a LinearLayout with button and image.

No, it's not. You can't update a UI that's not visible :) Activity A is onPause (or Stopped if needed).
You have to implement a reasonable Activity LIfeCycle so ActivityA can update its UI during onResume(); The AsyncTask should only touch the data that the UI needs to draw itself.
Your "Custom IMage View" has to be able to load the image from a place outside the Activity.
If your CustomImageView is (or can pass as a regular ImageView), you can use something like Picasso to offload the Bitmap handling the correct way.

Related

How to avoid OnCreate method execution when activity has been opened previously (Xamarin.Android)?

I have two activities FirstActivity and SecondActivity. When I am in FirstActivty I call the SecondActivity like that:
var secondActivity = new Intent(this, typeof(SecondActivity));
secondActivity.PutExtra("someExtra", someExtra);
StartActivity(secondActivity);
Finish();
In SecondActivity I call the FirstActivity in OnBackPressed method:
public override void OnBackPressed()
{
StartActivity(typeof(FirstActivty));
Finish();
}
I looked at answers regarding that question for Android(Java). The answers were that in order to avoid OnCreate method to be executed in FirstActivity when the activity has been already created, I don't have to destroy FirstActivity after I open SecondActivity, I have to remove Finish() after StartActivity(secondActivity); line. I removed it but OnCreate method still gets executed when I go back from SecondActivity. Does this solution work only in Android(Java) ,and if yes, what is the solution for Xamarin.Android ?
You can add LaunchMode = Android.Content.PM.LaunchMode.SingleInstance in your FirstActivity attribute like this code.
[Activity(Label = "#string/app_name", Theme = "#style/AppTheme", MainLauncher = true,LaunchMode = Android.Content.PM.LaunchMode.SingleInstance)]
public class MainActivity : AppCompatActivity
{
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
Xamarin.Essentials.Platform.Init(this, savedInstanceState);
// Set our view from the "main" layout resource
SetContentView(Resource.Layout.activity_main);
}
Here is running GIF.
If you do not want to execute the code in the Oncreate method, You can refer to this thread.
https://stackoverflow.com/a/6931246/10627299

How to cancel the creation of a view in Eclipse RCP e4?

Is it possible to cancel the creation of a view in the #PostConstruct phase? I have:
#PostConstruct
public void createPartControl(Composite parent) {
try {
// do something where an exception is thrown
} catch (Exception e) {
// I want to cancel construction, close the view and show an error dialog
}
}
You can run the part service hide part immediately after the part creation has finished using something like:
#PostConstruct
public void postConstruct(Composite parent, UISynchronize uiSync,
EPartService partService, MPart part)
{
// Other code
// Run hidePart as soon as possible after part creation has finished
uiSync.asyncExec(() -> partService.hidePart(part));
}
(Above is using Java 8 lambda).
Just close the view, e4 style
MPart part = partService.findPart(viewId);
part.setVisible(true);

Get delay on UI thread

I'm setting color of a listview item using the following code parent.getChildAt(itemPosition).setBackgroundColor(Color.parseColor("#FF9494"));
This piece of code I'm writing in OnItemClickListener.
After setting the color I want to keep this color for a time of 4 Seconds and then restore the color of the item to its previous(say White).
I tried putting a sleep on the UI thread, but I know that it is not a correct approach.
Can anyone suggest me how to achieve this?
parent.getChildAt(itemPosition).setBackgroundColor(Color.parseColor("#FF9494"));
// Start new Thread that sets the color back in 4 seconds
new Thread(new Runnable() {
#Override
public void run() {
SystemClock.sleep(4000); // Sleep 4 seconds
// Now change the color back. Needs to be done on the UI thread
runOnUiThread(new Runnable() {
#Override
public void run() {
parent.getChildAt(itemPosition).setBackgroundColor(Color.parseColor("#000000")); // use whatever other color you want here
}
});
}
}).start();
The main thread has a looper running within. For this it is possible to schedule a Runnable delayed. Within an OnItemClickListener your code could be as simple as:
#Override
public void onItemClick(AdapterView<?> parent, final View view, int position, long id) {
view.setBackgroundColor(Color.parseColor("#FF9494"));
view.postDelayed(new Runnable() {
#Override
public void run() {
view.setBackgroundColor(Color.parseColor("#FFFFFF"));
}
}, 4000);
}
May be you can try to implement an asyncTask which can then be called from onItemClickListener. The doInBackground method of this asyncTask can contain a sleep method to avoid calling the onPostExecute for a while. In the onPostExecute, you can then reset the color as desired.
If sleep method can't be written in the doInBackground method as I am expecting, then put the sleep method also inside the onPostExecute method before changing the text color.

Update ListView Textview vom Asyntask

i need to update a textView from my asynctask. I have an custom adapter for the listview and there i want to have a countdown for each entry. I will start the asynctask for each entry from my Adapter. How can i update the textview each second from the asynctask?
Thanks for help :)
If you post your code, I can give you a better answer. However, a common way to update views periodically is by using Handlers.
private final Handler mHandler = new Handler(); //intialize in main thread
public void test() {
mHandler.postDelayed(new Runnable() {
#Override
public void run() {
mTextView.setText("hello");
}
}, 1000);
}
You can do something like this (this will add an entry to a list view every one second). I have used the normal ArrayAdapter to add a string. You can use your custom adapter to do something similar. The publishProgress() method basically triggers the onProgressUpdate() method which hooks to the UI thread and displays the elements getting added.:
class AddStringTask extends AsyncTask {
#Override
protected Void doInBackground(Void... params) {
for(String item : items) {
publishProgress(item);
SystemClock.sleep(1000);
}
return null;
}
#Override
protected void onProgressUpdate(String... item) {
adapter.add(item[0]);
}
#Override
protected void onPostExecute(Void unused) {
Toast.makeText(getActivity(), "Done adding string item", Toast.LENGTH_SHORT).show();
}
}

How can I correctly update a progress bar for an operation of unknown duration within an Eclipse wizard?

I have implemented a wizard for my Eclipse plug-in, showing several pages. One of these pages needs some lengthy initialization, that means it consists of a SWT table, which needs to be populated by information coming from an external source. This source needs to be activated first (one single method call that returns after a couple of seconds - I can not know in advance how long it will take exactly), before it can be used as input for for the table viewer. This initialization is currently done by the table model provider when it needs to access the external source for the first time.
Therefore, when I enter the wizard page, I would like to show a dummy progress bar that just counts up for a while. My approach was the following, but unfortunately does not work at all:
private void initViewer() {
IRunnableWithProgress runnable = new IRunnableWithProgress() { // needed to embed long running operation into the wizard page
#Override
public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException {
SubMonitor progress = SubMonitor.convert(monitor);
Thread thread = new Thread() {
#Override
public void run() {
Display.getDefault().syncExec(new Runnable() {
public void run() {
viewer.setInput(ResourcesPlugin.getWorkspace().getRoot()); // this will make the table provider initialize the external source.
}
});
}
};
thread.start();
while(thread.isAlive()) {
progress.setWorkRemaining(10000);
progress.worked(1);
}
progress.done();
}
};
try {
getContainer().run(false, false, runnable);
} catch(Exception e) {
throw new Exception("Could not access data store", e);
}
}
This method gets then invoked when the wizard page's setVisible()-method is called and should, after a couple of seconds, set the viewer's input. This, however, never happens, because the inner-most run()-method never gets executed.
Any hints on how to deal with long-running (where an exact estimate is not available) initializations in Eclipse wizards would be very appreciated!
I have given below a simple example on how to use IRunnableWithProgress along with a ProgressMonitorDialog to perform a task of unknown quantity. To start with, have an implementation to IRunnableWithProgress from where the actual task is performed. This implementation could be an inner class.
public class MyRunnableWithProgress implements IRunnableWithProgress {
private String _fileName;
public MyRunnableWithProgress(String fileName) {
_fileName = fileName;
}
#Override
public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException {
int totalUnitsOfWork = IProgressMonitor.UNKNOWN;
monitor.beginTask("Performing read. Please wait...", totalUnitsOfWork);
performRead(_fileName, monitor); // This only performs the tasks
monitor.done();
}
}
Now, a generic implementation to ProgressMonitorDialog can be created as below which could be used for other places where a progress monitor dialog is required.
public class MyProgressMonitorDialog extends ProgressMonitorDialog {
private boolean cancellable;
public MyProgressMonitorDialog(Shell parent, boolean cancellable) {
super(parent);
this.cancellable = cancellable;
}
#Override
public Composite createDialogArea(Composite parent) {
Composite container = (Composite) super.createDialogArea(parent);
setCancelable(cancellable);
return container;
}
}
Having got the required implementation, the task can be invoked as below to get it processed with a progress dialog.
boolean cancellable = false;
IRunnableWithProgress myRunnable = new MyRunnableWithProgress(receivedFileName);
ProgressMonitorDialog progressMonitorDialog = new MyProgressMonitorDialog(getShell(), cancellable);
try {
progressMonitorDialog.run(true, true, myRunnable);
} catch (InvocationTargetException e) {
// Catch in your best way
throw new RuntimeException(e);
} catch (InterruptedException e) {
//Catch in your best way
Thread.currentThread().interrupt();
}
Hope this helps!
I assume the reason why it's "not working" for you is that the preparation of input is done in UI thread meaning that the progress bar cannot be updated. A better approach is to prepare input in advance and only set input to viewer after that.