Passing current Intent as extra to another Activity - android

I have a problem with my Login screen. When it's started, I check for network connection, and if it's disabled, I want to show NoNetworkActivity. And the same for every other screen: when Activity is launched, I check network connection and navigate to NoNetworkActivity is needed. When navigating, I want to save the Intent which launched this previous activity and finish it to disable the Back button redirection when on NoNetworkActivity. So, when connection is restored, I want to launch that intent and get actual state of the app before this error:
LoginActivity
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_login);
if (!App.getInstance().isNetworkConnected()) {
Intent noNetwork = new Intent(this, NoNetworkActivity.class);
noNetwork.putExtra(NoNetworkActivity.EXTRA_FAILED_INTENT, getIntent());
startActivity(noNetwork);
finish();
}
...
NoNetworkActivity
private void checkNetworkConnection() {
mCheckButton.setVisibility(View.INVISIBLE);
mProgressBar.setVisibility(View.VISIBLE);
if (App.getInstance().isNetworkConnected()) {
Intent failedIntent = getIntent().getParcelableExtra(EXTRA_FAILED_INTENT);
startActivity(failedIntent);
finish();
} else {
mCheckButton.setVisibility(View.VISIBLE);
mProgressBar.setVisibility(View.INVISIBLE);
App.toast("Connection failed");
}
}
And it's getting strange: startActivity(failedIntent) does NOTHING. I've tried to remove finish() from next line, and NoNetworkActivity just stays on top without anything happening.
And one more thing. You can suggest passing Activity actual class names instead of intents, but I realy need Intent. That's because I'm using a lot of starting actions for every activity and a bunch of extras.
Thanks in advance for any help. Cheers!

Very bad approach. Don't use it.
First, you don't need to finish previous activity just to disable Back action. You can override onBackPressed().
Second, you don't need to start parent activity again. Just call a new activity with startActivityForResult(); and override onActivityResult() callback.
Third, but most important. Why do you want to call a new activity just to show 'No Network' message? And what if network won't be re-established? Just create isNetworkEnabled() method and call it when user attempts to get data from the Internet, before sending actual request to server. If no network - notify a user with an alert or toast.

