Why Intents are not preserved in android - java

I'm testing my mobile phone how many intents can be created in parallel but only one is created...
This is my app manifest
<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"
android:launchMode="standard">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<activity
android:name=".IntentExamples"
android:exported="false"
android:launchMode="standard"
android:parentActivityName=".MainActivity">
</activity>
</application>
And this is the class where I do all the calls...
public class IntentExamples extends AppCompatActivity {
// Numbers of intents created
static int COUNTER = 0;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_intent_examples);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
// When a intent is created +1 to the counter
COUNTER++;
((TextView) findViewById(R.id.intent_counter)).setText("NUMBER OF INTENTS: " + COUNTER);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.main_menu, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch(item.getItemId()){
case R.id.another_intent:
Intent intent = new Intent(IntentExamples.this, IntentExamples.class);
startActivity(intent);
case android.R.id.home:
this.finish(); break;
default:
return false;
}
return true;
}
#Override
protected void onDestroy() {
super.onDestroy();
// When a intent is completely destroy, -1 to the counter
COUNTER--;
}
The main activity just have a copy pasted code from the menu's code...
When I hit the item menu that creates another intent, in the TextView shows 1 intent created, I hit it again, shows 2 intents created and when I hit the button a 3rd time it got stuck in 2 intents created... I don't understand the reason why the counter doesn't reach 3 intents created or more.

Take a look at this code from onOptionsItemSelected()
switch(item.getItemId()){
case R.id.another_intent:
Intent intent = new Intent(IntentExamples.this, IntentExamples.class);
startActivity(intent);
case android.R.id.home:
this.finish(); break;
default:
return false;
}
There is no break; after startActivity(), so the Activity finishes. So eventually (not necessarily immediately!) onDestroy() is called and COUNTER-- is executed.
Because the Activity has called finish(), it is not possible to reach it once more by pressing BACK - and this "misbehaviour" was what I could not explain in the first place. I was ready to believe that the Runtime would keep at most two Activity instances alive and store all the others in the BackStack. But not being able to go back? There had to be an explanation for this - and I'm kind of relieved I've found it :)
Now why does COUNTER show 1 instead of 2 after rotating the device?
That's because an orientation change (like all configuration changes) causes all Activity instances to be destroyed, and the one which was shown is instantly recreated.

Related

Wrong activity displayed when implicit intent received from another app with Action.SEND

