I have an android app. When the user clicks button A and intent is fired like this android-presudocode :)
//inside FirstActivity
#Override
public void onClick(View view) {
startActivity(new Intent(this, AnotherActivity.class));
}
So if I'm not mistaken, the onResume method in AnotherActivity should be called, right?
I use ActivityInstrumentationTestCase2<FirstActivity> to test my activity but I'm unable to instantiate AnotherActivity.
So the question is, how can I test this: 'When a button is pressed, the correct activity is resumed and the correct extras are passed to the intent'.
You can use the instrumentation to make an ActivityMonitor. This will monitor if a new activity has been started.
ActivityMonitor am = getInstrumentation().addMonitor(Activity3.class.getName(), null, true;
Then you want to use button.performClick() to "press the button". Finally, you check if the activity monitor has been hit.
am.waitForActivitywithTimeout(timeout);
assertEquals(1, am.getHits());
I haven't used ActivityInstrumentationTestCase2 in quite a while so I don't guarantee these steps are exactly right. In any case, I recommend that you take a look at Robolectric: a wonderful unit testing framework for Android that will change your life. It will help you overcome many situations that are difficult or impossible to test with any of the default instrumentation tests.
So after some time I want to post the solution that I use almost always.
Initially I liked #aleph_null's solution but it turns out that it makes tests unbearably slow so this is what I use now:
First, I have this interface
/**
* Simple interface to launch other activities.
*/
public interface ActivityLauncher {
/**
* Starts an activity with the Intent provided.
* #param intent an intent
*/
public void start(Context context, Intent intent);
/**
*
* Returns the intent as set by {#link #start(android.content.Context, android.content.Intent) start} or null if not yet
* called.
*
* #return an intent or null
*/
public Intent getIntent();
}
And I have two implementations for it:
/**
* Default implementation of ActivityLauncher
*/
public class DefaultActivityLauncher implements ActivityLauncher{
private Intent intent;
public DefaultActivityLauncher(){}
#Override
public void start(Context context, Intent intent) {
this.intent = intent;
context.startActivity(intent);
}
#Override
public Intent getIntent() {
return intent;
}
}
and
/**
* Mock implementation of ActivityLauncher that simply sets the intent but does not actually starts
* an activity.
*/
public class MockActivityLauncher implements ActivityLauncher {
private Intent intent;
#Override
public void start(Context context, Intent intent) {
this.intent = intent;
}
#Override
public Intent getIntent() {
return intent;
}
}
Then I use a dependency injection framework like Dagger or similar like this:
public class MyActivity {
#Inject ActivityLauncher launcher;
public void onCreate(Bundle bundle){
// some code omitted for brevity
findViewById(R.id.goToOtherActivityButton).setOnClick(new OnClickListener(){
Intent intent = new Intent(getContext(), MyOtherActivity.class);
launcher.start(getContext(), intent);
});
}
public ActivityLauncher getLauncher(){
return launcher;
}
}
Testing is then as simple as checkIntentIsValid(activity.geLauncher().getIntent())
This code might give you a good idea
If you are calling Activity1 --- > Activity2
You can send the UserName by this method
Intent intent = new Intent(getBaseContext(), Activity2.class);
intent.putExtra("UserName ", UserName );
startActivity(intent);
To retrive the Extra() in Activity2, you need this code
String UserName = (String) getIntent().getSerializableExtra("UserName ");
Hope this helps
Below Edit for Better Understanding
public class Activity2 extends Activity {
private String UserName;
#Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
setContentView(R.layout.activity_2);
UserName= (String) getIntent().getSerializableExtra("UserName");
Log.i(Tag, "UserName: "+ UserName);
}
// you can call this method from click or where ever you want
private void AnyMethod()
{
Intent intent = new Intent(getBaseContext(), Activity3.class);
intent.putExtra("UserName ", UserName );
startActivity(intent);
}
}
#Override
public void onClick(View view) {
startActivity(new Intent(this, AnotherActivity.class));
}
Your code is not correct in every time.
Example:
btn.setOnClickListener(new OnClickListener(
#Override
public void onClick(View view) {
startActivity(new Intent(this, AnotherActivity.class));
}
));
Please replace this = CurrentActivity.this
It looks like:
#Override
public void onClick(View view) {
startActivity(new Intent(CurrentActivity.this, AnotherActivity.class));
}
Make ensure, your Manifest has this code:
<Activity name=".AnotherActivity">
</Activity>
Related
I am working on an online radio app demo. I've created an error Activity which I want to take the user to, when an error occurs. In the error page, there is a refresh button, which is supposed to refresh the last Activity where an error occurred. But I don't know how to get the Intent of previous Activity which led to the error page to get it refresh on ButtonClick, I only know to make it return to a particular Activity.
You can use startActivityForResult in both calling activities
In MainActivity.java
int REFRESH = 1;
private void startErrorActivity() {
startActivityForResult(new Intent(this, ErrorActivity.class), REFRESH);
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == REFRESH) {
//do refresh
}
}
And in ErrorActivity.java
Button button = findViewById(R.id.refreshButton);
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
finish(); //this will take you back to calling activities onActivityResult method
}
});
UPDATE:
I honestly think #sneharc's answer is better. Use that.
Try this:
public class ActivityA extends Activity {
public void myFunction(){
try{
// something bad happens here. need to go to ErrorActivity
}
catch (SomeException e){
Intent startErrorActivityIntent = new Intent(this, ErrorActivity.class);
startErrorActivityIntent.putExtra("sourceActivity", ActivityA.class.getSimpleName())
startActivity(this, startErrorActivityIntent)
}
}
}
public class ActivityB extends Activity {
public void myFunction(){
try{
// something bad happens here. need to go to ErrorActivity
}
catch (SomeException e){
Intent startErrorActivityIntent = new Intent(this, ErrorActivity.class);
startErrorActivityIntent.putExtra("sourceActivity", ActivityB.class.getSimpleName())
startActivity(this, startErrorActivityIntent)
}
}
}
public class ErrorActivity extends Activity {
private Intent mReceivedIntent;
#Override
protected void onCreate(Bundle savedInstanceState) {
mReceivedIntent = getIntent();
}
public void onClickRefresh(){
String retryActivityName = mReceivedIntent.getStringExtra("sourceActivity");
Intent retryActivityIntent = null;
if (!TextUtils.isEmpty(retryActivityName)){}
if (retryActivityName.equalsIgnoreCase(ActivityA.class.getSimpleName()))
retryActivityName = new Intent(this, ActivityA.class);
if (retryActivityName.equalsIgnoreCase(ActivityB.class.getSimpleName()))
retryActivityName = new Intent(this, ActivityB.class);
}
if (retryActivityIntent != null)
startActivityForResult(this, retryActivityIntent);
}
}
I've got a class which handles a question sequence. It doesn't extend Activity. In the class there is the method:
public class QuizMaster {
public void startQuiz(Activity activity, Model model) {
//switch - case statement using model
Intent intent = new Intent(activity, QuestionTextActivity.class)
activity.startActivityForResult(intent, requestCode);
//other case statements with other intents
}
}
When I call this method from a working activity with
mQuizMaster.startQuiz(this, mModel);
And I finish() the child activity:
Intent returnIntent = new Intent();
returnIntent.putExtra(ARG_SELECTED_CHECKBOX, checkedBox);
setResult(RESULT_CODE, returnIntent);
finish();
it doesn't execute the parent activity's
#Override
protected void onActivityResult(final int requestCode, final int resultCode, final Intent data) {
Log.d(LOG_TAG, "OnActivityResult called in SignDetailsActivity. Resultcode is: ");
}
But when I execute the
Intent intent = new Intent(activity, QuestionTextActivity.class)
activity.startActivityForResult(intent, requestCode);
in the actual parent activity file, it does execute the onActivityResult method.
Why doesn't the child activity run the onActivityResult in the parent activity if sent with a non-activity class? How do i fix this?
I haven't found anyone with the same problem with executing new Intent() in a non-activity class like this. If there is someone, i didn't use the right search keywords and some others might type in the same as I did and come on this page.
You need to call setResult(int) before call finish(). This is from Activity documentation:
When an activity exits, it can call setResult(int) to return data back
to its parent. It must always supply a result code, which can be the
standard results RESULT_CANCELED, RESULT_OK, or any custom values
starting at RESULT_FIRST_USER. In addition, it can optionally return
back an Intent containing any additional data it wants. All of this
information appears back on the parent's Activity.onActivityResult(),
along with the integer identifier it originally supplied.
Here is my implementation, which worked:
MainActivity.java (parent activity)
public class MainActivity extends AppCompatActivity {
private Sample sample;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button btn = (Button) findViewById(R.id.button);
btn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
sample = new Sample();
sample.startActivity(MainActivity.this);
}
});
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
Log.d("TEST", "DONE");
}
}
LaunchActivity.java (child activity)
public class LaunchActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_launch);
Button btn = (Button) findViewById(R.id.button2);
btn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
setIntent(new Intent());
finish();
}
});
}
}
Sample.java (class start activity)
public class Sample {
public Sample () {}
public void startActivity (Activity a) {
Intent it = new Intent(a, LaunchActivity.class);
a.startActivityForResult(it, 0);
}
}
I've read many answers on the same question but still I do not understand why my code doesn't work properly. I have a problem with (as I think) exchanging data between two activities.
I have 2 activities - the first contains ListView and an Add button.
When user presses Add new activity starts with the form to fill. When user completes the form he/she presses OK and my first activity starts again (it really does) and it should contain new item (but it doesn't).
This is my first activity:
public class DatabaseActivity extends Activity implements OnClickListener {
ArrayList<Student> students;
StudentDatabaseAdapter adapter;
ListView lvStudentList;
ImageButton imgBtnAdd;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.database);
students = new ArrayList<Student>();
fillArrayList();
adapter = new StudentDatabaseAdapter(this, students);
lvStudentList = (ListView)findViewById(R.id.lvStudentsList);
lvStudentList.setAdapter(adapter);
imgBtnAdd = (ImageButton)findViewById(R.id.imagBtnAddStudent);
imgBtnAdd.setOnClickListener(this);
}
public void fillArrayList() {
//code here
}
#Override
public void onClick(View v) {
Intent intent;
intent = new Intent(this, WizardActivity.class);
startActivity(intent);
}
public void addStudent(Student student) {
students.add(student);
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
super.onActivityResult(requestCode, resultCode, intent);
if(resultCode==RESULT_OK)
{
if(requestCode==2)
{
if (intent == null) {return;}
Student newStudent = new Student(intent.getStringExtra("name"), intent.getStringExtra("surname"),
intent.getStringExtra("last_name"), Integer.parseInt(intent.getStringExtra("year_of_birth")), R.drawable.default_ava);
addStudent(newStudent);
adapter.notifyDataSetChanged();
}
}
}
}
And that's my second activity:
public class WizardActivity extends Activity implements OnClickListener {
EditText etName, etSurname, etLastName, etYearOfBirth;
ImageButton imgBtnOK;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.wizard);
etName = (EditText)findViewById(R.id.etName);
//initializing other edit texts
imgBtnOK = (ImageButton)findViewById(R.id.imgBtnOK);
imgBtnOK.setOnClickListener(this);
}
#Override
public void onClick(View v) {
Intent intent = new Intent(this, DatabaseActivity.class);
intent.putExtra("name", etName.getText().toString());
intent.putExtra("surname", etSurname.getText().toString());
intent.putExtra("last_name", etLastName.getText().toString());
intent.putExtra("year_of_birth", etYearOfBirth.getText().toString());
setResult(RESULT_OK, intent);
startActivityForResult(intent, 2);
}
}
There is nothing wrong with your notifyDataSetChanged(). You seem to be missing the way a secondary activity communicates results back to its caller activity.
DatabaseActivity.onClick() should call startActivityForResult() instead of startActivity().
WizardActivity.onClick() should just call finish() after setResult() (remove the startActivityForResult() call, it doesn't make sense there). Also notice that the intent you provide to setResult() can be an empty intent, i.e. Intent intent = new Intent();
After the secondary activity finishes, DatabaseActivity will be back to foreground and the result will be processed by DatabaseActivity.onActivityResult().
I think you haven't to start new activity in WizardActivity
try this :
WizardActivity
......
#Override
public void onClick(View v) {
Intent intent = new Intent(this, DatabaseActivity.class);
intent.putExtra("name", etName.getText().toString());
intent.putExtra("surname", etSurname.getText().toString());
intent.putExtra("last_name", etLastName.getText().toString());
intent.putExtra("year_of_birth", etYearOfBirth.getText().toString());
setResult(RESULT_OK, intent);
finish();
}
and in
DatabaseActivity
add if you want
#Override
protected void onResume (){
......
adapter.notifyDataSetChanged();
}
I'm new to Android and I'm stuck on a conception problem.
I have an application with several activities, some of those activities are critical and require the user to be logged in a webApp.
When the user clicks a button to reach one of those critical activities, I call a background Service which ask if the user is still connected to the webApp (not timeout). If the user is logged in, the activity is started, otherwise a dialog pops up and ask for username and password. The problem is that there is several protected activities, and I want to use the same service to do the verification. The way I do it for the moment works but it's kind of kludgy.
public class A_Activity extends Activity {
Context context;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
context = getApplicationContext();
setButtonClickListener();
}
private void setButtonClickListener() {
button_1 = (Button)findViewById(R.id.button1);
button_1.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
Intent intentCall = new Intent(context,com.them.cp.ConnexionManagerService.class);
intentCall.putExtra("WHO_IS_CALLED","FIRST_ACTIVITY");
context.startService(intentCall);
}
});
button_2 = (Button)findViewById(R.id.button2);
button_2.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
Intent intentCall = new Intent(context,com.them.cp.ConnexionManagerService.class);
intentCall.putExtra("WHO_IS_CALLED","SECOND_ACTIVITY");
context.startService(intentCall);
}
});
}
}
And my service
public class ConnexionManagerService extends Service{
public class IsConnectedAsync extends AsyncTask<String , Void, Void>{
protected Void doInBackground(String... whoIsCalled) {
String redirectedURL = getRedirectedURL();
if(redirectedURL.equalsIgnoreCase(IF_NOT_CONNECTED_URL)){
if(whoIsCalled[0].equalsIgnoreCase("FIRST_ACTIVITY")){
Intent trueIntent = new Intent(getBaseContext(), FirstActivity.class);
trueIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
getApplication().startActivity(trueIntent);
}
else if(whoIsCalled[0].equalsIgnoreCase("SECOND_ACTIVITY")){
Intent trueIntent = new Intent(getBaseContext(), SecondActivity.class);
trueIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
getApplication().startActivity(trueIntent);
}
}
else{
Intent falseIntent = new Intent(getBaseContext(), PopUpLoginActivity.class);
falseIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
getApplication().startActivity(falseIntent);
}
}
return null;
}
}
#Override
public void onCreate() {
Toast.makeText(this, "My Service Created", Toast.LENGTH_LONG).show();
Log.d("service onCreate", "onCreate");
}
public int onStartCommand(Intent intent, int flags, int startId){
String whoIsCalled = intent.getStringExtra("WHO_IS_CALLED");
new IsConnectedAsync().execute(whoIsCalled);
return START_STICKY;
}
#Override
public IBinder onBind(Intent intent) {
return null;
}
}
with my little knowledge I wish i could just send an intent, but it seems that it's not possible as it's not the UI thread.
My question is: What can I do to make this service more generic ?
I want to use the same service to do the verification.
If you don't destroy the service it will be the same service object. If an activity which started your service finishes or stops the service it could be destroyed if it was the unique activity that started the service. If you want to ensure that the service reminds on background start it on you application class (extending Application) and in each activity you need. When an activity stops the service or finishes the service will not be destroyed because your application class is still connected.
EDIT:
To avoid write putExtra again and again:
public class StartOrder1 extends Intent {
public StartOrder(Context ctx, String activity_name){
super(ctx, ServiceName.class);
if(activity_name != null)
super.putExtra("WHO", activity_name);
else
super.putExtra("WHO", "UNKNOWN");
}
public String getWho(){
reurn.getIntExtra("WHO");
}
}
To start it:
this.startService(new StartOrder1(this, "My activity name"));
The best solution:
public class StartOrder2 extends Intent {
public StartOrder(Activity a){
super(a, ServiceName.class);
super.putExtra("WHO", a.toString());
}
public String getWho(){
reurn.getIntExtra("WHO");
}
}
And you can override toString method in each Activity passing the activity name, class name, whatever you want. Then when you start an intent:
this.startService(new StartOrder2(this));
Or extends Activity with this utility:
public class EnhancedActivity extends Activity{
protected startMyService(String name){
Intent i = new Intent(this, MyService.class);
i.putExtra("who", name);
startService(i);
}
}
And call it on your final activity
[...]
super.startMyService("activity_name");
[...]
Consider i am using five screen pages for project "A".Each page is having switching between other pages sequentially one by one,my need is to do close all the page when i am clicking the button "exit" from the page five which is the last one.
I have used this below code,but the problem is only the last page is getting close others are not.
find my code below
Button extbtn = (Button)findViewById(R.id.but_Exit);
extbtn.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
Intent intent = new Intent();
setResult(RESULT_OK, intent);
finish();
} });
Thanks for your time!
Make all five activities extend a BaseActivity that registers a BroadcastReceiver at onCreate (and unregisters at onDestroy).
When extbtn is clicked, send a broadcast to all those BaseActivities to close themselves
for example, in your BaseActivity add:
public static final String ACTION_KILL_COMMAND = "ACTION_KILL_COMMAND";
public static final String ACTION_KILL_DATATYPE = "content://ACTION_KILL_DATATYPE";
private KillReceiver mKillReceiver;
#Override
protected void onCreate(Bundle savedInstanceState) {
...
...
mKillReceiver = new KillReceiver();
registerReceiver(mKillReceiver, IntentFilter.create(ACTION_KILL_COMMAND, ACTION_KILL_DATATYPE));
}
#Override
protected void onDestroy() {
super.onDestroy();
unregisterReceiver(mKillReceiver);
}
private final class KillReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
finish();
}
}
and at extbtn's onClick call:
extbtn.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
// send a broadcast that will finish activities at the bottom of the stack
Intent killIntent = new Intent(BaseActivity.ACTION_KILL_COMMAND);
killIntent.setType(BaseActivity.ACTION_KILL_DATATYPE);
sendBroadcast(killIntent);
Intent intent = new Intent();
setResult(RESULT_OK, intent);
finish();
}
});