Interact between apps in Android - java

I'm developing two android applications let's call them app A and app B.
App A opens app B through and Share Intent and pass it params through a bundle, until this point it's ok, works.
Now, I want to realize some operations in app B and once these have finished close app B and return a message that operations has finished and the result of these operations to app A but I don't know how to solve it or how looking for.
I have thought another intent but it will reopen my app and delete the content of my screen that I have previously. Any suggestion?

Try to use ResultReceiver:
https://developer.android.com/reference/android/os/ResultReceiver.html
Or Messenger:
https://developer.android.com/reference/android/os/Messenger.html
I worked with ResultReceiver only, when developed SDK for one application. In first app you create an instance of ResultReceiver:
public ResultReceiver generateParcelableReceiver(ResultReceiver actualReceiver) {
Parcel parcel = Parcel.obtain();
actualReceiver.writeToParcel(parcel, 0);
parcel.setDataPosition(0);
ResultReceiver receiverForSending = ResultReceiver.CREATOR.createFromParcel(parcel);
parcel.recycle();
return receiverForSending;
}
and then pass it as an extra parameter to Intent:
requestLogin.putExtra("EXTRA_TARGET_RECEIVER", mAndroidUtils.generateParcelableReceiver(emptyReceiver));
Where emptyReceiver is:
ResultReceiver emptyReceiver = new ResultReceiver(null) {
#Override
protected void onReceiveResult(int resultCode, Bundle resultData) {
//do nothing
}
};
As you can see, it receives Bundle. And in your second application, retrive the receiver, and pass the result when needed.
NOTE
Please, make sure you use android.support.v4.os.ResultReceiver, because there is another implementation of it(with different package name), and it doesn't work very well. This implementation contains in:
compile 'com.android.support:appcompat-v7:23.1.1'

Related

How do I track if activity has ended Android Studio

I have an activity to add an object to a database in my application, and the database is displayed in activity which calls an AddActivity. My problem is I need to refresh ArrayList after i update a database, but i can't have access to it inside my AddActivity. So i wanted to track in MainActivity when the AddActivity has ended and then call the refreshing function. For now i tried using code below and this is working, but i don't think this is the way i should do it, I feel like there is better function for that but I couldn't find it.
Code in MainActivity inside onClickListener:
Intent intent = new Intent(mContext, ExerciseAdd.class);
startActivityForResult(intent, 1);
Code in AddActivity also inside onClickListener:
dataBaseAccess = ExercisesDataBaseAccess.getInstance(getApplicationContext());
dataBaseAccess.open();
dataBaseAccess.addExercise(nameString, typeString, "NULL");
dataBaseAccess.close();
Intent intent = new Intent();
intent.putExtra("result", 1);
setResult(1, intent);
finish();
And refhresing function in MainActivity:
#Override
public void onActivityResult(int requestCode, int resultCode, #Nullable Intent data)
{
super.onActivityResult(requestCode, resultCode, data);
dataBaseAccess.open();
exercises = dataBaseAccess.getAllExercises();
dataBaseAccess.close();
adapter.setExercises(exercises);
adapter.notifyDataSetChanged();
}
Or maybe is there any way to pass an reference to ArrayList to AddActivity? it was hard to me to find any information about this
The way you are doing it is the most robust and clean way. You are storing your data in the database and you have one Activity that adds items to the database and another Activity that reads the data from the database and displays it. This may seem like overkill, but this architecture is more robust than sharing data in memory between activities.
Of course, it is possible to share data in memory between activities. You can store a reference to your ArrayList<Exercise> in a public static variable and it can be accessed by both activities. This is a simple way to share data but can be tricky if your app goes to the background and Andriod kills off the OS process hosting the app and then the user returns to the app. If he was last using the AddActivity, when he returns to the app, Android will create a new OS process to host the app and instantiate the AddActivity, but MainActivity is not yet instantiated and your shared public static data will be gone. So this approach is error-prone.
Another approach would be to use Live Data. This is a more complicated approach to sharing data in memory between activities. You can read more about live data here: https://developer.android.com/topic/libraries/architecture/livedata

Deprecated method "startActivityForResult()" vs properly bluetooth set up

Hey I try to make bluetooth service according to the information on the official android dev website. But I came across to the deprecate method startActivityForResult(). What should I do to properly turn on bluetooth device?
Here is my code with deprecated method:
private void enableBt(View view){
if(myBluetoothAdapter==null){
//we don't have bt in this device
}
else if(!myBluetoothAdapter.isEnabled()){
Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
}
}
It’s a special AndroidX extension that wraps the startActivityForResult and provide sort of a simpler method.
According to Android Developers, you need to extend ActivityResultContract, in which you implement an input/output for the activity result call by overriding 2 methods:
Method for creating intent based on the input.
Method for parsing an output based on the activity result.
In your case you don’t have an input so you can use Void type for the input (don’t know about your output though).
After properly implementing that contract class, you simply create an instance from that class and pass it to registerForActivityResult(…) (before your activity is started), which returns some sort of a launcher.
You use that launcher and call launch instead of startActivityForResult.
Enjoy :)

