How to wait before another method is called with RxJava - java

For example I am starting a activity which finishes and returns a result, which is returned by the method onActivityResult. How can I wait before the result is provided by the onActivityResult and then continue my reactive stream?
public class TestActivity extends AppCompatActivity {
...
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
// receiving result here
}
private Single<Data> loadData() {
return Remote.getInstance().getData()
.flatMap(data -> {
// do something
Intent intent = new Intent(TestActivity.this, OtherActivity.class);
startActivityForResult(intent, 0);
}) // how can I receive the result from the onActivityResult here?
}
}

It would be possible for example by using a PublishSubject that would notify in onActivityResult() and to which you'd flatMap() to in your original call, but I'd strongly advice against this. Here is why:
When your Activity receives an onActivityResult(), it might have been just recreated from scratch, because of a configuration change, memory pressure or anything else that happened in the meantime. This means that your Single subscription is either no longer active (if you properly unsubscribed from it onDestroy() or better in onStop()) or leaked the previous activity instance to what it is still attached to (in case you did not unsubscribe).
So, instead the stream (and the aforementioned PublishSubject) should probably live inside a component that survives activity recreation, like a retained fragment and you should call into that in onActivityResult() to notify your stream about the results. Here is some example how retained fragments and RxJava can work together.

Related

After calling zxing scanner, I go back to my activity but in a new instance

