I've got two activities, one of them is called MyActivity. I want both of them to be able to use a function located in a class othat we may call MyClass. In MyClass, I try to use an intent to launch the activity AnotherActivity. Since the constructor takes a context as parameter, I simply tried to store a context from the activity in the constructor, and then use it when I try to create my intent.
class MyClass {
private Context cxt;
MyClass(Context cxt) {
this.cxt = cxt;
}
startIntent() {
Intent intent = new Intent(cxt, AnotherActivity.class);
startActivity(intent); // this line throws a NullPointerException
}
}
The code in MyActivity to use the class is shown below:
myClassObject = new MyClass(MyActivity.this);
myClassObject.startIntent();
However, even thought none of the arguments are null (checked that with a simple if-statement), intent seems to be null and a NullPointerException is thrown. Why does it not work, and what can I do to solve the problem?
I'm quite new to Android and Java development, so please explain it as basic as you can.
cxt.startActivity(new Intent(cxt, AnotherActivity.class));
and to be sure that it's intent is NULL, and not something internal in startActivity method, you can add some checks, i.e.
Intent intent = new Intent(cxt, AnotherActivity.class);
Log.d(toString(), "intent = " + intent.toString());
cxt.startActivity(intent);
I've used almost identical code in my applications and it's worked fine.
I suspect there's something else going on that's in code you haven't shown us; I suspect there's some cut-and-paste issues --- e.g. what are you calling startActivity() on in MyClass?
Related
So, I have two options to get the context. See the following two methods (cleaned up for clarity) from a Utility Class.
public static void onCopyClicked(Context context, ImageView copy){
copy.setVisibility(View.GONE);
Intent intent = new Intent(context, NextActivity.class);
context.startActivity(intent);
}
public static void onCopyClicked(ImageView copy){
Context context = copy.getContext();
copy.setVisibility(View.GONE);
Intent intent = new Intent(context, NextActivity.class);
context.startActivity(intent);
}
I can pass the context or simply get it from the view. I guess I prefer the second one since it is one less parameter to pass, but I wonder if the getContext() call is costly. I'm not trying to micromanage my code, but rather just trying to follow best practices (if one exists for this case).
You can use the second option.
Calling getContext() on a View is not costly. The context reference is saved when a View is created and the getContext() method just returns it.
Check the constructor source code and the getContext() method of a View.
I am using the quickstart-android code provided by google but after many attempts I cam unable to find a context that is not returning null. The BarcodeScannerProcessor is not itself an Activity, so I have attempted to create an instance of the LivePreviewActivity and use that as the context in the intent, but it's null.
The goal is to once a valid barcode is recognized I want to open a new activity that allows a user to verify value and on the push of a button call a webservice to post the barcode to a database via API. I am having a hard time finding a valid context and the app is crashing when it trys to execute the Intent.
Starting at line 97-107:
https://github.com/jamiekeefer/quickstart-android/blob/master/mlkit/app/src/main/java/com/google/firebase/samples/apps/mlkit/java/barcodescanning/BarcodeScanningProcessor.java
for (int i = 0; i < barcodes.size(); ++i) {
FirebaseVisionBarcode barcode = barcodes.get(i);
BarcodeGraphic barcodeGraphic = new BarcodeGraphic(graphicOverlay, barcode);
graphicOverlay.add(barcodeGraphic);
System.out.println(barcode.getRawValue());
if (!barcode.getRawValue().equals("") ) {
System.out.println("Got the number:" + barcode.getRawValue() + " Context: " + mContext); //OLD SCHOOL DEBUG OUTPUT
//enter code to start activity
Intent intent = new Intent(mContext, SendScannedBarcode.class);
String message = scannedBarcode;
intent.putExtra(EXTRA_MESSAGE, message);
mContext.startActivity(intent);
}
}
You can back up in the repo to see the instance of the LivePreviewActivity where I trying to get context.
I have tried a number of things and read about Context, Views and Activities and basically have completely confused myself. The only tuts I can find are using Kotlin, which is not helping clarify things.
I appreacite any help in indentifying or contruting a valid Intent from this Context. Thank you.
So I am assuming that in your LivePreviewActivity you are creating an object of the class BarcodeScanningProcessor. What you can do is change the constructor in the BarcodeScanningProcessor class to accept a context and then you pass in your LivePreviewActivity's context.
This is what the code should look like:
In BarcodeScanningProcessor:
public BarcodeScanningProcessor(Context context) {
// Note that if you know which format of barcode your app is dealing with, detection will be
// faster to specify the supported barcode formats one by one, e.g.
// new FirebaseVisionBarcodeDetectorOptions.Builder()
// .setBarcodeFormats(FirebaseVisionBarcode.FORMAT_QR_CODE)
// .build();
detector = FirebaseVision.getInstance().getVisionBarcodeDetector();
this.mContext = context;
}
Then in LivePreviewActivity:
In the particular case of your activity you would do:
case BARCODE_DETECTION:
Log.i(TAG, "Using Barcode Detector Processor");
cameraSource.setMachineLearningFrameProcessor(new BarcodeScanningProcessor(getApplicationContext()));
break;
Or if you just wanted to create an object of the class you could do:
BarcodeScanningProcessor bsp = new BarcodeScanningProcessor(getApplicationContext());
This should now give your BarcodeScanningProcessor class the context of your activity. Now, in BarcodeScanningProcessor, mContext should not be null and will have the context of your activity. I hope this answers your question.
try this create Application class
import android.app.Application;
public class MyApplication extends Application {
static MyApplication instance;
#Override
public void onCreate() {
super.onCreate();
instance=this;
}
public static MyApplication getInstance() {
return instance;
}
}
Register in manifest file
<application
..
android:name="com.yourpackage.MyApplication"
..>
.
.
.
</application>
start activity using this MyApplication.
Intent intent = new Intent(MyApplication.getInstance(), SendScannedBarcode.class);
String message = scannedBarcode;
intent.putExtra(EXTRA_MESSAGE, message);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
MyApplication. getInstance().startActivity(intent);
Another way of handling the issue is create new constructor of BarcodeScanningProcessor which takes interface call back and once processing is done pass back result to caller.
public interface BarcodeUpdateListener {
#UiThread
void onBarcodeDetected(Barcode barcode);
}
private BarcodeUpdateListener callback;
public BarcodeScanningProcessor(BarcodeUpdateListener callback){
this.callback = callback;
detector = FirebaseVision.getInstance().getVisionBarcodeDetector();
}
Once you get the result pass result to caller
callback.onBarcodeDetected(<Barcode>)
You can get the context from graphicOverlay:
Context context = graphicOverlay.getContext();
I want to use String variable containig the name of an activity, and i want to open the activity via in intent.
For example:
next = "foo.class";
Intent baslat = new Intent(this,next);
"next" is my value. I think using variable is impossible because eclipse don't let me use two arguments.
How can I solve this problem?
Edit: I am trying to go to "foo.class"
Edit: I solve the problem, You are all so nice and pretty :D, kisses for all, thank you very much!
OK, use the method Class.forName()
String myClass = "foo.class";
Intent myIntent = new Intent(getApplicationContext(), Class.forName(myClass));
startActivity(myIntent );
There is a method Intent.putExtra(). You can use this method to add extra variables inside your intent object.
String next = "foo.class";
Intent baslat = new Intent();
baslat.putExtra("my_tag", next);
Intent.putExtra() is what you're looking for.
next = "foo.class";
Intent baslat = new Intent(/*intent action goes here*/);
basalt.putExtra(/*data name*/, next);
If foo.class is where you're headed, then use Intent(Context packageContext, Class cls):
Intent baslat = new Intent(this, foo.class);
startActivity(basalt);
I managed to get my headset buttons get recognized by my app when pressed, but one of the buttons needs to call a method that's in MyCustomActivity. The problem is onReceive's 1st parameter is a Context that cannot be cast to Activity and using a MyCustomActivity's inner class won't work in Android 4.1 unless it is static (which has the same problem of inability to access MyCustomActivity's method.
So the only option left for me (in order to support both 2.x and 4.1) is to pass the activity as a parameter to RemoteControlReceiver.
But how do I do that, when the only way to instantiate it is via:
private ComponentName mRemoteControlReceiver = new ComponentName(this, RemoteControlReceiver.class);
Which doesn't accept any additional parameters?
Any idea how to work around this limitation?
Note: If I try to define RemoteControlReceiver as having a constructor with a parameter, I receive the following exception:
E/AndroidRuntime(2836): java.lang.RuntimeException: Unable to instantiate receiver com.example.RemoteControlReceiver: java.lang.InstantiationException: can't instantiate class com.example.RemoteControlReceiver; no empty constructor
Caused by:
E/AndroidRuntime(2836): Caused by: java.lang.InstantiationException: can't instantiate class com.example.RemoteControlReceiver; no empty constructor
E/AndroidRuntime(2836): at java.lang.Class.newInstanceImpl(Native Method)
E/AndroidRuntime(2836): at java.lang.Class.newInstance(Class.java:1319)
E/AndroidRuntime(2836): at android.app.ActivityThread.handleReceiver(ActivityThread.java:2205)
So it is clear that this new registerMediaButtonEventReceiver requirement (introduced in Android 4.1) expects an empty constructor.
Is there no way to work around this?
For example, is there a way to get a reference to the actual RemoteControlReceiver object (instantiated indirectly via mAudioManager.registerMediaButtonEventReceiver())? So that I can use an accessor to set a data-member of RemoteControlReceiver after it has been instantiated?
registerMediaButtonEventReceiver requires the BroadcastReceiver to be declared in the application manifest. This means that the receiver must be a standalone class, meaning it knows nothing about your current activity or service.
In order to get this message to your activity or service, you have a number of options:
Use a static global for the activity or service so the receiver can forward the message to it. This is generally not a good idea as it leads to leaks and isn't very adaptable when you want to change the code later. Statics are generally to be avoided.
Re-broadcast the message to a specific class, which happens to be an inner class of the activity or service you want to invoke. E.g. in the BroadcastReceiver for registerMediaButtonEventReceiver:
// Standalone class, declared in the manifest
public class ButtonReceiver extends BroadcastReceiver {
#Override
public void onReceive(final Context context, final Intent intent) {
Intent intent = new Intent();
intent.setAction("com.foo.ACTION");
// Rebroadcasts to your own receiver.
// This receiver is not exported; it'll only be received if the receiver is currently registered.
context.sendBroadcast(intent);
}
}
And in your activity:
class MyActivity extends Activity {
private BroadcastReceiver myReceiver = new BroadcastReceiver() {
#Override
public void onReceive(final Context context, final Intent intent) {
MyActivity.this.onMessageReceived();
}
}
#Override
protected void onResume() {
registerReceiver(myReceiver, new IntentFilter("com.foo.ACTION"));
}
#Override
protected void onPause() {
unregisterReceiver(myReceiver);
}
private void onMessageReceived() {
}
}
Similar to the above method, it doesn't necessarily have to be a broadcast, it could be an Intent passed to the activity, depending on your use case. To do this instead of using sendBroadcast, you'd use startActivity (or startService if you're using a service).
I have a button on Main's android xml file which once clicked will display another view/activity.
My problem is the error message displays that the application must end unexpectedly.
Here is the button
<Button android:id="#+id/showmeurcode"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="OnShowMeUrCode"
>
The method OnShowMeUrCode is defined in the MainActivity class as
private void OnShowMeUrCode(View btn)
{
Intent urCode=new Intent(this,CodePage.class);
startActivity(urCode);
}
CodePage is generated from a class of the same name
public class CodePage extends Activity
{
....
}
That is all I have done in the hope that I could accomplish the simple task with Intent to display another view but I run in an unexpected error and my program fails short.
You need to change your OnShowMeUrCode() function to be public, not private. Since it's part of the Activity class, your Button won't have access to it if it's private.
Plus it's in the docs:
http://developer.android.com/reference/android/widget/Button.html
Based on your code without the error log output, I guess you didn't pass a correct Context to the method.
This is your code:
private void OnShowMeUrCode(View btn)
{
Intent urCode=new Intent(this,CodePage.class);
startActivity(urCode);
}
Try replace the relevant line with:
Intent urCode=new Intent(MainActivity.this,CodePage.class);
Say, I have two Activities, A and B. If I'm calling B from A, I should write something like:
Intent i = new Intent(A.this, B.class);
startActivity(i);
Besides, you need to register your Activity in AndroidManifest.xml each time you create a new activity. In your case, please check if there are 2 activities in your AndroidManifest.xml