I have an app with two activities: MainActivity, which contains a URL entry field where the user can enter a YouTube video URL and press a submit button, to start the second activity, VideoActivity, which displays some information about this video (fetched from another web server).
The app also has a feature to receive intent via the Youtube application. When user presses the share button within the Youtube app, my app appears in the share list. Upon pressing share from the Youtube app, MainActivity should be brought to the front, and the URL should be posted within the MainActivity's URL field.
However, this only happens correctly on the first share. If the app is in the background when user shares from Youtube app, they are taken to whatever the last visible activity was, whether it is MainActivity or VideoActivity, (and even if it is MainActivity, the URL is not posted into the URL field, but the field is left in whatever state it was in when the app was last visible).
Here is my current AndroidManifest.xml:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.youcmt.youdmcapp">
<uses-permission android:name="android.permission.INTERNET"/>
<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"
android:launchMode="singleTop">
<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.SEND"/>
<category android:name="android.intent.category.DEFAULT"/>
<data android:mimeType="text/plain"/>
</intent-filter>
</activity>
<activity
android:name=".VideoActivity"
android:parentActivityName=".MainActivity"/>
<service
android:name=".FetchVideoService"
android:exported="false"/>
</application>
</manifest>
Here is my MainActivity.java code:
public class MainActivity extends AppCompatActivity {
private ResponseReceiver mReceiver;
private EditText mUrlEditText;
private Button mSearchButton;
private ProgressBar mProgressBar;
#Override
protected void onCreate(Bundle savedInstanceState) {
setContentView(R.layout.activity_main);
super.onCreate(savedInstanceState);
mUrlEditText = findViewById(R.id.url_search_et);
Intent intent = getIntent();
if (intent.getType()!=null &&
intent.getType().equals("text/plain")) {
Bundle extras = getIntent().getExtras();
String value = extras.getString(Intent.EXTRA_TEXT);
if(value!=null)
{
mUrlEditText.setText(value);
}
}
mProgressBar = findViewById(R.id.progress_bar);
mSearchButton = findViewById(R.id.search_button);
mSearchButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
try {
askForVideo(mUrlEditText.getText().toString());
mSearchButton.setVisibility(View.INVISIBLE);
mProgressBar.setVisibility(View.VISIBLE);
} catch (Exception e) {
mUrlEditText.setText("");
mUrlEditText.setHint(e.getMessage());
e.printStackTrace();
}
}
});
}
#Override
protected void onResume() {
super.onResume();
//register the ResponseReceiver
mReceiver = new ResponseReceiver();
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(FETCH_VIDEO_INFO);
registerReceiver(mReceiver, intentFilter);
}
private void askForVideo (String url) throws Exception {
try {
Intent intent = FetchVideoService.newIntent(this, url);
startService(intent);
} catch (Exception e) {
mUrlEditText.setText(e.getMessage());
}
}
public class ResponseReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
int status = intent.getIntExtra(EXTRA_VIDEO_STATUS, FAIL);
mProgressBar.setVisibility(View.INVISIBLE);
mSearchButton.setVisibility(View.VISIBLE);
if(status==FAIL)
{
mUrlEditText.setText("");
mUrlEditText.setHint("Error retrieving video!");
}
else if(status==SUCCESS) {
Video video = intent.getParcelableExtra(EXTRA_VIDEO);
Intent videoActivityIntent =
VideoActivity.newIntent(getApplicationContext(), video);
startActivity(videoActivityIntent);
}
}
}
#Override
protected void onPause() {
unregisterReceiver(mReceiver);
super.onPause();
}
}
I do not think any of the other files will be useful in understanding the problem. Although this seems like something many app creators should have to deal with, I can find no answers to this problem. Please comment if you feel I should add any additional information and thank you in advance for any help!
Update: testing demonstrates that after the first use of "Share" from YouTube (and considering app remains in the background), the MainActivity no longer receives any new intent on further shares. However, my app is still brought to the foreground somehow. This is very confusing to me.
When you share from another app, your MainActivity is brought to the front and onNewIntent() is called on it. You don't override onNewIntent() so you never see the share Intent.

SplashScreen everytime I'm back on MainActivity