I suggest you use fragments instead of activities first of all.
Using fragments you can set retainInstance(true);
To disable coming back from an activity to the previous :
1)call finish() on that activity
2)
Intent i = new Intent();
i.setClass(this, MyActivity.class);
i.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
startActivity(i);`

It works with an explicit Intent.
In LoginActivity substitute:
noNetwork.putExtra(NoNetworkActivity.EXTRA_FAILED_INTENT, getIntent());
with:
noNetwork.putExtra(NoNetworkActivity.EXTRA_FAILED_INTENT, new Intent(this, LoginActivity.class));
Btw, Alexander Zhak has some good points in his answer

Related

Android how to start activity without intent or backround

Suppose I have two activities A and B activity A which contains a button I want to start Activity B when I press Button without intent.
According the Oficial Documentation:
An intent is an abstract description of an operation to be performed. It can be used with startActivity to launch an Activity, broadcastIntent to send it to any interested BroadcastReceiver components, and startService(Intent) or bindService(Intent, ServiceConnection, int) to communicate with a background Service.
An Intent provides a facility for performing late runtime binding between the code in different applications. Its most significant use is in the launching of activities, where it can be thought of as the glue between activities. It is basically a passive data structure holding an abstract description of an action to be performed.
So you have to use it to open activities with no exceptions or workarounds, if you do that, you are ignoring the entire system architecture.
There is no way to start an activity from anotherone without an intent.
If the reason of not using Intent that you don't want the the user to re-enter the previous activity
You can use finish() to finish that activity intent after you done work with
if(currentUser == null){
startActivity(new Intent(MainActivity.this,StartActivity.class));
finish();
}
So user will be unable to back again
If you want to do some code while the activity is finishing
You can use onDestroy() override method, Sometimes it can also be called if the activity is being killed by the android itself so you can add
isFinishing() function
Inside onDestroy() method which checks whether the application is closing by the call finish() returning true or otherwise by anything else returning false then you can easily specify your code for each situation.
#Override
protected void onDestroy() {
super.onDestroy();
if(isFinishing()){
// Activity is being destroyed by the function `finish()`
// What to do...
}else{
// Activity is being destroyed anonymously without `finish()`
// What to do...
}
}
Put your activity inside a Fragment and start the fragment fromo the button.
These are the possible ways to start any Activity
1st
startActivity(new Intent(Activity_A.this, Activity_B.class));
2nd
Intent intent = new Intent(Activity_A.this, Activity_B.class);
startActivity(intent);
3rd
Intent intent = new Intent(Activity_A.this, Activity_B.class);
startActivityForResult(intent,code);

How to prevent user being directed to loginActivity(MainActivity)from MainMenu

I wrote a messaging application which requires an XMPP connection. Everything is ok when user is changing pages inside the application. Everything is also ok when I send a notification to him and he clicks it to come back to my application. But when he tries to come back to my application from his "last applications" page my application redirects him to my login screen. And since he is connected he cannot login again, hence he is stuck in there. How can I redirect someone from his main menu to another screen other than login(I think it sends him to login because its my main activity.) With sending notifications I was easily able to specify the intent target. Here is what I tried in loginActivity.
protected void onRestart() {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
boolean loginStatus=prefs.getBoolean("xmpp_logged_in",true);
if (loginStatus) {
Intent intent = new Intent(this, ConversationActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(intent);
finish();
}
super.onRestart();
}
I have a solution but it is not a pretty one. My app follows this screens Login-Show Contacts- Message with a user.
So in Show Contacts I overwrited onBackPressed and made it same with home button. Here is the code
public void onBackPressed() {
Intent setIntent = new Intent(Intent.ACTION_MAIN);
setIntent.addCategory(Intent.CATEGORY_HOME);
setIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(setIntent);
}
I would recommend to put your code inside onResume() instead of onRestart() since it is more reassuring that the lines of codes here are called every time your app gets into foreground state.
Your code seems okay. Can you make sure that you called apply() or commit() to your Shared Preference transaction after successful login?
For instance,
prefs.edit().putBoolean("xmpp_logged_in", true).commit();

Refresh activity and re-open

This is my first post, so please be nice :)
I have a question and no one gave the answer in the post I've seen.
My app has a list and a button to open an activity, this activity creates a new item to show in the list of the previous activity when pressing the button Create.
How can I do this?
This is the code I made for the first button:
intent = new Intent(this.getBaseContext(), NewTestActivity.class);
this.finish();
startActivity(intent);
and this is the code to go back an refresh:
Intent intent = new Intent(getBaseContext(), TestListActivity.class);
startActivity(intent);
But the code to goback is useful, because the activity don't refresh.
I have to call the new activity in a diferent way? Or go back to previus activity in a diferent way? Or go back normally and refresh the activity when I'm back in the previus activity?
Well...this is all.
Sorry for my bad english and, if this question has been answered in another thread, give me the link to read, because I can't find it :)
PS: I started with android in December.
Thanks for your help.
When you are going to start new activity you shouldn't close a current one until you actually need this behaviour. (remove this.finish(); row from your code)
Also you shouldn't close an active activity manually until you actually need it. When the user presses the "back" button on the device Android pops the previous activity from the "back stack". Read once more Activity documentation.
According to your description you have a list of elements. So in order to refresh the list you need to update your dataset and notify the list about it by ListView.notifyDataSetChanged() method call.
Before getting to a real answer, I'd like to show some improvements to your code.
First, when creating an Intent (or when you need a context in general) from an Activity there is no need to call getBaseContext(), you can just use this:
intent = new Intent(this, NewTestActivity.class);
Second, android is good at handling Activities, you do not have to close your first activity manually with finish(). Android will automatically pause or stop your first activity and bring it back when you return to it.
Third, in your case you might want to use startActivityForResult() instead of startActivity() for reasons I will explain below.
This will make your code look like the following:
private static final int MY_REQUEST_CODE = 33487689; //put this at the top of your Activity-class, with any unique value.
intent = new Intent(this, NewTestActivity.class);
startActivityForResult(intent, MY_REQUEST_CODE);
Now, the startActivityForResult() starts an activity and waits for a result from that new Activity. When you call finsih() in the new Activity you will end up in the first Activitys onActivityResult()-method, with data supplied from the new Activty that is now closed:
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if(requestCode != MY_REQUEST_CODE) return; //We got a result from another request, so for this example we can return.
if(resultCode != RESULT_OK) return; //The user aborted the action, so we won't get any data.
//After the above if-statements we know that the activity that gives us a result was requested with the correct request code, and it's action was successful, we can begin extracting the data, which is in the data-intent:
Item item = (Item) data.getSerializableExtra("customData"); //casts the data object to the custom Item-class. This can be any class, as long as it is serializable. There are many other kinds of data that can be put into an intent, but for this example a serializable was used.
itemList.add(item); //This is the list that was specified in onCreate()
//If you use an Adapter, this is the place to call notifyDataSetChanged();
}
For this all to work, we need to do some things in the second Activity:
When the item has been created, we must set a result:
//We begin by packing our item in an Intent (the Item class is an example that is expected to implement Serializable)
Item theCreatedItem; //This is what was created in the activity
Intent data = new Intent();
data.putSerializable(theCreatedItem);
setResult(RESULT_OK, data);
finish();
This should return to the first Activitys onActivityResult()-method with the item, as explained above.

Notification to restore a task rather than a specific activity?

I have a foreground service that keeps a connection open with the server as long as the user is logged into the application. This is so that the connection is kept alive and can receive messages directly from the server even when the application has been sent into the background by the user pressing Home.
The application has a number of Activities, any of which could be the active one when it is sent into the background.
I would like to allow the user to click on the notification to restore the current Activity. I understand how to restore a particular activity, but wondered if there is a way to restore the last Activity that the user was on? Of course I could keep track of the the last one, and then call that from the Notification callback, but thought there might be a way at a task level?
Thanks for any advice you can offer.
What you need is just a simple Activity that does nothing. Here is an example:
public class NotificationActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Now finish, which will drop the user in to the activity that was at the top
// of the task stack
finish();
}
}
Set up your notification to start this activity. Make sure that in the manifest the task affinity of this activity is the same as the task affinity of the other activities in your application (by default it is, if you haven't explicitly set android:taskAffinity).
When the user selects this notification, if your application is running, then the NotificationActivity will be started on top of the topmost activity in your application's task and that task will be brought to the foreground. When the NotificationActivity finishes, it will simply return the user to the topmost activity in your application (ie: wherever the user left it when it went into the background).
This won't work if your application isn't already running. However, you have 2 options to deal with that:
Make sure the notification isn't present in the notification bar when your application is not running.
In the onCreate() method of the NotificationActivity, check if your application is running, and if it isn't running call startActivity() and launch your application. If you do this, be sure to set the flag Intent.FLAG_ACTIVITY_NEW_TASK when starting the application so that the root activity of the task is not NotificationActivity.
Works very well, thanks David! The following class checks if the application is already running and if not, starts it before finishing (as suggested by David in option 2).
public class NotificationActivity extends Activity
{
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
// If this activity is the root activity of the task, the app is not running
if (isTaskRoot())
{
// Start the app before finishing
Intent startAppIntent = new Intent(getApplicationContext(), MainActivity.class);
startAppIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(startAppIntent);
}
finish();
}
}
There is a simpler solution that does not require the extra activity. See this post for details. Basically, the notification starts the (possibly existing) task the same way it is started when you click the launcher icon while the app ist in the background.
My solution, which emulates the behaviour of the launcher (bringing up the task to the foreground):
Intent intent = new Intent(Intent.ACTION_MAIN);
intent.addCategory(Intent.CATEGORY_LAUNCHER);
intent.setClassName(MyApplication.class.getPackage().getName(), MainActivity.class.getName());
Intent intent = new Intent(Intent.ACTION_MAIN);
intent.addCategory(Intent.CATEGORY_LAUNCHER);
This works, no doubts about it but the problem is when you set your intent as ACTION_MAIN. Then you will not be able to set any bundle to the intent. I mean, your primitive data will not be received from the target activity because ACTION_MAIN can not contain any extra data.
Instead of this, you can just set your activities as singleTask and call your intent normally without setting ACTION_MAIN and receive the intent from onNewIntent() method of your target activity.
But be aware if you call, super.onNewIntent(intent); then a second instance of the activity will be created. Just don't call super method.
I combined David Wasser's and Raginmari's solution by doing that approach to the root activity of your app then it will work for both cases when your app was already started or haven't been started.
public class YourRootActivity extends Activity
{
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
if (!isTaskRoot()) // checks if this root activity is at root, if not, we presented it from notification and we are resuming the app from previous open state
{
val extras = intent.extras // do stuffs with extras.
finish();
return;
}
// OtherWise start the app as usual
}
}

Android - Opening a webpage and back to Activity?

Let's say I am on an Activity, user clicks a button, and I navigate to a web page.
Intent i = new Intent(Intent.ACTION_VIEW);
i.setData(Uri.parse("SOME_URL"));
startActivity(i);
it takes me to the web page, and then when I click back to goes to my activity, but it starts it all over again.
So is it possible to do this in a way so that after clicking the back button, it takes me to my activity, but instead of onCreate it call onRestart.
The goal is not going through onCreate again.
That is the normal life cycle of an Activity... you could save the state of the activity and restore it to get the "same" as before.
The main question should be: Why do you not want to go through onCreate? If it goes through it because it was destroyed before and need to be recreated. So not going through it will cause a lot of trouble.
You could set an intent in your activity (setIntent) before calling the web browser, then in your onCreate method, check for if this intent called you back (check the intent name or an extra) and if so, skip the rest of onCreate.
Before calling web browser :
Intent intentForThis = new Intent( "AfterWebBroswer" );
this.setIntent( intentForThis );
Intent i = new Intent(Intent.ACTION_VIEW);
i.setData(Uri.parse("SOME_URL"));
startActivity(i);
And then in your onCreateMethod
public void onCreate( Bundle b ) {
if( !getIntent().getAction().equals("AfterWebBrowser") ) {
//rest of onCreate
}//if
}//met
Regards,
Stéphane

Categories

Resources