How to start BroadcastReceiver or IntentService from non-activity class
by start I mean send intent and make run BroadcastService or IntentService
I.e:
I have class:
public class NumberOne{
#Override
public int functionOne(){
int i = 1 + 4;
if(/*something is true*/){
Intent intent = new Intent(this,intetServiceOne.class);
intent.putExtra("id","path");
context.startService(intent);
}
else {/*continue*/
}
return i;
}
//other functions
}
and if a condition in functionOne is true start IntentService
public class IntentServiceClassOne extends IntentService {
public IntentServiceClassOne () {
super("IntentServiceClassOne ");
}
#Override
protected void onHandleIntent(Intent intent) {
String data = intent.getStringExtra("id");
Log.d("dataIs: ", data);
}
//more functions what to do
}
It dont depend if it is IntentService or BroadcastReceiver
Thanks
To start service You need context instance. You can pass it as constructor parameter:
public class NumberOne{
Context context;
public NumberOne(Context context){
this.context = context;
}
public int functionOne(Context context){
int i = 1 + 4;
if(/*something is true*/){
Intent intent = new Intent(this,intetServiceOne.class);
intent.putExtra("id","path");
context.startService(intent);
}
else {/*continue*/
}
return i;
}
//other functions
}
You don't have to pass Activity instance, Context is enough. It can be application context. You can get it by getApplicationContext() method
You can also create static instance in Application object and get it from them:
public class YourApplication extends Application {
public static YourApplication INSTANCE;
public void onCreate(){
super.onCreate();
INSTANCE = this;
}
}
And your class will be look like below.
public class NumberOne{
public int functionOne(Context context){
int i = 1 + 4;
if(/*something is true*/){
Intent intent = new Intent(this,intetServiceOne.class);
intent.putExtra("id","path");
YourApplication.INSTANCE.startService(intent);
}
else {/*continue*/
}
return i;
}
//other functions
}
But is not good solution.
And the last you can create callback listener and set it in your class like below:
public class NumberOne{
//add setter
YourListener yourListener;
public int functionOne(Context context){
int i = 1 + 4;
if(/*something is true*/){
if(yourListener != null){
yourListener.onFunctionOneCall();
}
}
else {/*continue*/
}
return i;
}
//other functions
public interface YourListener{
void onFunctionOneCall();
}
}
And some place where you have context - for example in activity:
numberOneInstance.setYourListener(new YourListener(){
#Override
public void onFunctionOneCall(){
Intent intent = new Intent(this,intetServiceOne.class);
intent.putExtra("id","path");
this.startService(intent);
}
});
or you can set context by setter
public class NumberOne{
Context context;
public setContext(Context context){
this.context = context;
}
public int functionOne(Context context){
int i = 1 + 4;
if(/*something is true*/){
if(context != null){
Intent intent = new Intent(this,intetServiceOne.class);
intent.putExtra("id","path");
context.startService(intent);
}
}
else {/*continue*/
}
return i;
}
//other functions
}
Related
I am working on ReactNative-Native bridging.
I have Module as below
public class DemoModules extends ReactContextBaseJavaModule {
private Callback mCallback;
private static ReactApplicationContext reactContext = null;
private final ActivityEventListener mActivityEventListener = new BaseActivityEventListener() {
#Override
public void onActivityResult(Activity activity, int requestCode, int resultCode, Intent data)
{
String transactionId = data.getStringExtra("TEST_ID");
mCallback.invoke(transactionId);
}
};
DemoModules(ReactApplicationContext context) {
super(context);
reactContext = context;
reactContext.addActivityEventListener(mActivityEventListener);
}
#Override
public String getName() {
return "DemoModules";
}
#ReactMethod
public void navigate(String mData,Callback mCallback) {
Activity currentActivity = getCurrentActivity();
Intent mIntent= new Intent(reactContext, TestActivity.class);
mIntent.putExtra("TOKEN",mData);
mIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
this.mCallback = mCallback;
currentActivity.startActivityForResult(mIntent,2, null);
}
}
I am calling navigate method as below from my ReactNative code
DemoModules.navigate("TestToken",mCallback => {
console.log(`Created a new event with id ${mCallback}`);
},)}
This navigates to another activity which is TestActivity from which I need to revert with some result so In next Activity I am doing as below
val resultIntent = Intent()
resultIntent.putExtra("TEST_ID", "TEST")
setResult(Activity.RESULT_OK, resultIntent)
finish()
So Summarising it
From React Native>Demo Modules>TestActivity>OnActivityResultback to DemoModules>The final result should be delivered to ReactNative code.
But I am not getting any callback in onActivityResult
What I am missing here?
Update
The main issue currently is onActivityResult is not called in DemoModules.
I'm trying to send a class's object(let's say Class X's object) as part of class that implements Parcelable.
The problem that I am facing here is, Class X is a part of some library and I can not edit it to implement Parcelable or serializable.
I've checked that Class X does not implement Parcelable or serializable and we can not change as well.
Can you guys please help me here?
MainActivity:
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Start the service.
DummyParcelableObject mObj = new DummyParcelableObject(new RandomClass(2019));
Intent serviceIntent = new Intent(MainActivity.this, SampleService.class);
serviceIntent.putExtra("myObj", mObj);
startService(serviceIntent);
}
}
Dummy Parcelable class:
class DummyParcelableObject implements Parcelable {
RandomClass mRandomClass;
public DummyParcelableObject(RandomClass obj) {
mRandomClass = obj;
}
protected DummyParcelableObject(Parcel in) {
mRandomClass = (RandomClass) in.readValue(RandomClass.class.getClassLoader());
}
public static final Creator<DummyParcelableObject> CREATOR = new Creator<DummyParcelableObject>() {
#Override
public DummyParcelableObject createFromParcel(Parcel in) {
return new DummyParcelableObject(in);
}
#Override
public DummyParcelableObject[] newArray(int size) {
return new DummyParcelableObject[size];
}
};
public int getRandomVar() {
int n = 0;
if (mRandomClass != null)
{
System.out.println("Anil: DummyParcelableObject: if (mRandomClass != null) is true.\n");
n = mRandomClass.getNumb();
}
else
{
System.out.println("Anil: DummyParcelableObject: if (mRandomClass != null) is false.\n");
}
return n;
}
#Override
public int describeContents() {
// TODO Auto-generated method stub
return 0;
}
#Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeValue(mRandomClass);
}
}
Class X that is part of another library:
class RandomClass{
public static int cnt = 0;
private int nRandomNumber = 0;
public RandomClass(int n)
{
nRandomNumber = n;
}
public int getNumb()
{
return nRandomNumber;
}
}
Service that we need to send the data to:
public class SampleService extends Service {
#Override
public int onStartCommand(Intent intent, int flags, int startid) {
DummyParcelableObject obj = intent.getParcelableExtra("mObj");
if (obj == null) {
System.out.println("\nAnil: ParcelableExtra is null");
}
else {
System.out.println("\nAnil: ParcelableExtra is not null");
System.out.println("\nAnil: obj.getRandomVar() = " + obj.getRandomVar());
}
return START_STICKY;
}
}
If you cannot implement Parcelable or Serializable, there is only one option left: passing the object through global state.
Using static fields
Add a static field of the type RandomClass to DummyParcelableObject, e.g. randomClassStatic. Set it just before starting the service:
// Start the service.
DummyParcelableObject mObj = new DummyParcelableObject(new RandomClass(2019));
Intent serviceIntent = new Intent(MainActivity.this, SampleService.class);
serviceIntent.putExtra("myObj", mObj);
DummyParcelableObject.randomClassStatic = mObj.getRandomClass();
startService(serviceIntent);
Then retrieve it right after the service started in onStartCommand():
DummyParcelableObject obj = intent.getParcelableExtra("mObj");
obj.setRandomClass(DummyParcelableObject.randomClassStatic);
DummyParcelableObject.randomClassStatic = null;
You would need to define getRandomClass() and setRandomClass() accordingly for getting / setting mRandomClass.
Note that this is not the safest thing to do in regard of concurrency, objects' life cycles, etc…
Using the Application class
This can only be used if you have access to an Activity or Service on both ends.
Subclass Application and add a field of type RandomClass to it. It will serves as relay. Define public methods for getting / setting this field (e.g. getRandomClass() and setRandomClass()). Do not forget to reference your subclassed Application in the manifest as described here. Before starting the service:
// Start the service.
DummyParcelableObject mObj = new DummyParcelableObject(new RandomClass(2019));
Intent serviceIntent = new Intent(MainActivity.this, SampleService.class);
serviceIntent.putExtra("myObj", mObj);
((MyApplication) getApplication()).setRandomClass(mObj.getRandomClass());
startService(serviceIntent);
Then for retrieving the object once the service started, still in onStartCommand():
DummyParcelableObject obj = intent.getParcelableExtra("mObj");
obj.setRandomClass(((MyApplication) getApplication()).getRandomClass());
DummyParcelableObject.randomClassStatic = null;
This has the benefit of not using a static field, but can still be a source of bugs if handled poorly (thread safety, no checks on nullity, …).
Updated :
I have build a image cropping app its running fine, but now I want to save cropped image name as textbox value.
In short I am trying to set textbox value in object and get object value in java Class. I have tried several techniques, recently I am trying to get,set data by using interface technique and the image is saved as ".jpg"only.
I would love to know where am I going wronk?
Following is the code I have tried.
MainActivity
public class TestActivity extends AppCompatActivity implements CropHandler, View.OnClickListener {
public static final String TAG = "TestActivity";
ImageView mImageView;
EditText formnumber;
String formid;
CropParams mCropParams;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.test);
mCropParams = new CropParams(this);
mImageView = (ImageView) findViewById(R.id.image);
formnumber =(EditText)findViewById(R.id.FormNumber);
findViewById(R.id.bt_crop_capture).setOnClickListener(this);
findViewById(R.id.bt_crop_gallery).setOnClickListener(this);
}
#Override
public void onClick(View v) {
mCropParams.refreshUri();
formid=formnumber.getText().toString();
// Intent i = new Intent(TestActivity.this, CropHelper.class);
// i.putExtra("Id",formid);
if(formid.matches(""))
{
Toast.makeText(getApplicationContext(),"Please Enter Application Id",Toast.LENGTH_SHORT).show();
}
else
{
switch (v.getId()) {
case R.id.bt_crop_capture: {
mCropParams.enable = true;
mCropParams.compress = false;
Intent intent = CropHelper.buildCameraIntent(mCropParams);
startActivityForResult(intent, CropHelper.REQUEST_CAMERA);
}
break;
case R.id.bt_crop_gallery: {
mCropParams.enable = true;
mCropParams.compress = false;
Intent intent = CropHelper.buildGalleryIntent(mCropParams);
startActivityForResult(intent, CropHelper.REQUEST_CROP);
}
break;
}
}
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
CropHelper.handleResult(this, requestCode, resultCode, data);
if (requestCode == 1) {
Log.e(TAG, "");
}
}
#Override
public void onTaskComplete(String response) {
onTaskComplete(this.formid);
}
}
CropHelper Class
public class CropHelper {
public static final String TAG = "CropHelper";
/**
* request code of Activities or Fragments
* You will have to change the values of the request codes below if they conflict with your own.
*/
public static final int REQUEST_CROP = 127;
public static final int REQUEST_CAMERA = 128;
public static final int REQUEST_PICK = 129;
public static String AppId;
public static final String CROP_CACHE_FOLDER = "PhotoCropper";
public static Uri generateUri() {
File cacheFolder = new File(Environment.getExternalStorageDirectory() + File.separator + CROP_CACHE_FOLDER);
if (!cacheFolder.exists()) {
try {
boolean result = cacheFolder.mkdir();
Log.d(TAG, "generateUri " + cacheFolder + " result: " + (result ? "succeeded" : "failed"));
} catch (Exception e) {
Log.e(TAG, "generateUri failed: " + cacheFolder, e);
}
}
// String name = String.format("image-%d.jpg", System.currentTimeMillis());
String name = String.format(AppId.toString()+".jpg",System.currentTimeMillis());
return Uri
.fromFile(cacheFolder)
.buildUpon()
.appendPath(name)
.build();
}
#Override
public void onTaskComplete(String response) {
AppId=response;
}
}
Interface
public interface CropHandler
{
void onPhotoCropped(Uri uri);
void onCompressed(Uri uri);
void onTaskComplete(String response);
void onCancel();
void onFailed(String message);
void handleIntent(Intent intent, int requestCode);
CropParams getCropParams();
}
Set formid to EditText value and get the return value in your CropHelper class.
public static String formid=null;
formid=formnumber.getText().toString();
Now create an object of your Activity in a class where you want to call formid value.
MainActivity my_objec= new MainActivity();
String id= my_objec.formid;
String name = String.format(""+id+".jpg",System.currentTimeMillis());
thats all you need to do.
Implement this with your class and get return back your value in interface
public interface onTaskComplete {
void onComplete(String response);
}
Normally what i do is create different class which holds/save all data and values which can used across differnt classes in app.
For example:
// your activity
private CropHelper cropHelper;
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == CropHelper.REQUEST_CROP) {
cropHelper.onReceivedImageData(data.get...)
}
}
public interface DataCallBack {
public void OnReceivedImageData(Data data);
}
....
// your crop helper
public class CropHelper implements YourActivity.DataCallBack {
#Override
public void OnReceivedImageData(Data data) {
// doing anything with data
}
}
Best Approach for this is using interface try to do as :
Create Interface
public interface MyListener {
// you can define any parameter as per your requirement
public void callback(View view, String result);
}
public class MyActivity extends Activity implements MyListener {
#override
public void onCreate(){
MyButton m = new MyButton(this);
}
// method invoke when mybutton will click
#override
public void callback(View view, String result) {
// do your stuff here
}
}
public class MyButton {
MyListener ml;
// constructor
MyButton(MyListener ml) {
this.ml = ml;
}
public void MyLogicToIntimateOthere() {
ml.callback(this, "success");
}
}
for more Go to this link:
Using Interface
Pass data through arguments in constructor..,
For example.. Create Constructor in your class.
public class CropHelper {
private Context context;
private String msg;
public CropHelper(Context context, String msg) {
this.context = context;
this.msg = msg;
if (msg != null) {
showMsg(msg);
}
}
//Replace with your logic
void showMsg(String msg) {
//Perform your operation
Toast.makeText(context, msg, Toast.LENGTH_SHORT).show();
}
}
And then simple call it from any Activity by Creating instance of that class..
Like..
new CropHelper(this, "Hello from Activity");
How can i make a callback to an Activity form a Java Class?
Example:
public class TestClass{
String text = "Test";
public TestClass(Context context){
startActivity(new Intent(context, SomeActivity.class));
}
private void sendToSomeActivity(){
//Call some method of SomeActivity and pas text as string
}
}
When sendToSomeActivity() is called, i want to make a callback to the already started SomeActivity and pass some text to the Activity. In SomeActivity i want to use the text.
Note: The TestClass object that i want to use is already created in another class.
How can this be done?
The solution I chose is as follows:
Use BroadcastReceivers to communicate between Java classes and Activities.
Example:
public class SomeActivity extends Activity{
private MyBroadcastReceiver receiver;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
receiver = new MyBroadcastReceiver();
this.registerReceiver(receiver, new IntentFilter(MyBroadcastReceiver.ACTION));
}
#Override
public void onDestroy() {
super.onDestroy();
this.unregisterReceiver(receiver);
}
private class MyBroadcastReceiver extends BroadcastReceiver{
public static final String ACTION = "com.example.ACTION_SOMETHING"
#Override
public void onReceive(Context context, Intent intent) {
String test = intent.getStringExtra("dataToPass");
}
}
}
public class TestClass{
private String test = "TEST";
private Context context;
public TestClass(Context context){
this.context = context;
}
private void sendToSomeActivity(){
Intent intent = new Intent();
intent.setAction(SomeActivity.MyBroadcastReceiver.ACTION);
intent.putExtra("dataToPass", test);
context.sendBroadcast(intent);
}
}
Try this..
public class TestClass{
interface Implementable{
public void passData(String text);
}
Implementable imple;
String text = "Test";
public TestClass(Context context){
startActivity(new Intent(context, SomeActivity.class));
}
private void sendToSomeActivity(){
if(imple != null){
imple.passData(text);
}
}
public void setListener(Implementable im){
imple = im;
}
}
class SomeActivity implements Implementable{
new TestClass().setListener(this);
#override
public void passData(String text){
//here is your text
}
}
In your java class create an interface like this
public class TestClass{
private MyInterface myInterface;
public interface OnSendSomething {
public void onSending(String sendWhateverYouWant);
}
public void setOnSendListener(MyInterface myInterface) {
this.myInterface = myInterface;
}
}
private void sendToSomeActivity(){
//Call some method of SomeActivity and pas text as string
myInterface.onSending(sendWhateverYouWant);
}
And in your activity do something like this:
TestClass tclass = new TestClass(context);
tclass.setOnSendListener(new OnSendSomething () {
#Override
public void onSending(String sendWhateverYouWant) {
//sendWhateverYouWant is here in activity
}
});
You can also visit these links for better understanding.
How to create our own Listener interface in android?
Observer Design Pattern in Java
I have an activity MyActivity that holds a service class MyService.
I would like the service to send String data to the activity, and then create a button using this data.
Following this post I created a static method in the activity.
The problem of course is that i can't use this in a static context.
public class MyActivity extends Activity {
private MyService myService;
public void onCreate(Bundle savedInstanceState) {
setContentView(R.layout.main);
myService = new MyService();
}
public static void connectMethod (String buttonName) {
Button btn = new Button(this); // error
btn.setId(i);
final int buttonID = btn.getId();
btn.setText(buttonName + buttonID);
}
}
public class MyService {
...
private void showButton (String data) {
MyActivity.connectedMethod(data);
}
}
Two possible solutions to avoid your error:
public static void connectMethod (Context context, String buttonName) {
Button btn = new Button(context);
btn.setId(i);
final int buttonID = btn.getId();
btn.setText(buttonName + buttonID);
}
// ...
public class MyService {
private Context context;
public MyService(Context context) {
this.context = context;
}
...
private void showButton (String data) {
MyActivity.connectedMethod(context, data);
}
}
Or create a static class field : private static Context context;
public static void connectMethod (String buttonName) {
Button btn = new Button(context);
btn.setId(i);
final int buttonID = btn.getId();
btn.setText(buttonName + buttonID);
}