I'm using this code on MainActivity for a splashscreen that works perfectly
final ImageView splash1 = (ImageView) this.findViewById(R.id.splash);
new Handler().postDelayed(new Runnable(){
#Override
public void run() {
splash1.setVisibility(View.GONE);
}
}, 1000);
but everytime I'm back on MainActivity (where the main menu is), the splashScreen is there again. Is there a way to keep using this code, and just adding an if condition do not see the splashScreen after the first time?
(e.g: a variable that changes when the app loads)
Thanks in advance
Use 2 different activity SplashActivity and MainActivity.
Your "Splash" activity need to be MAIN LAUNCHER Activity. So modify the AndroidManifest file like this...
<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">
</activity>
<activity android:name=".Splash">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
And Jump to MainActivity from SplashActivity after few seconds.. Use this code in SplashActivity.
Handler hadler=new Handler();
hadler.postDelayed(new Runnable() {
#Override
public void run () {
finish();
Intent i = new Intent(context, MainActivity.class);
startActivity(i);
}
}, 3000);
here 3000 is used for 3 seconds. The MainActivity auto start after 3 seconds. Hope it helps.
Use separate activity for splash screen after that go for MainActivity, Don't forget to use finish() in splash screen activity.
This link may help you
http://androidexample.com/Splash_screen_-_Android_Example/index.php?view=article_discription&aid=113&aaid=135
Simply create one variable to know whether its displayed or not.
class YourActivity extends Activity {
boolean isDisplayed;
#Override
protected void onStart() {
if (!isDisplayed) {
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
isDisplayed = true;
splash1.setVisibility(View.GONE);
}
}, 1000);
} else {
splash1.setVisibility(View.GONE);
}
}
}
use finish() after starting the SplashScreen Activity
EDIT:
One more approach can be - Create a boolean application level variable (set to false) by extending Applicationclass & then checking it in the runmethod - If false then show the splash & set it to true, so that it will not execute again.
public class DefaultApplication extends Application {
private boolean isSplashDisplayed = false;
public boolean isSplashDisplayed() {
return isSplashDisplayed ;
}
public void setIsSplashDisplayed(boolean isSplashDisplayed) {
this.isSplashDisplayed = isSplashDisplayed;
}
}
Second Approach -
Its better to create a separate activity for Splash, then call MainActivity from SplashActivity & finish SplashActivity
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
Intent i = new Intent(SplashScreen.this, MainActivity.class);
startActivity(i);
finish();
}
}, 1000);
Also need to make your SplashActivity as launcher
<activity
android:name=".SplashActivity"
android:label="#string/title_activity_splash_screen" >>
<intent-filter>
<action android:name="android.intent.action.MAIN" />>
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
< /activity>

Killing the activity when user clicks the home button