Android - app goes to launcher after calling CAPTURE_IMAGE intent and taking picture (doesn't return to the fragment)

So I have a Fragment that calls the following method which launches the camera:
private void launchCamera() {
Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
if (takePictureIntent.resolveActivity(getActivity().getPackageManager()) != null) {
startActivityForResult(takePictureIntent, REQUEST_IMAGE_CAPTURE);
}
}
And I expect to receive the picture data in this method in my fragment:
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if (!(resultCode == RESULT_OK)) return;
if (requestCode == REQUEST_IMAGE_CAPTURE || requestCode == REQUEST_GALLERY_IMAGE) {
Uri imageURI = data.getData();
// do something
}
}
However, after I take a picture and confirm it, the app goes to my launcher. After setting breakpoints in the onActivityResult method, the app never even reaches this method before crashing. I've granted made sure to grant all permissions in both the manifest and at runtime.
There are also no outputs to Logcat with this crash, both in the app logs and the device logs. I have also tested on both my device (Moto G5 Plus) & Pixel XL API 26 emulator; both have the same result.
I think you need to call super.onActivityResult().
The fragment is the one making the startActivityForResult() call, but the activity gets the first shot at handling the result so you need to implement super.onActivityResult() to make the fragment handle the result.
the app immediately crashes to my launcher
No, the camera app immediately brings up the launcher. Apparently, the developers of this camera app wrote it to bring up the home screen when the user is done taking the picture. This is a bug, of course, but there is little that you can do about it.
Use ACTION_IMAGE_CAPTURE when you would like a picture but do not mind if you do not get it, due to bugs in some of the hundreds of camera apps that you are integrating with. Otherwise, use a camera library (Fotoapparat, CameraKit-Android, etc.) to take the picture directly in your own app.
Also, and FWIW, ACTION_IMAGE_CAPTURE does not return a Uri, so your onActivityResult() code will not work anyway. Given your particular ACTION_IMAGE_CAPTURE Intent configuration, in onActivityResult(), data.getParcelableExtra("data") will return a Bitmap representing a thumbnail-sized image.
I believe this is yet another manifestation of the Android: Activity getting Destroyed after calling Camera Intent.
The bottom line is, the system restarts your app from scratch and your activity is created but has a chance to restore its state.
So you must implement onRestoreInstanceState(). I am not sure you can guarantee that the fragment will be ready to receive onActiviyResult() timely, so to be in the safe side, I prefer to handle the captured image in activity itself.
So this issue was actually because of an intent flag I had attached to the activity. My activity was started using the NO_HISTORY intent flag, which apparently prevented it from being recreated when returned from a startActivityForResult call.

Initiliazing ParseLoginUI?

