Unable to find Context for getExternalFilesDir() function in Android Studio - java

So, I am trying to write text to a file in Android Studio. I have the following code:
public void sampleFunction() {
File file = new File(getExternalFilesDir(null), "sample-file.txt");
}
The issue is that the method getExternalFilesDir(null) cannot be resolved. After doing some research I have noted that I need to provide the Context class. Such as:
public void sampleFunction(Context c) {
File file = new File(c.getExternalFilesDir(null), "equation_history.xml");
}
And when I called sampleFunction, I would simply pass in the current Context:
sampleFunction(this);
This normally would work, however, I need to call this function inside a setOnClickListener function for a Button. For example:
Button b_go = findViewById(R.id.b_go);
b_go.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Functions.sampleFunction(this);
}
});
So the return value for this is android.view.View.OnClickListener rather than android.content.Context.
How might I get around this? Any advice would be greatly appreciated.

Instead of passing "this" as an argument try calling getApplicationContext() or if you are in fragment just call getActivity().

What is often done is that a Context myContext variable is declared in the class, then onCreate, you populate it with myContext = this; Then, in any listener or Async Task, you can use myContext.getExternalFilesDir(null)

File storageDir = getActivity().getExternalFilesDir(Environment.DIRECTORY_PICTURES);

Related

How can I find context and start a new Activity from Android firebase ML-Kit BarcodeScannerProcessor onSuccess

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();

How to get a view from within Espresso to pass into an IdlingResource?

I essentially have a custom IdlingResource that takes a View a constructor argument. I can't find anywhere that really talks about how to implement it.
I'm trying to use this answer: https://stackoverflow.com/a/32763454/1193321
As you can see, it takes a ViewPager, but when I'm registering the IdlingResource in my test class, I'm not sure how I can get my view.
I've tried findViewById() and I've tried getting the currently running activity and then calling findViewById() on that, with no luck.
Anyone know what to do in this scenario?
Figured it out. To get the view to pass into an idling resource, all you have to do is take the member variable of your ActivityTestRule
For example:
#Rule
public ActivityTestRule<MainActivity> activityTestRule = new ActivityTestRule<>(
MainActivity.class);
and then just call getActivity().findViewById(R.id.viewId)
So the end result is:
activityTestRule.getActivity().findViewById(R.id.viewId);
The accepted answer works as long as a test is running in the same activity. However, if the test navigates to another activity activityTestRule.getActivity() will return the wrong activity (the first one). To address this, one can create a helper method returning an actual activity:
public Activity getCurrentActivity() {
final Activity[] currentActivity = new Activity[1];
InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
#Override
public void run() {
Collection<Activity> allActivities = ActivityLifecycleMonitorRegistry.getInstance()
.getActivitiesInStage(Stage.RESUMED);
if (!allActivities.isEmpty()) {
currentActivity[0] = allActivities.iterator().next();
}
}
});
return currentActivity[0];
}
And then it could be used as the following:
Activity currentActivity = getCurrentActivity();
if (currentActivity != null) {
currentActivity.findViewById(R.id.viewId);
}
If you are using ActivityScenarioRule from androidx.test.ext.junit.rules (since ActivityTestRule "will be deprecated and eventually removed from library in the future"), you can get your Activity instance and call findViewById method:
import androidx.test.ext.junit.rules.activityScenarioRule
import androidx.test.ext.junit.runners.AndroidJUnit4
#RunWith(AndroidJUnit4::class) {
#get: Rule
var testRule = activityScenarioRule<MainActivity>()
#Test
fun mainTestCase() {
testRule.scenario.onActivity { activity ->
val view = activity.findViewById<YourView>(R.id.view)
}
}
}
I haven't already used IdilingResources in Espresso, but did you saw these articles:
Espresso: Custom Idling Resource by Chiuki
Wait for it...a deep dive into Espresso's Idling Resources
Also please check official Android Docs: Idling Resources (reference)
To answer your question,
the best way to do it is passing in an instance of one of the Views into the class's constructor. Check: Calling findViewById() from outside an activity
another way is getting view by context. Check android - How to get view from context?
Here's an exmple taken from a link above:
Starting with a context, the root view of the
associated activity can be had by
View rootView = ((Activity)_context).Window.DecorView.FindViewById(Android.Resource.Id.Content);
In Raw Android it'd look something like:
View rootView = ((Activity)mContext).getWindow().getDecorView().findViewById(android.R.id.content)
Then simply call the findViewById on this
View v = rootView.findViewById(R.id.your_view_id);
This might be also useful: How to call getResources() from a class which has no context?
Hope it help

Loader doesn't start after calling initLoader()?