Okey, this is weird.
I have two activities (well, more than two, but they don't matter) - AppActivity and PopupActivity. AppActivity is my main application activity and it contains my app's settings. PopupActivity is a dialog that gets opened when user clicks the button in the notification (it's a RemoteViews notification). Well, it works. Works great. But only if user closed the AppActivity by clicking the back button. If they clicked home, PopupActivity opens after a few seconds after clicking the button. Same thing happens when user closes the PopupActivity with a home button. Clicking the button in the notification doesn't open the PopupActivity instantly, but it takes a few seconds to kill the previous activity that still exists somewhere in the background.
I've tried calling finish() in the onStop and onPause methods, but it doesn't fix my problem.
Edit: Here's the code I have:
Manifest:
<activity
android:name="cc.lupine.quicksocial.AppActivity"
android:label="#string/app_name"
android:configChanges="orientation|screenSize" android:noHistory="true" android:clearTaskOnLaunch="true" android:finishOnTaskLaunch="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:configChanges="orientation|screenSize"
android:excludeFromRecents="true"
android:showOnLockScreen="false"
android:theme="#android:style/Theme.Holo.Light.Dialog.NoActionBar.MinWidth"
android:name="cc.lupine.quicksocial.PopupActivity"
android:noHistory="true"
android:launchMode="singleInstance"
android:taskAffinity=""
>
<intent-filter>
<action android:name="android.intent.action.MAIN" />
</intent-filter>
</activity>
<service android:name="cc.lupine.quicksocial.ShareService"></service>
ShareService.java (just a function that gets called when user clicks a button in the notification):
public static void startSharing(Context ctx, int n) {
Log.d("sn", "startsharing called in shareservice");
if(n == 1 || n == 2)
{
Intent i = new Intent(ThisApplication.getAppContext(), PopupActivity.class);
i.putExtra("shareType", n);
i.setFlags(Intent.FLAG_ACTIVITY_NO_HISTORY|
Intent.FLAG_ACTIVITY_CLEAR_TOP|
Intent.FLAG_ACTIVITY_SINGLE_TOP|
Intent.FLAG_ACTIVITY_CLEAR_TASK|
Intent.FLAG_FROM_BACKGROUND|
Intent.FLAG_ACTIVITY_NEW_TASK);
ctx.startActivity(i);
} else if(n == 3) {
// doesn't matter for now
}
}
PopupActivity.java (fragments):
public class PopupActivity extends Activity implements OnDataPass {
#Override
protected void onCreate(Bundle savedInstanceState) {
Log.d("sn", "oncreate called in popupactivity");
super.onCreate(savedInstanceState);
instanceOfPopupActivity = this;
setContentView(R.layout.activity_popup);
ShareFragment sfrag = new ShareFragment();
Bundle args = new Bundle();
Bundle extras = getIntent().getExtras();
try {
//doesn't matter
} catch(Exception e) { e.printStackTrace(); finish(); }
sfrag.setArguments(args);
FragmentManager fragmentManager = getFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.contFragment, sfrag);
fragmentTransaction.commit();
}
#Override
public void onPause()
{
Log.d("sn", "onpause called in popupactivity");
finish();
super.onPause();
}
#Override
public void onStop() {
Log.d("sn", "onstop called in popupactivity");
super.onStop();
}
#Override
public void onDestroy()
{
Log.d("sn", "ondestroy called in popupactivity");
super.onDestroy();
}
}
And if I open the popup for the first time:
05-26 14:37:14.149: D/sn(7218): startsharing called in shareservice
05-26 14:37:14.179: D/sn(7218): oncreate called in popupactivity
But when I close the popup with a home button and try to open it again:
05-26 14:38:11.620: D/sn(7218): startsharing called in shareservice
05-26 14:38:14.103: D/sn(7218): oncreate called in popupactivity
It takes a lot of time for onCreate to be called. And now, what's the reason?
I think you are focusing on the wrong problem (killing the activity) instead of focusing on the real problem (10 seconds to start it again).
First you need to understand WHY it is taking 10 seconds to open it if you exited the other acitivty with the home key!
If you posted more details (with source code) it would have been easier to understand and help you!
call finish() when you want to close app. Call finish() on both activities and watch out popup window has to be focusable to handle click.

andengine start game from menu

I want to start a game from a menu. In Eclipse, I have 2 projects, one with the menu, the other the actual game. Both using SimpleBaseGameActivity as their base. The examples on the net do something like below. In particular, it creates an intent and starts an activity with that intent. The code below gives a NoClassDefFoundError on MyGame.class. This is no surprise since MyGame.class doesn't exist, but rather MyGame.apk does. How do I do this?
public boolean onMenuItemClicked(final MenuScene pMenuScene,
final IMenuItem pMenuItem,
final float pMenuItemLocalX,
final float pMenuItemLocalY) {
switch(pMenuItem.getID()) {
case MENU_PLAY:
MainActivity.this.runOnUiThread(new Runnable() {
public void run() {
Intent intent = new Intent(getApplication(), MyGame.class);
startActivity(intent);
finish();
}
});
return true;
}
}
----- edit
I've got it working, with everything in one project, in that when the menu item is clicked on, then the game starts. However, when the 'back arrow' is clicked, it doesn't return to the menu, but rather to the operating system. The activity definitions in the manifest file are below. Does this look correct?
<activity
android:name=".MainActivity"
android:label="#string/title_activity_main" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name="com.mygame.MyGame"
android:label="#string/mygame_activity"
android:parentActivityName="com.menu.MainActivity" >
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value="com.menu.MainActivity" />
</activity>
I added this to MyGame, but it doesn't get called:
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
}
--- edit
I needed to remove this line:
MainActivity.this.finish();
first insert in the Manifest in the tags
<application>...</application>
this tag:
<activity
android:name=".MyGame"
android:label="MygameName" >
</activity>
and change in your code:
public boolean onMenuItemClicked(final MenuScene pMenuScene,
final IMenuItem pMenuItem,
final float pMenuItemLocalX,
final float pMenuItemLocalY) {
switch(pMenuItem.getID()) {
case MENU_PLAY:
MainActivity.this.runOnUiThread(new Runnable() {
public void run() {
Intent intent = new Intent(MainActivity.this, MyGame.class);
startActivity(intent);
MainActivity.this.finish();
}
});
return true;
MyGame have to be an activity and it must be mentioned in Android.manifest as an activity.
http://developer.android.com/training/basics/firstapp/starting-activity.html
Please Remove call to function "finish()" and then it will take you back to the parent activity.

Launch an activity from a menu button?

I've making an app and I want to launch a new activity from a menu, but ever time I click the menu button, the app crashes. I've tried many ways and all of the have failed.
public boolean onCreateOptionsMenu(Menu menu) {
new MenuInflater(getApplication())
.inflate(R.menu.menu, menu);
return(super.onPrepareOptionsMenu(menu));
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.Menu1:
Toast.makeText(this, "Coming soon", Toast.LENGTH_SHORT).show();
break;
case R.id.Menu2:
Intent Intent = new Intent(this, About.class);
startActivity(Intent);
}
return(super.onOptionsItemSelected(item));
}
}
Android Manifest
<application android:icon="#drawable/icon" android:label="#string/app_name" android:debuggable="true">
<activity android:name=".AndroidRssReader"
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=".About" android:label="#string/app_label"></activity>
Intent Intent = new Intent(this, About.class);
startActivity(Intent);
This needs to become
Intent intent = new Intent(this, About.class);
startActivity(intent);
My implementation of onOptionsItemSelected() is slightly different as I am returning true when I have handled the selection myself, rather than always passing to the superclass.
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.Menu1:
Intent myIntent = new Intent(this,About.class);
startActivity(myIntent);
return true;
default:
return super.onOptionsItemSelected(item);
}
}
Check the documentation
We really need to see the logcat to be sure though
It could be a few things, for example is the About class in your root package? (since you declare it as android:name=".About")
But the best way to troubleshoot this is to have a look at the crash details in Logcat (both Eclipse and IntelliJ have a Logcat plugin). What does it say?
I just did the same thing, ie, launch an activity from a menu button; and it worked fine. As for the resolving of the variable with the same name as the class, i'm not so sure of. The declaration may work fine, but further references to that variable won't be accurate is my guess. Also, make sure all control paths in the onOptionsItemSelected function return a boolean value.
You're trying to pass a class into your startActivity method, not an Intent. You're declaring Intent Intent. You need to do Intent intent, or Intent myIntent, something like that. You can't have the same name for a variable as it's class, just as you can't do int int.
Android may be having difficulty starting your About class, e.g. an exception is being thrown in onCreate(). Looking at the stack trace in logcat may confirm this. Post the stack trace if its unclear to what is the root cause.
Just an observation but your switch statement should break and have a default case. it will help prevent errors in the future and possibly help with this issue. Other than that, post logs...
Maybe this fix the problem. I paste a example part below. Because, I think you forgot to made a new/second activity in your AndroidManifest.
<application
android:allowBackup="true"
android:allowTaskReparenting="true"
android:hardwareAccelerated="true"
android:icon="#drawable/ic_launcher"
android:label="#string/app_name"
<activity
android:name="YourPackageName.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="YourPackageName.SecondActivity" />
<activity
android:name="YourPackageName.ThirdActivity" />**
</application>
I hope this is gonna help you!
ADDED Post:
And this is my code, must be work! Put it in your main or something else, but not in the activity from your button.
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// TODO Auto-generated method stub
switch (item.getItemId()) {
case R.id.MenuButton_About:
Toast.makeText(this, "YourPopupText.", Toast.LENGTH_SHORT).show();
startActivity(new Intent("Name of this activity".this, "Name of the menu button acivity".class));
break;
default:
break;
}
return super.onOptionsItemSelected(item);
}
}
You can also use: Toast.LENGTH_SHORT -> Toast.LENGTH_LONG
I hope this is gonna help you!
Check your About java activity file. I had a similar problem where the project would compile OK but the app would force a shutdown when the menu button was selected. When I rewrote the second activity everything was fine!

Categories

Resources