Where does one actually place the code to launch the ParseLoginUI activity?
ParseLoginBuilder builder = new ParseLoginBuilder(MainActivity.this);
startActivityForResult(builder.build(), 0);
Is it in the ParseLoginDispatchActivity? This was not made very clear at all within any of the official documentation:
https://github.com/ParsePlatform/ParseUI-Android
https://www.parse.com/docs/android/guide#user-interface
I'm importing ParseLoginUI into my existing app. What do I once I've installed everything, updated my manifests, my build.gradle and now want to actually launch the Login activity once my app launches?
Do I put something in my manifest to indicate that the ParseLoginActivity should launch first? That doesn't seem to work as an Activity from my main application is required to launch as the initial intent. I'm a little lost here... Any thoughts?
Well I did find one solution, albeit a trivial one:
Intent loginIntent = new Intent(MainActivity.this, ParseLoginActivity.class); startActivity(loginIntent);
I launched the above Intent with an options menu item, but you could do it with a button or whatever else suits your needs.
If you're importing ParseLoginUI into an existing app, it appears you can just launch ParseLoginActivity with a simple Intent. I wish they mentioned this on their integration tutorial. Seems like the most straightforward way to get it running.
This solution definitely launches the Activity you want, but it doesn't check for whether the user is logged in or not and hence doesn't redirect you to the appropriate pages in your log-in flow (which I believe has more to do with your Manifest). It does, however, allow you to successfully register a user and log in with Parse, which is a great start.
A better solution would be to add the following to the onCreate method in the Activity that launches when your app launches. So if when your app launches you land on FirstActivity, the following will check to see if you are logged in. If you are not, you will be sent the login screen, and if you are logged in you will be sent to the second Activity, which is presumably where your users will want to be when they open your app.
ParseUser currentUser = ParseUser.getCurrentUser();
if (currentUser != null) {
Intent launchMainActivity = new Intent(this, SecondActivity.class);
startActivity(launchMainActivity );
} else {
ParseLoginBuilder builder = new ParseLoginBuilder(FirstActivity.this);
startActivityForResult(builder.build(), 0);
}

Android - Call an activity of an integrated application

Mixare has an application (Open source) that lets you view POIs with your camera. It gives you the possibility to call the app from your application thanks to this :
Intent i = new Intent();
i.setAction(Intent.ACTION_VIEW);
i.setDataAndType(Uri.parse("http://ws.geonames.org/findNearbyWikipediaJSON"), "application/mixare-json");
startActivity(i);
The problem is that user must have the app installed in addition to my app, so what I did is that I imported the whole app within mine, with all its resources and stuff.
But I don't know how to call the main activity MainActivity.java, which resides in the package org.mixare.
How can I make an intent to call this activity ? And how do I declare it in the manifest ?
If you have added the code and resources of the app to your own app, then you should declare and call it's activities as they were your own.
Intent i = new Intent(this, MainActivity.class);
startActivity(i);
This being said, it's not a trivial task. You need to merge AndroidManifest and could get into trouble if you don't know what you're doing. For instance, user can have the Mixare app in addition to yours and intent could have same actions etc.
There is an alternative to this. You could check if Mixare app is installed and if not ask user to do so. This could be more "android way of doing things", depending on your use case.
Look at,
http://code.google.com/p/mixare/wiki/DisplayYourOwnData for how to start mixare via Intent.
Alternatively, you can use mixare as your library project and then call its MainActivity class directly from your application as Using an Android library project Activity within another project.
Quoting the same here -
Declaring library components in the manifest file
In the manifest file of the application project, you must add
declarations of all components that the application will use that are
imported from a library project. For example, you must declare any
, , , , and so on, as well as
, , and similar elements.
Declarations should reference the library components by their
fully-qualified package names, where appropriate.
Then you can definitely call,
Intent intent = new Intent(this, MainActivity.class);
startActivity(intent);
No, it is very hard to do a 2+2=4 kind of addition of manifest files etc.
I see there are two ways to handle this:
Use the external app: Check if the user has external app you want him to have. Else, direct him to the right link. You can get the package name of the publiched app and use it in this function:
private boolean appInstalledOrNot(String uri) {
PackageManager pm = getPackageManager();
boolean app_installed = false;
try {
pm.getPackageInfo(uri, PackageManager.GET_ACTIVITIES);
app_installed = true;
}
catch (PackageManager.NameNotFoundException e) {
app_installed = false;
}
return app_installed ;
}
Combining code: This has no direct/correct answer. You need to study the code and integrate with your existing one.
//appPackageName,appClassName can be found in Logcat
ComponentName component = new ComponentName("appPackageName","appClassName");
Intent intent = new Intent();
intent.setComponent(component);
startActivity(intent);

Categories