I am building an app which has a feature to crop images using react-native-image-crop-picker. I am trying to implement the logic to store the cropped images locally in my react native app. I could successfully implement the logic for iOS, however, I am having trouble with the Android side.
My problem is that when I store the image using reactContext.getFilesDir(), the image is stored into the /data/user/0/com.myapp/files/ directory. And the images can be accessed via 'Google Photos' app or 'Files' app. I don't want to let the users access these images.
Here is the picture describing my problem.
The things I have tried so far:
1. Use getCurrentActivity() instead of reactContext
2. Use getReactApplicationContext() instead of context
Findings:
- After saving the image, it is stored into /data/user/0/com.myapp/files/, /data/data/0/com.myapp/files/ and storage/emulated/0/Pictures/.
FileStreamHandler.java
public class FileStreamHandler extends ReactContextBaseJavaModule {
private Context context;
// private Activity mActivity;
#Nonnull
#Override
public String getName() {
return "FileStreamHandler";
}
public FileStreamHandler(ReactApplicationContext reactContext) {
super(reactContext);
// mActivity = reactContext.getCurrentActivity();
this.context = reactContext;
}
#ReactMethod
private void saveImageData(String base64String, Callback callback) {
// Generate random image name
String fileName = UUID.randomUUID().toString() + ".png";
// File fileDirectory = mActivity.getFilesDir();
File fileDirectory = context.getFilesDir();
File imageFile = new File(fileDirectory, fileName);
String imageFilePath = imageFile.getAbsolutePath();
try {
OutputStream stream = new FileOutputStream(imageFile);
//decode base64 string to image
byte[] decodedBytes = Base64.decode(base64String, Base64.DEFAULT);
Bitmap decodedImage = BitmapFactory.decodeByteArray(decodedBytes, 0, decodedBytes.length);
decodedImage.compress(Bitmap.CompressFormat.PNG,100, stream);
stream.flush();
stream.close();
} catch (IOException e) {
e.printStackTrace();
}
callback.invoke(imageFilePath);
}
}
The image is stored successfully without any errors. However, it is stored into /data/user/ and can be accessed via other applications such as 'Photos' or 'Files'.
Although I am using exactly the same logic in my pure Android app, I have never had this problem. Therefore, I am suspecting that the react application context is causing the problem.
Any help would be highly appreciated.
Thank you.
It turns out that the cause of the problem is the react native library that I am using. I don't know why they implemented in this way, however, it seems like the react-native-image-crop-picker library saves images into the /storage/0/Pictures/ directory after cropping.
export I m new in android so I don't anyhow to use this type of code in firebase. Below is my video link URL and I want to use it from firebase how can I do it please give me solution step by step because I m new in android project. thank you. here is video URL of mine `public
class playUtils {
public static String[] videoUrls = {
"http://112.253.22.163/4/p/p/q/v/ppqvlatwcebccqgrthiutjkityurza/hc.yinyuetai.com/59EC014EDDFE31808075899973863AAD.flv",
"http://112.253.22.162/7/i/u/l/x/iulxxctvtlkdvznykfxqbftlwlvfdk/hc.yinyuetai.com/010C014EBF2B4B726D9D67F0BB236F6D.flv",
"http://112.253.22.159/30/u/h/c/t/uhcthkfakxfueltyfrickugkkshedl/hc.yinyuetai.com/29A801589BED77C3D62884A3A15BA1F3.mp4",
"http://112.253.22.164/4/a/q/t/z/aqtzkpyhsvnomtvjbskpjjkkyjeaaq/hc.yinyuetai.com/0EAD0158BD54A2F9F242E02065A966C2.mp4",
"http://112.253.22.157/19/f/k/n/n/fknntmnmqvxxwomhukhftbjwrtmyci/hc.yinyuetai.com/45580153801E6B6083057A09E1811AA1.flv",
"http://112.253.22.163/4/u/x/o/t/uxotdanllblkoxoegkthfpapivsywh/hc.yinyuetai.com/E2B60155AAA1AD8BD01A027BCB2540DE.flv",
"http://112.253.22.162/5/k/s/a/r/ksarzmxsvukrlrlrncyqgqvguwgnww/hc.yinyuetai.com/BA710157626FB47F1B68C35E974120C7.flv",
"http://112.253.22.156/14/j/s/s/d/jssdpypuuzgutqiolfvbxizywfjzjd/hc.yinyuetai.com/F9640146F51C894E3B31592989D7AE28.flv",
"http://220.194.199.186/1/a/o/i/q/aoiqwkcqlcyqmhyaprtbhafndapzoe/hc.yinyuetai.com/70FD014F061C972D24F5EDE5381BE543.flv",
"http://112.253.22.162/4/d/p/k/c/dpkcdjdhtzzfntsuoxhozwayhjvwke/hc.yinyuetai.com/ED44014EF18FF6700FBF10169A21144E.flv"};
`
after that here is video thumbnail `public static String[] videoThumbs = {
"http://img3.yytcdn.com/video/mv/140108/850708/D81901436FF172396A44128BAC8C3707_240x135.jpeg",`
and title is here ` public static String[] videoTitles = {
"B.B.B(Big Baby Baby)",`
use Exoplayer to play from the link(Uri).
This is the code to stream the video.
private void initializePlayer() {
Uri uri = Uri.parse(/*your video link here*/);
MediaSource mediaSource = buildMediaSource(uri);
player.prepare(mediaSource, true, false);
}
Find more about Exoplayer here. https://codelabs.developers.google.com/codelabs/exoplayer-intro/#2
The google Vision's Barcode detection API works fine and gets the result of the scanned barcode using Android. But I didn't find any way to get the frame from which the barcode is detected. Is there any way to get that exact frame?
You can use detect(Frame) instead of receiveFrame(Frame).
When using receiveFrame(), you can only receive the barcode results returned by a processor:
class BarcodeTrackerFactory implements MultiProcessor.Factory<Barcode> {
private GraphicOverlay mGraphicOverlay;
BarcodeTrackerFactory(GraphicOverlay graphicOverlay) {
mGraphicOverlay = graphicOverlay;
}
#Override
public Tracker<Barcode> create(Barcode barcode) {
BarcodeGraphic graphic = new BarcodeGraphic(mGraphicOverlay);
return new GraphicTracker<>(mGraphicOverlay, graphic);
}
}
Whereas detect() is a synchronized method. So you can save the results with the exact frame.
i have read many threads on this topic and tried to use them in my code but i am still not able to solve it.
What i am trying to do:
Like facebook or any other app which downloads feed from server which includes image, I am also doing same and trying to display feeds and images on the image view.
What is happening:
I am able to download the feeds (in JSON) which includes URL of images and i am able to show them on ImageView.
In Emulator my MAX heap size is 64MB. I am consuming around 30MB in first 10 feeds( not sure why but this is what i get from Memory tab in Android monitor of Android Studio and Even in Android Device monitor).
I have a refresh button in my app which reloads the same feeds after removing all feeds which were earlier populated. I expected that i will be consuming the same memory or some what more. But contrary to that my memory usage got increased upto 42MB. Hence after tapping on refresh for 3 to 4 times, it is causing OutOFMemory Execption. Even if i load next 10 feed or 50 feeds at a time i am getting OutOfMemory Exception.
I know that facebook instagram and many more such apps does the same thing but not sure how they implemented the code to cover this situation.
Below is my code for populating feed
private void loadFeed(List<Feed> feedList)
{
Log.v(Constant.TAG,"Loading Feed in social feed page");
for(final Feed feed:feedList) {
LinearLayout feedBox = new LinearLayout(this);
feedBox.setOrientation(LinearLayout.VERTICAL);
FrameLayout profileDetailContainer= new FrameLayout(this);
LinearLayout profileDetailContainerParent=new LinearLayout(this);
LinearLayout profileDetailContainerChild=new LinearLayout(this);
profileDetailContainerChild.setOrientation(LinearLayout.VERTICAL);
ImageView imgProfile= new ImageView(this);
TextView txtDate= new TextView(this);
TextView txtName= new TextView(this);
ImageView imgProduct= new ImageView(this);
txtName.setText(feed.getUserFullName());
TextView txtDesciption= new TextView(this);
txtName.setTypeface(null, Typeface.BOLD);
if(feed.getDescription().length()>Constant.NUMBER_OF_DESCRIPTION_CHAR_SHOW_ON_RESULT)
{
txtDesciption.setText(feed.getDescription().substring(0,Constant.NUMBER_OF_DESCRIPTION_CHAR_SHOW_ON_RESULT)+"...");
}
else
txtDesciption.setText(feed.getDescription());
if(!IOUtil.fileExists(this,feed.getProductImageName())) {
WebRequest request = new WebRequest();
request.setUrl(Constant.ROOT_APPLICATION_URL_WITH_SEPARATOR + feed.getImgPath());
request.setParam(feed.getId() + "");
new ImageDownloadTask(this, true, feed.getProductImageName(), this).execute(request);
Log.v(Constant.TAG,"URL:"+Constant.ROOT_APPLICATION_URL_WITH_SEPARATOR+feed.getImgPath());
Picasso.with(getApplicationContext()).load(R.drawable.logo).into(imgProduct);
feedBox.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
ScreenUtility.alertException(v.getContext(),"Please wait untill product image loads");
}
});
PixyfiSession.save(feed.getId() + "", imgProduct);
PixyfiSession.save(feed.getId() + "_feed", feed);
}
else
{
ImageUtil.recycleIfPossible(imgProduct);
try {
imgProduct.setImageBitmap(ImageUtil.getLocalImage(feed.getProductImageName(),this));
FeedboxOnClickListener feedboxOnClickListener = new FeedboxOnClickListener(feed);
feedBox.setOnClickListener(feedboxOnClickListener);
} catch (FileNotFoundException e) {
Log.v(Constant.TAG,e.getMessage(),e);
}
}
if(FacebookUtil.localProfilePicExists(feed.getUserName(),this))
{
Bitmap profileImage= FacebookUtil.getLocalProfilePicture(feed.getUserName(),this);
imgProfile.setImageBitmap(profileImage);
}
else {
FacebookUtil.loadProfilePicture(feed.getUserName(),this,this);
PixyfiSession.save(feed.getUserName(),imgProfile);
imgProfile.setImageResource(R.drawable.profile);
}
try {
if(feed.getDate()==null) {
txtDate.setText(new SimpleDateFormat("dd MMM yyyy").format(new SimpleDateFormat("yyyy-MM-dd").parse(feed.getFeedDate())));
}
else {
txtDate.setText(new SimpleDateFormat("dd MMM yyyy").format(feed.getDate()));
}
} catch (ParseException e) {
Log.e(Constant.TAG,e.getMessage(),e);
}
LinearLayout.LayoutParams layoutParam= new LinearLayout.LayoutParams(140,140);
layoutParam.setMargins(5,5,0,0);
imgProfile.setLayoutParams(layoutParam);
layoutParam= new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT,LinearLayout.LayoutParams.WRAP_CONTENT,Gravity.TOP|Gravity.LEFT);
layoutParam.setMargins(20,5,0,0);
txtName.setLayoutParams(layoutParam);
layoutParam= new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT,LinearLayout.LayoutParams.WRAP_CONTENT,Gravity.LEFT);
layoutParam.setMargins(20,5,0,0);
txtDate.setLayoutParams(layoutParam);
profileDetailContainerParent.addView(imgProfile);
profileDetailContainerChild.addView(txtName);
profileDetailContainerChild.addView(txtDate);
profileDetailContainerParent.addView(profileDetailContainerChild);
feedBox.addView(profileDetailContainerParent);
LinearLayout.LayoutParams feedLayoutParam=new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,ViewGroup.LayoutParams.WRAP_CONTENT,Gravity.CENTER_VERTICAL);
feedLayoutParam.setMargins(5,5,5,5);
imgProduct.setLayoutParams(feedLayoutParam);
txtDesciption.setLayoutParams(feedLayoutParam);
feedBox.addView(txtDesciption);
feedBox.addView(imgProduct);
feedLayoutParam=new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,ViewGroup.LayoutParams.WRAP_CONTENT,Gravity.CENTER_VERTICAL);
feedLayoutParam.setMargins(0,5,0,5);
feedBox.setLayoutParams(feedLayoutParam);
feedBox.setBackgroundColor(Color.parseColor("#cccccc"));
PixyfiSession.save(feed.getId()+"_feedbox",feedBox);
imgProfile.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
PixyfiSession.save(Constant.SELECTED_USER_ID,feed.getUserName());
ScreenUtility.loadScreen(v.getContext(),UsersProfile.class,false);
}
});
this.feedContainer.addView(feedBox);
}
if(feedList.size()==Constant.FEED_SIZE_IN_ONE_REQUEST)
{
Button moreFeed= new Button(this);
moreFeed.setText("Load MOre Feed");
moreFeed.setOnClickListener(new MoreFeedButtonListener(this));
this.feedContainer.addView(moreFeed);
}
this.progressBar.setVisibility(View.INVISIBLE);
}
For reloading/refreshing the feed
this.currentPage=1;
this.recycleImages();
this.feedContainer.removeAllViews();
PixyfiSession.save(Constant.CURRENT_FEED_PAGE,this.currentPage);
this.progressBar.setVisibility(View.VISIBLE);
loadFeed();
recycleImages Method:
private void recycleImages()
{
for(int i=0;i<this.feedContainer.getChildCount();i++)
{
if(this.feedContainer.getChildAt(i) instanceof ImageView)
{
ImageView view=(ImageView)this.feedContainer.getChildAt(i);
ImageUtil.recycleIfPossible(view);
}
}
}
If you need further details on the code then please let me know.
Also is it possible to see memory usage of other apps like facebook in android device monitor?
UPDATE
ImageUtil.getLocalImage Method
public static Bitmap getLocalImage(String imageName, Context context) throws FileNotFoundException
{
Bitmap bitmap=null;
InputStream is=null;
if(IOUtil.fileExists(context,imageName)) {
is = context.openFileInput(imageName);
bitmap= BitmapFactory.decodeStream(is);
}
else {
throw new FileNotFoundException("Image file doesn't exists");
}
return bitmap;
}
I am adding the answer :
Instead of managing the view components yourself you should always prefer listview or better recycler view.
Because it help you avoid view leaks and provide better reuse of views that you already created.
i had same problem add this line to your manifest in application tag:
<application
android:largeHeap="true"
.
.
.
As Saber Safavi told do that first and then add
defaultConfig {
....
multiDexEnabled true
....
}
in your
app/build.gradle
file..
Look like you have problem with loading images. Please check your ImageUtils.getLocalImages, did you decode and load a scaled version of images into memory, or did you load original images into memory?
Follow this document from Android developer , i think it's the best tutorial for loading images efficiently in Android.
Image handling in Android is very very tricky. Better use a library which has been built to take care of the situation and complexities involved.
I prefer
UniversalImageLoader or Piccaso!
It is because you are keeping too many bitmap images in Run-time memory, try not to create too many images and try nullifying them.
Mobile devices typically have constrained system resources. Android devices can have as little as 16MB of memory available to a single application. Virtual Machine Compatibility gives the required minimum application memory for various screen sizes and densities. Applications should be optimized to perform under this minimum memory limit. However, keep in mind many devices are configured with higher limits.
I will not recommend you for the heapSize flag in android manifest. I hope you are not developing games :), Rather go for retrofit or any other image processing library if you want. I would suggest you to look at BitmapFun sample provided by Google. It is available on developer portal.
http://developer.android.com/training/displaying-bitmaps/index.html
Cheers!!
I'm developing an Android app which allows users to upload/download images to and from a database (powered by Amazon AWS). The problem I'm facing is that I can successfully download the files to a directory
/storage/emulated/0/data/myfile.jpg
But I cannot display them as a new ImageView.
Here are my methods that deal with displaying the methods. Note that RefreshFeedTask.downloadedFiles is a List of Bitmaps as shown here:
do {
objectListing = s3Client.listObjects(listObjectsRequest);
for (S3ObjectSummary objectSummary :
objectListing.getObjectSummaries()) {
keys.add(objectSummary.getKey());
}
listObjectsRequest.setMarker(objectListing.getNextMarker());
} while (objectListing.isTruncated());
Iterator<String> o = keys.iterator();
while(o.hasNext())
{
String n = o.next();
File file = new File(Environment.getExternalStorageDirectory()+"/data/", n);
if(!file.exists())
{
try {
file.createNewFile();
} catch (IOException e) {
e.printStackTrace();
}
}
TransferObserver observer = transferUtility.download(
existingBucketName,
n,
file);
Bitmap m = BitmapFactory.decodeFile(file.getAbsolutePath());
private void refreshFeed()
{
new RefreshFeedTask(this).start();
for(Bitmap f : RefreshFeedTask.downloadedFiles)
{
displayImage(f);
}
}
private void displayImage(Bitmap f){
ImageView myImage = new ImageView(this);
myImage.setImageBitmap(f);
myImage.setVisibility(View.VISIBLE);
Log.i("Background","Displaying file");
}
Any help is appreciated, as I am somewhat new to Android development, but not Java development.
Looks like you have not added you new ImageView to any view, try adding your new ImageView to any container to display it.
parentLayout.addView(theNewImageView);
Another tip: You can try Glide if you want to display many images more efficiently.
One issue that you have here is Ownership.
Advise: That file you just downloaded to that location, your app may not own that location. If this is a closed ecosystem where you are the sole user and owner of that file, you should probably create an application specific directory upon running the application.
The best way to display something that you do not own in the Sdcard is to use the MediaStore API in Android to access them. You need a URI to the right path and just doing an absolute path is not generally advised, especially for image assets.
A good example of this is here:
https://dzone.com/articles/displaying-images-sd-card