I have an activity that listens to preference changes and reloads the app. I am using recreate() to do that. But I don't know how to pass in arguments through that, so I have resorted to manual activity reloading.
Intent intent = getIntent();
finish();
// add in the arguments as Extras to the intent
startActivity(intent);
This has the behaviour I want, but the recreating of the activity isn't smooth for the user as they will see the activity being killed and the same activity relaunching. I want the user to not be aware that the activity was relaunched. So, my question is can I use the method recreate() and still pass arguments through it.
You can set the data on the activity's intent before calling recreate
getIntent().putExtra("RECREATE_DATA", "Some Data");
recreate()
since when you recreate the activity the same activity instance is used, the data in the intent will still be there after recreate.
You can try this way:
You can restart you activity with launch Mode as SingleTop and handle the onNewIntent(Intent intent) method. This way you are restarting the activity and send the intent, along with this activity is not being Killed i.e. oncreate of your activity will not be called.
public class MainActivity extends Activity implements View.OnClickListener {
Button btn ;
String mRelaunchData ;
public static String TAG = "RelaunchMainActivity";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btn = (Button)findViewById(R.id.button);
btn.setOnClickListener(this);
Log.e(TAG, "onCreate called");
}
#Override
public void onClick(View view) {
Log.e(TAG, "onClick called");
Intent intent = new Intent("relaunch.activity.ACTIVITY_SELF_START_INTENT").setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
intent.putExtra("RESTART_DATA", "This is relaunch of this Activity");
startActivity(intent);
}
#Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
Log.e(TAG, "onNewIntent called");
mRelaunchData = intent.getStringExtra("RESTART_DATA");
Log.e(TAG, "mRelaunchData =" + mRelaunchData);
}
#Override
protected void onResume() {
super.onResume();
Log.e(TAG, "onResume called");
if(mRelaunchData != null){
Toast.makeText(MainActivity.this, mRelaunchData, Toast.LENGTH_SHORT).show();
}
}
#Override
protected void onPause() {
super.onPause();
Log.e(TAG, "onPause called");
}
#Override
protected void onStart() {
super.onStart();
Log.e(TAG, "onStart called");
}
#Override
protected void onStop() {
super.onStop();
Log.e(TAG, "onStop called");
}
#Override
protected void onDestroy() {
super.onDestroy();
Log.e(TAG, "onDestroy called");
}
}
in AndroidManifest.xml
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<action android:name="relaunch.activity.ACTIVITY_SELF_START_INTENT" />
<category android:name = "android.intent.category.DEFAULT"/>
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
onClick will relaunch the Activity.
LifeCycle will be
-onclick
-onPause
-onNewIntent
-onResume
Related
There are two applications : Caller, Callee
Case 1 >
When I launch Callee application from home screen, I can get an action("android.intent.action.MAIN") from INTENT.
While Callee is running, I launch Callee application with an action("andoird.intent.action.test") again from Caller application. Then I get the action("android.intent.action.MAIN"). not action("andoird.intent.action.test").
How can I get the action("andoird.intent.action.test")?
Case 2 >
When I launch Callee application with an action("andoird.intent.action.test"), I get the action("andoird.intent.action.test").
While Callee is running, I launch Callee application from the home screen. Then I get the action("andoird.intent.action.test"). not action("android.intent.action.Main").
How can I get the action("android.intent.action.Main")?
What am I missing to get the proper action?
Here is Caller code below.
public class CallerActivity extends AppCompatActivity {
public static final String ACTION_TEST = "android.intent.action.test";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button test = (Button) findViewById(R.id.gotoSetting);
test.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent intent = getPackageManager().getLaunchIntentForPackage(PACKAGE);
intent.setAction(ACTION_TEST);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_SINGLE_TOP);
startActivity(intent);
}
});
}
}
Here is Callee code below.
public class CalleeActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Log.e("test", "onCreate()");
Log.e("test", getIntent().getAction());
}
#Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
Log.e("test", "onNewIntent()");
Log.e("test", getIntent().getAction());
}
}
Here is Callee's AndroidManifest.
<activity
android:name=".CalleeActivity"
android:launchMode="singleTop"
android:screenOrientation="portrait"
android:windowSoftInputMode="stateHidden">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.test"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</activity>
Please help.
Replace this code:
#Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
Log.e("test", "onNewIntent()");
Log.e("test", getIntent().getAction());// getIntent() will return old intent
}
with
#Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
Log.e("test", "onNewIntent()");
Log.e("test", intent.getAction()); //use new intent
}
I have a single Activity and one Service. The activity is used for search and the service is used to display a hovering widget over all the screens like Facebook chat head does.
When the user leaves the activity like pressing back key I start a service and the widget starts hovering. On Clicking the hovering widget the activity is again relaunched from service by using FLAG_ACTIVITY_NEW_TASK. But doing this when my activity is overlapped by other app activity neither onStop() nor onPause() is getting called. onStop() is called when the activity on top of it onStop() is called.
Can someone explain why this is happening? Thanks in advance.
Activity Code:
public class CouponSearchActivity extends AppCompatActivity {
public static final String TAG = CouponSearchActivity.class.getSimpleName();
public static final String BROADCAST_ACTION_ACTIVITY_STARTED =
"activity_created";
public static final String BROADCAST_ACTION_ACTIVITY_STOPPED = "activity_stopped";
public static void startActivity(Context context){
Intent intent = new Intent(context, CouponSearchActivity.class);
context.startActivity(intent);
}
public static void startActivityFromService(Context context){
Intent intent = new Intent(context, CouponSearchActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(intent);
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.d("TAG",": onCreate()");
setContentView(R.layout.activity_coupon_search);
CouponWidgetService.stopService(this);
if(savedInstanceState == null){
initCouponSearchFragment();
}
}
#Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
Log.d("TAG",": onNewIntent()");
}
private void initCouponSearchFragment(){
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.add(R.id.container, CouponSearchFragment.newInstance()).commit();
}
private void sendBroadcast(){
Intent intent = new Intent();
intent.setAction(BROADCAST_ACTION_ACTIVITY_STARTED);
sendBroadcast(intent);
Log.d("Broadcast sent", action = " +BROADCAST_ACTION_ACTIVITY_STARTED);
}
#Override
protected void onResume() {
super.onResume();
Log.d("TAG","onResume()");
sendBroadcast();
CouponWidgetService.stopService(this);
}
#Override
protected void onPause() {
super.onPause();
Log.d("TAG + "onPause()");
}
#Override
protected void onStop() {
super.onStop();
Intent intent = new Intent();
intent.setAction(BROADCAST_ACTION_ACTIVITY_STOPPED);
sendBroadcast(intent);
Log.d("TAG", "onStop()");
Log.d("Broadcast sent", action = " + BROADCAST_ACTION_ACTIVITY_STOPPED);
CouponWidgetService.startService(this, StoreCoupons.getStoreCouponsResponse(), StoreCoupons.getSelectedCategories());
}
#Override
public void onBackPressed() {
Log.d("onBackPressed()");
//CouponWidgetService.startService(this, StoreCoupons.getStoreCouponsResponse(), StoreCoupons.getSelectedCategories());
super.onBackPressed();
}
But doing this when my activity is overlapped by other app activity
neither onStop() nor onPause() is getting called.
This looks like a legit behavior to me. When your Activity is overlapped by some other Activity, onPause will be called. If the "overlap" is complete (i.e. your Activity is no longer visible), then its onStop should also be called.
At some later time, when you click on "hovering widget", your Activity is already paused (and, potentially, stopped), therefore it won't get those lifecycle callbacks again.
I tried to learn LocalBroadcastManager. Searched in web and implemented a simple app with Two activity to perform LocalBroadcastManager. But it's not working. I can't found what's wrong with my code. please help me!
here is my code.
FirstActivity.java
public class FirstActivity extends Activity {
private Button button;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_first);
button = (Button) findViewById(R.id.button);
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
startActivity(new Intent(FirstActivity.this, SecondActivity.class));
Intent intent = new Intent("localReceiver");
LocalBroadcastManager.getInstance(FirstActivity.this).sendBroadcast(intent);
}
});
} }
SecondActivity.java
public class SecondActivity extends Activity {
private TextView textView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_second);
textView = (TextView) findViewById(R.id.hi_text);
LocalBroadcastManager.getInstance(this).registerReceiver(message, new IntentFilter("localReceiver"));
}
#Override
protected void onPause() {
super.onPause();
LocalBroadcastManager.getInstance(this).unregisterReceiver(message);
}
private BroadcastReceiver message = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
Log.d("SecondActivity", "Receiver Initiated...");
textView.setText("Intent receiver activated");
}
}; }
AndroidManifest.xml
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:theme="#style/AppTheme" >
<activity
android:name=".FirstActivity"
android:label="#string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name=".SecondActivity"
android:windowSoftInputMode="adjustResize|stateHidden"
android:label="SecondActivity" />
</application>
you are broadcasting something from FirstActivity, and you expect that SecondActivity receives it. In order this to happen you should be able to run two different Activitys at the same time, which is, by design, not possible. By the time you broadcast the string, you don't have anybody listening for it. Try using a Service to broadcast the String, with the receiving Activity resumed, and it will work
SecondActivity would looks like this:
private BroadcastReceiver uiUpdateReceiver;
onStart():
#Override
protected void onStart() {
LocalBroadcastManager.getInstance(SecondActivity.this).registerReceiver((uiUpdateReceiver), new IntentFilter("Your_Data");
super.onStart();
}
onCreate():
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_second);
uiUpdateReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
}
};
}
onStop():
#Override
protected void onStop() {
LocalBroadcastManager.getInstance(ChatActivity.this).unregisterReceiver(uiUpdateReceiver);
super.onStop();
}
Hope it will help you.
The next process is simple to understand and to reproduce but leads to a bug:
activityA starts an activityB in its onCreate() method
activityB is created and I call finish() in its onResume() method
activityB onDestroy() is called
activityA onResume() is called
and here in activityA, I click a menu button to call finish() - or press the back key.
activityA is removed but onDestroy() is NOT called and A is still living ( adb shell dumpsys 'myPackageName' indicates too many living Activities )
Code
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="gleroy.com.algo">
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:theme="#style/AppTheme">
<activity
android:name=".activity.MainActivity"
android:label="#string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name="gleroy.com.algo.activity.FakeA"
android:label="#string/app_name"></activity>
<activity
android:name="gleroy.com.algo.activity.FakeB"
android:label="#string/app_name"></activity>
</application>
</manifest>
Activity A :
public class FakeA extends Activity {
private final static String TAG = FakeA.class.getCanonicalName();
#Override
protected void onCreate(Bundle savedInstanceState) {
Log.d(TAG, "onCreate, taskId :" + getTaskId());
super.onCreate(savedInstanceState);
Intent intent = new Intent(FakeA.this, FakeB.class);
startActivity(intent);
}
#Override
protected void onResume() {
Log.d(TAG, "onResume");
super.onResume();
}
#Override
protected void onDestroy() {
Log.d(TAG, "onDestroy");
super.onDestroy();
}
#TargetApi(Build.VERSION_CODES.HONEYCOMB)
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_main, menu);
super.onCreateOptionsMenu(menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.stop_session_menu_item:
/* stop and quit */
finish();
return false;
}
return super.onOptionsItemSelected(item);
}
}
Activity B :
public class FakeB extends Activity {
private final static String TAG = FakeB.class.getCanonicalName();
#Override
protected void onCreate(Bundle savedInstanceState) {
Log.d(TAG, "onCreate, taskId :"+getTaskId());
super.onCreate(savedInstanceState);
}
#Override
protected void onResume() {
super.onResume();
Log.d(TAG, "onResume, isFinishing :" + isFinishing());
finish();
}
#Override
protected void onDestroy() {
super.onDestroy();
Log.d(TAG, "onDestroy");
}
}
Activity A is started from MainActivity which contains a simple button :
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
findViewById(R.id.btn).setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent intent = new Intent(MainActivity.this, FakeA.class);
startActivity(intent);
}
});
So I know that we can't be sure that onDestroy() is gonna be called but here my ActivityA is clearly leaking.
Also I observed that if I use a Timer and TimerTask to delay startActivity in ActivityA or finish() in ActivityB then I don't have this bug anymore.
Here are the events :
FakeA onCreate, taskId :154
FakeA onResume
FakeA onPause, isFinishing : false
FakeB onCreate, taskId :154
FakeB onResume, isFinishing :false
FakeA onResume
FakeB onDestroy
call finish or press back key : FakeA onPause, isFinishing : true
In place of finish() try finishAffinity().
As far as i know:
finish() just destroys the current live Activity
while, finishAffinity() destroys all active Activities.
The best solution was simply to detect whether or not it is useful to start Activity FakeB.
I am working on an application that display the messages , for that i am using BroadcastReceiver inside my activity and i am trying to refresh the listview inside onReceive method , but onReceive is not getting call some how please help me with this.
public class MessageActivity extends BaseActivity {
private BroadcastReceiver mMessageReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
// Extract data included in the Intent
String message = intent.getStringExtra("message");
Log.d("receiver", "Got message: " + message);
Toast.makeText(getApplicationContext(), "Inside Reciver",Toast.LENGTH_SHORT).show();
getSMSCursorCount();
loadInitialMessages();
}
};
protected void onCreate(Bundle savedInstanceState) {
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
super.onCreate(savedInstanceState);
setContentView(R.layout.messageinbox);
}
#Override
public void onResume() {
super.onResume();
IntentFilter intentFilter = new IntentFilter("android.provider.Telephony.SMS_RECEIVED");
intentFilter.setPriority(1000);
registerReceiver(mMessageReceiver, intentFilter);
Log.d("This is onResume method ","<<<<<<<<< onResume <<<<<<<<<");
try {
getSMSCursorCount();
loadInitialMessages();
} catch (Exception e) {
e.printStackTrace();
}
}
#Override
protected void onPause()
{
super.onPause();
try {
unregisterReceiver(mMessageReceiver);
} catch (IllegalArgumentException e) {
if (e.getMessage().contains("Receiver not registered")) {
// Ignore this exception. This is exactly what is desired
Log.w(TAG,"Tried to unregister the reciver when it's not registered");
} else {
// unexpected, re-throw
throw e;
}
}
Log.d("This is onPause method ","<<<<<<<<< onPause <<<<<<<<<");
}
You have to write separate broadcast receiver class by extending BroadcastReceiver and declare it in your manifest file with intentfilter. Override the onReceive method and call your activity there.In oncreate of activity refresh yor listview if the intent is from broadcast receiver.
public class MessageReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
System.out.println("inside message receiver... ");
Intent popupintent = new Intent(context,ShowNotificationDialog.class);
popupintent.putExtra("from", "broadcast");
context.startActivity(popupintent);
}
public class ShowNotificationDialog extends Activity
{
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Intent i = getIntent();
String fromString = i.getStringExtra("from");
if(from != null)
{
if(from.equals("from"))
// refresh your listview
}
}
}
In manifest:
<receiver android:name=".MessageReceiver" >
<intent-filter>
<action android:name="broadcast action" />
</intent-filter>
</receiver>