I use the library zxing-android-embedded in my Android App. Before calling initiateScan() method to start the scanner from my activity, I set a class variable scanedItemId to know on which item I clicked to scan.
My issue is that when the scanner activity finished, it goes back to my activity, but in a new instance and not the initial one (I checked with a break point in the onCreate method). So, my class variable is null. What can I do to keep my initial activity instance live and be sure the scanner goes back to it?
public class MyActivity
[...]
scanedItemId = currentItem.id // The current item where we clicked on.
IntentIntegrator qrCodeScanner = new IntentIntegrator(this);
qrCodeScanner.setOrientationLocked(false);
qrCodeScanner.initiateScan();
[...]
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
switch (requestCode) {
case IntentIntegrator.REQUEST_CODE:
// Here the scanedItemId is always null.
[...]
```
You asked:
What can I do to keep my initial activity instance live and be sure
the scanner goes back to it?
You can't. When your app goes to the background and the scanner app needs resources, Android will kill your app to make the resources available to the scanner app. This is normal and your app needs to be made robust enough to deal with this. If you need to keep track of your app's state so that you can continue when your app returns to the foreground, then you need to save that information somewhere persistent. You have choices:
SharedPreferences
SQLite database
Use a file
Implement onSaveInstanceState()
Following what #David said, I implemented the "onSaveInstanceState()" solution which works fine: I just added this in my activity:
#Override
public void onSaveInstanceState(Bundle savedInstanceState) {
super.onSaveInstanceState(savedInstanceState);
savedInstanceState.putInt("scanedItemIdKey", scanedItemId);
}
#Override
public void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
scanedItemId = savedInstanceState.getInt("scanedItemIdKey");
}
Thanks

How to manage onBackPressed from settings activity?

I am calling Settings activity from another activity using the startActivityForResult method. When the back button is clicked, it goes back to the screen on my application. But this activity had already been loaded before calling the settings activity, so I want to be able to refresh the activity on back click on the settings activity. How do I do that?
You will want to implement the onActivityResult() method in your first activity. This method will be called any time an activity you've started with startActivityForResult() finishes.
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == yourRequestCode) {
// your code here
}
}
In the case of the BACK button, the resultCode argument will be Activity.RESULT_CANCELED. This doesn't really change things, but lots of examples will include checking for resultCode == Activity.RESULT_OK and I just wanted to mention that it's perfectly fine to do things even when the result code is something else.
Just use
#Override
public void onResume(){
super.onResume();
// your code...
}
In the method implement what has to be needed to be updated.

Android - onCreate()

Is there a way to access to variables on onCreate(), to reuse them in another class?
String testSubCa="";
String prixe="";
String testWiifi="";
Double testPrice=0.0;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_srdata);
testSubCa = getIntent().getStringExtra(SearchRestau.txxtSub);
prixe = getIntent().getStringExtra(SearchRestau.txtprix);
testWiifi = getIntent().getStringExtra(SearchRestau.txxtWifi);
testPrice=Double.parseDouble(prixe);
refresh = (ImageButton) findViewById(R.id.imgRefresh);
refresh.setOnClickListener(this);
}
I need to use these data :/
Since you didn't really specify what exactly your plan is, it's a bit of a challenge getting a proper solution.
I'm just going to assume what you want to do is to start an activity, let the user do something inside this activity and then go back to where it was started from with the ability to use the values created inside the activity.
The easiest way to that is by not starting the activity via startActivity(Intent) but rather by using startActivityForResult(Intent, RequestCode);
In the same activity you then need to handle the event of actually getting a result. To do this you need to implement the method
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data)
{
if (resultCode == RESULT_OK)
{
//Your code to retrieve the data here!
}
}
The variables should be stored inside the Intent data and can be grabbed by using
data.getStringExtra();
To place the values inside the result you need to place this code in the activity you actually create them:
Intent intent = new Intent();
intent.putExtra("value_id", value);
setResult(RESULT_OK, intent);
finish();
I hope that helps with your problem!
GL

Returning string from Android Activity started with `startActivityForResult` inside `onClickListener` returns null

I use an Intent in MainActivity to start another Activity called MatchesActivity using startActivityForResult. I put breakpoints at finish() inside the started activity (MatchesActivity) and on the Log statement inside onActivityResult because I got NPE inside onActivityResult.
intent.getStringExtra("TXAMATCHES") contains what it should.
But Intent data comes back null.
Is this likely/possibly because I start the Intent inside an onClick listener?
Or because MatchesActivity calls a method in another class that extends AsyncTask and the data is what that task produces? (But the correct data is found in txaMatches just before it is returned to MainActivity...)
public class MainActivity extends Activity
{
...
btnSearch.setOnClickListener(new View.OnClickListener() {
#Override public void onClick(View v)
{
...
Intent matchesIntent;
matchesIntent = new Intent(MainActivity.this, MatchesActivity.class);
startActivityForResult(matchesIntent, 0);
...
}
...
#Override protected void onActivityResult(int requestCode, int resultCode, Intent data)
{
Log.w("MainActivity","" + onActivityResult " + data.getStringExtra("TXAMATCHES"));
}
}
...
public class MatchesActivity extends Activity implements DatabaseConnector.DatabaseProcessListener
{
...
#Override protected void onDestroy()
{
super.onDestroy();
finishThisAndReturnString();
}
public void finishThisAndReturnString()
{
Intent intent = new Intent();
intent.putExtra("TXAMATCHES",txaMatches.getText().toString());
setResult(RESULT_OK, intent);
finish();
}
(The started Activity is terminated by user pressing back icon.)
You can't finish a activity in the onDestroy method. In this lifecycle phase the activity is already dying.
The call of the finish() method will call the onDestroy, not the other.
Call the finish method when you want to to finish the MatchesActivity.
What you're trying to do is not correct. You're trying to call finish() on the onDestroy() method. onDestroy() gets called when the Activity is about to be killed. So basically calling finish() at that point is wrong.
I assume that you are trying to do some processing in the AsyncTask. I suggest that you call the finish() method on the onPostExecute() method of the AsyncTask.
You are setting the data in the Intent object in onDestroy() method . So in this case, whenever you call setResult() in onDestroy() method, you will always get resultCode in onActivityResult() as '0' which is the value for RESULT_CANCELED and whenever you get RESULT_CANCELED in onActivityResult() you get data object null. That's why you don't get the values you set in Intent .
First try to get the value of
txaMatches.getText().toString()
Check this value in the MatchesActivity Class.
It is possible that it is returning null value due to which u are getting the problem.
The problem is fixed by removing finishThisAndReturnString() from onDestroy, as stated in the first two Answers.

Activity on users click in Bluetooth discoverability dialog

I am quite new to Java and would appreciate if someone could explain show me
how can I implement startActivityForResult(Intent, int) and
onActivityResult() in Bluetooth discoverability stated
here.
What I want to achieve is: on button Enable BTDisco click
(if(bttn.getId() == R.id.bt_disco) my program calls
BTDiscoverable() method:
public void BTDiscoverable() {
Intent discoverableIntent = new
Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
discoverableIntent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION,
BT_ENABLE_TIME);
startActivityForResult(discoverableIntent, REQUEST_ENABLE_BT);
}
Now, the dialog pops up. If user clicks no, the program should not
continue. If user click yes, Enable BTDisco button should become
unavailable and another button, lets call it Start, becomes available. I
wrote onActivityResult which would make Start button available but I
doubt it is done right. Snippet here:
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent
data)
{
if (requestCode == REQUEST_ENABLE_BT)
{
if(resultCode == RESULT_OK)
{
((Button) findViewById(R.id.bt_server_start)).setEnabled(true);
BTCountDown = new BTTimer(BT_TIME_BTTIME,BT_TIME_BTTIME);
BTCountDown.start();
}
}
}
startActivityForResult is called in BTDiscoverable method but it does
not provide what I wanted. I have followed this but as I am quite
new here, I have no idea how to implement this in such problem as mine.
The onActivityResult method is implemented class that extends Activity.
There are no errors while compiling. Long story, short: R.id.bt_server_start stays disabled as initially programmed.
Could really use some help.
Just put this
if(resultCode != RESULT_CANCELED)
Documentation says the following
Your activity will then receive a call to the onActivityResult()) callback, with the result code equal to the duration that the device is discoverable. If the user responded "No" or if an error occurred, the result code will be RESULT_CANCELED.
So if result code is not RESULT_CANCELED, then you are okay to enable your button.

Categories