I have a fragment, and want to start a loader when a button is clicked:
public class MyFragment extends Fragment {
public void onActivityCreated() {
super.onActivityCreated();
Button btn = ...;
btn.setOnClickListener(new OnClickListener() {
public void onClick(View view) {
getLoaderManager().initLoader(500, null, mMyCallback);
}
});
}
private LoaderManager.LoaderCallbacks<String> mMyCallback = new LoaderManager.LoaderCallbacks<String>() {
#Override
public Loader<String> onCreateLoader(int arg0, Bundle arg1) {
Log.e(TAG, "LoaderCallback.onCreateLoader().");
return new MyLoader(getActivity());
}
}
}
public class MyLoader extends AsyncTaskLoader<String> {
public MyLoader(Context context) {
super(context);
}
#Override
public String loadInBackground() {
Log.e(TAG, "Hi, running.");
return "terrific.";
}
}
After clicking the button, I can see my callback's onCreateLoader method called, but the created loader never actually starts. Do we need to call forceLoad() on the loader itself to get it to actually start? None of the sample posts do this,
Thanks
You need to implement onStartLoading() and call forceLoad() somewhere in the method.
See this post for more information: Implementing Loaders (part 3)
In my experience it never worked unless I used forceLoad().
You may find the answer to this previous question helpful:
Loaders in Android Honeycomb
Three important points regarding Loaders are:
Always Use forceLoad() method while initialising Loaders. For Example:
getLoaderManager().initLoader(500, null, mMyCallback).forceLoad();
Always implement onStartLoading(). This function will automatically be called by LoaderManager when the associated fragment/activity is being started.
Make sure the ID of the loader is unique otherwise new Loader will not be called.
If there is still a problem you can check the state of loader by calling the isStarted() method.
You need to keep a reference to the instance of the loader you create in the method onCreateLoader. Then, to refresh it, call yourLoader.onContentChanged();
If you have more than 1 loader in the same activity, make sure their id differs. I lost few hours to figure it out :)

Android, Calling view object from code

I am kind of a newbie so excuse me if this question is too simple or too hard.
I have this code in my java file:
public void button_baby_clicked(View v)
{
//do something here
}
this gets called when someone clicks the imagebutton in my xml file, but how do I call this from the java file itself?
Because it's expecting a View object... and I'm guessing I need to recreate that? How?
Edit:
Ok, to clarify, I want to be able to call the above function via a click in my xml file as well as a function under it.
For example:
public void button_baby_clicked(View v)
{
//do something here
}
public void someFunction()
{
x = 10;
button_baby_clicked(); // This should call the above function.
}
In ur ImageButton you have to add an attribute: android:onClick="button_baby_clicked"
In the java file, you have added:
public void button_baby_clicked(View v)
{
//do something here
}
The logic behind this is:
Upon clicking ur imagebutton, this method will automatically get called, i.e "v" argument will be having ur imagebutton.
The advantage of giving like this is: You no need to initialize the imagebutton in ur activity and no need to set click listener too for this imagebutton.
Alright, if you want to have the method invoked every time the view is clicked, do what the others have said.
Alternatively, you can do something like this.
ImageView globalReference;
#Override
public void onCreate(Bundle icicle){
*** CODE ***
globalReference = (ImageView) findViewById(R.id.myImageView);
*** CODE ***
}
Then, whenever you want that to be called with that particular View, simply call
button_baby_clicked(globalReference);
You can also do this with any View object you create dynamically.
View myTv = new TextView(context);
View myLl = new LinearLayout(context);
button_baby_clicked(myTv);
button_baby_clicked(myLl);
Just get a valid View reference within the same scope as the method, and pass it in like any other method. It can even be null if the method is capable of handling it.
Can't you use it like -
mButton.setOnClickListener(new OnClickListener{
#Override
public void onClick(View v) {
button_baby_clicked(v);
}
}
);
??
EDIT :
If you need to call someFunction() from the onClick of a button,and from there,you need to call button_baby_clicked(),you have to get View v object in someFunction. This link might help you. Please refer Start a service on onClick. You can change appropriately.
I believe its best if you refactor your code and put the code in the event handler into a global method that can be called from anywhere. like this:
public void button_baby_clicked(View v)
{
taskToPerform(); // Perform a certain task
}
public void someFunction()
{
x = 10;
taskToPerform(), // Perform the same task again
}
public void taskToPerform()
{
//This is where you write the task you want to perform
}
This way you can reuse the code in the taskToPerform() method anywhere, anytime.

setOnClickListener to all extended ImageViews - Java

I have a custom class that I've written that extends ImageView (for Android Java). I want to add a ClickListener to every instance I create of the class that will do the same thing (just animate the ImageView.
I tried a few different things to no avail. The code below is what I want to accomplish but it's being applied to an instantiated object of the class.
MyCustomImageView fd = new MyCustomImageView(this);
fd.setOnClickListener(new OnClickListener(){
public void onClick(View v) {
Animater(fd);
}
});
I tried using "implements onClickListener" on the class declaration and then a public void onClick() method in the class, and that didn't work for me.
I also tried using the code snippet above with a "this" instead of "fd" and that didn't work either.
I'm relatively new to java and this is out of the scope of my knowledge. Any assistance you can provide is greatly appreciated.
It's really easy. You have to do it in your custom class:
public class MyCustomImageView extends ImageView{
public MyCustomImageView(Context context){
super(context);
setOnClickListener(theCommonListener);
}
private OnClickListener theCommonListener = new OnClickListener(){
public void onClick(View v) {
// do what you want here
}
}
}
There are other ways to do it, but this is one is really easy to implement and understand. Every instance of MyCustomImageView will have the same event listener (unless you override it from outside).

Categories