I need to make simple thing: from my app I have to make a photo, send it to server (in background) and show notification after sending. It all works, but now I have to wait for end of sending file - activity with camera is closing after that. I don't want to wait, I want to get back to my main activity right after taking picture (but upload would be still going in thread, and send notification when finishes).
The problem: I don't know how to let know to my main activity, that thread has finished uploading of photo.
Maybe passing context or handler to camera activity would help, but I can't do that by putExtra().
Any suggestions?
Some fragments of my code:
in MainActivity.java:
Intent intent = new Intent(this, Camera.class);
startActivityForResult(intent, Constants.REQUESTCODE_CAMERA);
in Camera.java:
#Override
protected void onCreate(Bundle savedInstanceState) {
//(...)
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
intent.putExtra(MediaStore.EXTRA_OUTPUT, photoUri);
startActivityForResult(intent,TAKE_PHOTO);
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
//(...)
new SendFileToServer().execute();
// finish(); // I would like to finish Camera.java here, and get back to MainActivity, while SendFileToServer uploads file and send some notification later
}
protected class SendFileToServer extends AsyncTask<Void, Void, String>{
#Override
protected String doInBackground(Void... params){
//(...) // here is sending of file to server, it works
}
#Override
protected void onPostExecute(String result) {
//(...) // code below doesn't work, because I didn't pass "context", I don't know how, or it's just impossible
MainActivity mainActivity = (MainActivity) context;
mainActivity.sendFileName(filename);
}
}
What you can do is send a broadcast on the end of the AsyncTask and register a receiver in the Activity where you want to do something (e.g. show notification).
To do that you will need to:
1) pass an Application Context to your AsyncTask (in Activity):
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
//(...)
new SendFileToServer(getApplicationContext()).execute(); // pass application context to AsyncTask
finish();
}
2) Send a broadcast from onPostExecute():
protected class SendFileToServer extends AsyncTask<Void, Void, String>{
private Context context;
public SendFileToServer(Context context) {
this.context = context;
}
#Override
protected String doInBackground(Void... params){
//(...) // here is sending of file to server, it works
}
#Override
protected void onPostExecute(String result) {
Intent intent = new Intent("com.example.UPLOAD_FINISHED");
context.sendBroadcast(intent);
}
}
3) Register a BroadcastReceiver in MainActivity (don't forget to unregister receiver in onPause()):
MainActivity.class
private BroadcastReceiver broadcastReceiver;
#Override
protected void onResume() {
super.onResume();
IntentFilter intentFilter = new IntentFilter(
"com.example.UPLOAD_FINISHED");
broadcastReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
// show notification
}
};
registerReceiver(broadcastReceiver, intentFilter);
}
#Override
protected void onPause() {
super.onPause();
unregisterReceiver(broadcastReceiver);
}
Related
I want to update an Activity which is not the MainActivity.
So I start a second Activity via a onClick method in MainActivity.
Now the Activty "SecondActivity" is at front.
When I started a Thread in the "MainActivity" how can I reference to the "SecondActivity" to update their TextViews and so on?
PseudoCode
public class activity_MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ThreadSome threadSome= new ThreadSome();
threadSome.start()
}
onClick(View View){
Intent intent = new Intent(this, activity_Second.class);
startActivity(intent);
}
}
Inside Thread
public class ThreadSome extends Thread {
#Override
public void run() {
//This is what I don't know, so I just write what I want to do.
// I know the following Code is wrong and not working.
activity_Second.someTextView.setText("Hi");
}
}
Is a WeakReference the best way to do this, or better work with static TextView objects? How would you solve this problem?
Based on your description, I think you want to do something where there will be some ui change in activity stack based on some event performed in the forground activity. There is a good way to use onActivityResult() via startActivityForResult() but if this is not fullfilling your requirement directly then you can try something like below:
/**
UpdateActivity is the activity where some ui update or action will be taken based on event in EventActivity.
**/
public class UpdateActivity extends Activity {
private BroadcastReceiver mReceiver;
public static final String ACTION_UPDATE = "com.my.internal.activity.action";
...
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_update);
......
//Prepared Intent for broadcast receiver
IntentFilter intentFilter = new IntentFilter(ACTION_UPDATE);
//registering our receiver
this.registerReceiver(mReceiver, intentFilter);
.....
}
//This is the receiver section where you need to do the ui update
mReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
//extract our message from intent
String some_msg = intent.getStringExtra("msg_1"); //parameter received if passed in intent when broadcast called.
//log our message value
Log.i("Message", some_msg);
updateActivityUi();
}
};
private void updateActivityUi() {
// you need to write the code for the update which you want to do after an event done in other activity.
}
#Override
protected void onDestroy() {
super.onDestroy();
//unregister our receiver
this.unregisterReceiver(this.mReceiver);
}
}
public class EventActivity extends Activity {
...
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_event);
......
//Sending BroadcastReceiver against the action ACTION_UPDATE and it will be received by UpdateActivity.
if(condition_for_event) {
Intent i = new Intent(UpdateActivity.ACTION_UPDATE).putExtra("msg_1", "Hey! an event performed here.");
this.sendBroadcast(i);
}
.....
}
....
}
Let me know if it solved your issue.
Send data from Activity to Fragment in Android using BroadcastReceiver. I know there is varies way to communicate Activity to Fragment.
But i don't know how to send data and receive using BroadcastReceiver.
From your Activity
Intent intent = new Intent("KEY");
sendBroadcast(intent);
In your fragment
private BroadcastReceiver mNotificationReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
updateUi();
}
};
#Override
protected void onResume() {
super.onResume();
registerReceiver(mNotificationReceiver, new IntentFilter("KEY"));
}
#Override
protected void onPause() {
super.onPause();
unregisterReceiver(mNotificationReceiver);
}
In my app, whenever I receive a push notification, I will perform a check if my mainActivity is visible to the user to do something...
I have a static boolean value that is set true inside onResume of mainActivity, and false inside it's onPause.
What should I do inside the onMessage
#Override
protected void onMessage(Context context, Intent intent)
{
if(mainActivity == visible)
//do something inside mainactivity.. change text inside edittext
else
//do something else
}
any insights ?
I'm not a fan of keeping static references to activities. I think they're a can of worms ready to explode on you. So you'll suggest an alternative to #TeRRo answer:
on your global BroadcastReceiver onMessage you'll send a LocalBroadcast that your activity will be listening to. Like this:
private static final String ACTION_PUSH_RECEIVED = "com.myapp.mypackage.action.pushReceived";
public static final IntentFilter BROADCAST_INTENT_FILTER = new IntentFilter(ACTION_PUSH_RECEIVED);
#Override
protected void onMessage(Context context, Intent intent) {
Intent i = new Intent(ACTION_PUSH_RECEIVED);
i.putExtra( ... add any extra data you want... )
LocalBroadcastManager.getInstance(context).sendBroadcast(i);
}
and now we make the activity listen to it:
#Override
protected void onResume() {
super.onResume();
LocalBroadcastManager.getInstance(context)
.registerReceiver(mBroadcastReceiver, BroadcastReceiverClass.BROADCAST_INTENT_FILTER);
}
#Override
protected void onPause() {
LocalBroadcastManager.getInstance(context)
.unregisterReceiver(mBroadcastReceiver);
super.onPause();
}
private BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver(){
#Override
public void onReceive(Context context, Intent intent){
// read any data you might need from intent and do your action here
}
}
To avoid this, you should manage activities references. Add the name of the application in the manifest file:
<application
android:name=".MyApp"
....
</application>
Your application class :
public class MyApp extends Application {
public void onCreate() {
super.onCreate();
}
private Activity mCurrentActivity = null;
public Activity getCurrentActivity(){
return mCurrentActivity;
}
public void setCurrentActivity(Activity mCurrentActivity){
this.mCurrentActivity = mCurrentActivity;
}
}
Create a new Activity :
public class MyBaseActivity extends Activity {
protected MyApp mMyApp;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mMyApp = (MyApp)this.getApplicationContext();
}
protected void onResume() {
super.onResume();
mMyApp.setCurrentActivity(this);
}
protected void onPause() {
clearReferences();
super.onPause();
}
protected void onDestroy() {
clearReferences();
super.onDestroy();
}
private void clearReferences(){
Activity currActivity = mMyApp.getCurrentActivity();
if (currActivity != null && currActivity.equals(this))
mMyApp.setCurrentActivity(null);
}
}
So, now instead of extending Activity class for your activities, just extend MyBaseActivity. Now, you can get your current activity from application or Activity context like that :
Activity currentActivity = ((MyApp)context.getApplicationContext()).getCurrentActivity();
Or why don't you use the Local broadcasts when you receive the push notification, and receive it in your activity, and do respective changes or actions.
And if they are UI intensive tasks, bind your activity to a service, and receive the push notification and perform the action in this service and use the result in the activity.
My requirement is when a push notification comes in my device, I need to call an Asynctask. The app can be running in background. I shouldn't click the notification, instead when it comes I need to call Asynctask. Is that possible?
In your GCMIntentService just override onMessage(..) method this method called when push notification is comming in device.
#Override
protected void onMessage(Context context, Intent intent) {
mContext = context;
final String message = intent.getStringExtra("message");
Log.e(TAG, "GCM Received message : "+message);
AsyncTask<Void, Void, Void> DatabaseOperationTask = new AsyncTask<Void, Void, Void>() {
#Override
protected Void doInBackground(Void... params) {
// do your Database Operation here
return null;
}
#Override
protected void onPostExecute(Void result) {
super.onPostExecute(result);
}
};
DatabaseOperationTask.execute();
}
Yes it is possible
you have GCMIntentService which have the method
#Override
protected void onMessage(Context context, Intent intent)
{
}
this method receives message and generate notification you can execute your async task in this method if you need any context the service has its own context
I have a service that listens for (ON_BATTERY_CHANGE), then onReceive service sends a Broadcast to My MainActivity. The problem is that I somehow can't get them from service to my main activity. Code: Main Activity:
public class MainActivity extends Activity
private BroadcastReceiver batteryReceiverService;
private TextView text2;
....
protected void onCreate(Bundle savedInstanceState) {
text2=(TextView)findViewById(R.id.TV_text2);
batteryReceiverService = new BroadcastReceiver(){
#Override
public void onReceive(Context context, Intent intent) {
text2.setText("left: "+intent.getStringExtra("H")+" hours "+intent.getStringExtra("M")+" minute(s)");
Log.e("text2","text2 HHH " +intent.getStringExtra("H")); //log shows 0
Log.e("text2","text2 MMM " +intent.getStringExtra("H")); // log shows 0
}
};
registerReceiver(batteryReceiverService, new IntentFilter(UltimateBatterySaverService.BROADCAST_ACTION));
....
#Override
protected void onDestroy() {
unregisterReceiver(batteryReceiverService);
super.onDestroy();
}
Service:
public class UltimateBatterySaverService extends Service {
private Intent intent;
static final String BROADCAST_ACTION = "lt.whitegroup.ultimatebatterysaver";
private BroadcastReceiver batteryLevelReceiver;
....
public void onCreate() {
super.onCreate();
intent = new Intent(BROADCAST_ACTION);
}
#Override
public void onDestroy() {
unregisterReceiver(batteryLevelReceiver);
super.onDestroy();
}
IntentFilter batteryLevelFilter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
batteryLevelReceiver = new BroadcastReceiver(){
#Override
public void onReceive(Context context, Intent intent){
// Receiving data, calculating and etc
averageChargingH=timeAllInHours;
averageChargingM=timeAllInMinutes;
// to put extras and send broadcast
does();
......
public void does(){
String strLong = Long.toString(averageChargingH);
String strLong2 = Long.toString(averageChargingM);
Log.e("cccccc","strLong h "+strLong); // getting good value not 0(everything ok)
Log.e("cccccc","strLong2 m"+strLong2); // getting good value not 0(everything ok)
intent.putExtra("H", strLong);
intent.putExtra("M", strLong2);
sendBroadcast(intent);
}
Any ideas why my information is not transfered correctly?
The does() method seems to be using variables in the same scope as onReceive so I'm guessing that the intent variable in does() is actually the Intent passed in from onReceive.
Try adding some logging before sending the broadcast to check if the action of the intent is correct, or simply create the broadcast intent in the onReceive method and name it intent2.