How to mock BitmapFactory: Method decodeFile - android

I have a program which creates thumbnail image from a full size image saved in the storage area . I am trying to test that functionality using mockito but it gives me the following error:
java.lang.RuntimeException: Method decodeFile in android.graphics.BitmapFactory not mocked
//Solved(Updated code)
I am running unit tests using mockito for the first time, Could someone please suggest what I am doing wrong(which I know definitely doing). I am also using ExifInterface to extract the metaData associated with the image but it is giving me the same error again:
java.lang.RuntimeException: Method getAttribute in android.media.ExifInterface not mocked.
Here is the MainActivity class :(where I am running the method).
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initValue();
}
public void initValue()
{
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
Bitmap thumbnail = createThumbnailFromBitmap("/storage/emulator/0/demo/abcd", 100, 100);
try {
ExifInterface exifInterface = new ExifInterface("/storage/emulator/0/demo/abcd");
String jsonData = exifInterface.getAttribute("UserComment");
try {
JSONObject rootJson = new JSONObject(jsonData);
dateList.add(rootJson.getString("captured"));
}
catch(JSONException e)
{
}
}
catch(Exception e)
{
System.out.println("exception "+e);
}
}
private Bitmap createThumbnailFromBitmap(String filePath, int width, int height){
return ThumbnailUtils.extractThumbnail(BitmapFactory.decodeFile(filePath), width, height);
}
}
My test class:
#RunWith(PowerMockRunner.class)
#PrepareForTest({BitmapFactory.class ,ThumbnailUtils.class})
public class initValueTest {
#Mock
private Bitmap bitmap;
#Test
public void initValueTest()
{
PowerMockito.mockStatic(BitmapFactory.class);
PowerMockito.mockStatic(ThumbnailUtils.class);
when(BitmapFactory.decodeFile(anyString())).thenReturn(bitmap);
MainActivity mainActivity = new MainActivity();
mainActivity.initValue();
}
}
Thanks for your help guys. Please excuse if I am doing anything wrong.

You can either:
Use power mock to mock static method decodeFile. See docks about it here
Extract bitmap decoding logic to a separate class, extract interface and provide
different implementation at run time.

Related

Android: Should I use AsyncTask for these two operations?

I have these next two methods, takescreenshots and saveScreenshot:
public static Bitmap takeScreenshot(View oView)
{
Bitmap oBitmap = null;
if(oView!=null) {
if (oView.getWidth()>0 & oView.getHeight()>0) {
oBitmap = Bitmap.createBitmap(oView.getWidth(),
oView.getHeight(), Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(oBitmap);
try{
oView.draw(canvas);
}catch (Exception ex){
//log or whatever
}
}
}
return oBitmap;
}
public static File saveScreenshot(Bitmap oBitmap)
{
String mPath = ApplicationContext.getActivity().getCacheDir().getAbsolutePath() + "/artandwordsshared_img.jpg";
File imageFile = new File(mPath);
try{
boolean operationOK = true;
if (imageFile.exists()){
operationOK = imageFile.delete();
}
if (operationOK) {
operationOK = imageFile.createNewFile();
}
if (operationOK) {
FileOutputStream outputStream = new FileOutputStream(imageFile);
int quality = 75;
oBitmap.compress(Bitmap.CompressFormat.JPEG, quality, outputStream);
outputStream.flush();
outputStream.close();
}
}catch(java.io.IOException ex){
ex.printStackTrace();
}
return imageFile;
}
I use this "takeScreenshot" method to capture a view (I use it in some parts of my app) and the other one to save screenshot on device, and I'd like to know if I must/should (regarding good practices) call them through an AsyncTask so they run on background, or if it is not necessary at all. I'm currently using AsyncTask for both and all it's working just fine, but not sure if it is really a must, like it is, for example, for network operations.
Thank you in advance.
Edit 1: Adding the AsyncTask "TakeScreenshot" class.
class TakeScreenshot extends AsyncTask<String, Void, ImageProcessingResult>
{
private WeakReference<View> view2Capture;
private ImageListeners listener;
private String asyncTaskCaller;
TakeScreenshot(View view2Capture, ImageListeners listener, String asyncTaskCaller)
{
this.listener = listener;
this.view2Capture = new WeakReference<>(view2Capture);
this.asyncTaskCaller = asyncTaskCaller;
}
protected ImageProcessingResult doInBackground(String... urls)
{
Bitmap bitmap = null;
String result = Enum.Result.KO;
if(view2Capture.get()!=null)
{
bitmap = ImageHelper.takeScreenshot(view2Capture.get());
result = ImageHelper.saveBitmap(bitmap);
}
return new ImageProcessingResult(bitmap, result);
}
protected void onPostExecute(ImageProcessingResult ipr)
{
listener.onScreenCaptureFinished(ipr, asyncTaskCaller);
}
}
BTW, as for now takeScreenshot method called from AsyncTask is working just fine. Just trying to use good practices, and that's why my post.
I'm not sure you will be able to call first function takeScreenshot in the background Thread. Because you are performing operation with UI Draw. In any case, it makes no sense to put this small implementation to the background.
Next function saveScreenshot must be defined in the background Thread for sure. You need to eliminate the jank on UI which you would have because of using in in the foreground. Maybe you will not feel difference on new devices, but in some condition/platforms you will.
UPDATE
Seems like you new to the Android. Of course you can use AsyncTask, but people prefer other tools. AsyncTask is very old and nowadays there are bunch of alternatives. Just try to search for it.
On another hand. AsyncTask based on Java Executors(which includes ThreadPool, "Handler", MessageQueue, etc). For simple actions like yours, you can use just Thread. Clean and simple.
//Just make it once
private final Handler ui = new Handler(
Looper.getMainLooper());
//Whenever you need just call next call
new Thread("Tag").start(() -> {
//Background Work
//Whenever you need to submit something to UI
ui.post(() -> {
// Foreground Work
});
}
})

"Quickblox" android SDK returns null InputStream in CustomObject.downloadFile

I am stuck in a problem that when I call CustomObject.downloadFile method to download a file it returns success but in the callback in onSuccess the InputStream has 0 size which means its null. Below is my code snippet:
QBCustomObject qbCustomObject = new QBCustomObject(Constants.MODULE_1_QUESTIONS,currentQuesData.getQ_id());
QBCustomObjectsFiles.downloadFile(qbCustomObject, "q_image", new QBEntityCallback<InputStream>() {
#Override
public void onSuccess(InputStream inputStream, Bundle bundle) {
Toast.makeText(mainActObj,"succes",Toast.LENGTH_SHORT).show();
Bitmap imageContent = BitmapFactory.decodeStream(inputStream);
}
#Override
public void onError(QBResponseException e) {
Toast.makeText(mainActObj,"error",Toast.LENGTH_SHORT).show();
}
});
Thanks in advance.
how did you find out
InputStream has 0 size
maybe BitmapFactory can't decode your image from InputStream? Did you check this issue on other images?

Running code from another class

hi I'm new to android programming and I'm creating an app that part of it generate Qrcode by using The Zxing library
I created a class with a method Encode contains block of code that generate the qrcode
public void Encode(String Text_To_Encode )
{
final ImageView imageView = (ImageView) findViewById(R.id.QrImageView);
String qrData = "Ahmed";
int qrCodeDimention = 500;
QRCodeEncoder qrCodeEncoder = new QRCodeEncoder(qrData, null,
Contents.Type.TEXT, BarcodeFormat.QR_CODE.toString(), qrCodeDimention);
try {
Bitmap bitmap = qrCodeEncoder.encodeAsBitmap();
imageView.setImageBitmap(bitmap);
} catch (WriterException e) {
e.printStackTrace();
}
}
Whenever I call this method in Oncreate() method in MainActivity the app Unfortunately has stopped
but when I take this block of code and run it directly in the MainActivity it runs perfectly
I need to know what I do wrong ....
From normal class use Activity context to access views :
public void Encode(String Text_To_Encode,Activity activity )
{
final ImageView imageView =
(ImageView)activity.findViewById(R.id.QrImageView);
.....
}
From Activity call Encode method by passing Activity context:
Encode(Text_To_Encode,ActivityName.this)
Your problem is in this line of code: final ImageView imageView = (ImageView) findViewById(R.id.QrImageView);
You see, you're trying to modify ONE SPECIFIC ImageView. That ImageView belongs to an Activity or Fragment, not to the Application. When you call that method in any Activity or Fragment that R.id.QrImageView does not exist, it will crash because it can't find the ImageView (which is because that ImageView is out-of-scope).
To solve this problem, I would improve your code by RETURNING THE BITMAP in the method.
To be clear, your method should look like this:
public Bitmap Encode(String Text_To_Encode )
{
String qrData = "Ahmed";
int qrCodeDimention = 500;
QRCodeEncoder qrCodeEncoder = new QRCodeEncoder(qrData, null,
Contents.Type.TEXT, BarcodeFormat.QR_CODE.toString(), qrCodeDimention);
try {
return qrCodeEncoder.encodeAsBitmap();
} catch (WriterException e) {
e.printStackTrace();
}
}
Now, in your Activity or Fragment, simply use imageView.setImageBitmap(qrClass.encode(String textToEncode));

Android OOM errors due to image cacheing?

It will be a little easier to understand this if you think if the app I'm working on like facebook (at least that will give you a context for what i'm doing). I have one activity that uses a navigationdrawer to swap between fragments each of these fragments could have from one to several "subFragments" --- think of these as individual posts with things like a textview, a few buttons and an ImageView in them. When the "container fragment" is created I call to the server and get the data I need to make all the "sub fragments". I then iterate through the data and add all the "sub fragments" to the "container fragment"'s view.
I have noticed that I seem to be using an excessively high amount of memory (around 129 mb).
When the subfragments are created I then call this async task which pulls the images each fragment will need from a server and places them in their ImageView.
public class URLImageFactory extends AsyncTask<String, Void, Bitmap>
{
ImageView imgView;
private static final ImgCache mCache = new ImgCache();
public URLImageFactory(ImageView bmImage) {
this.imgView = bmImage;
}
#Override
protected Bitmap doInBackground(String... urls) {
String urldisplay = Config.SERVER_URL + urls[0].replaceAll("\\s+","%20");
Bitmap bitmap = null;
//If it is in the cache don't bother pulling it from the server
if(bitmap != null)
{
return bitmap;
}
try {
InputStream in = new java.net.URL(urldisplay).openStream();
//This is in case we are using match_parent/wrap content
if(imgView.getWidth() == 0 || imgView.getHeight() == 0)
{
bitmap = BitmapFactory.decodeStream(in);
} else {
bitmap = Bitmap.createScaledBitmap(BitmapFactory.decodeStream(in),
imgView.getWidth(), imgView.getHeight(), false);
}
mCache.put(urldisplay,bitmap);
} catch (Exception e) {
Log.e("Error", e.getMessage());
e.printStackTrace();
}
return bitmap;
}
#Override
protected void onPostExecute(Bitmap result) {
imgView.setImageBitmap(result);
}
}
I have made a rudimentary attempt at caching the images to speed up the process
public class ImgCache extends LruCache {
public ImgCache() {
super( calculateCacheSize() );
}
public static int calculateCacheSize()
{
int maxMemory = (int) Runtime.getRuntime().maxMemory() / 8;
int cacheSize = maxMemory;
return cacheSize;
}
#Override
protected int sizeOf( String key, Bitmap value ) {
return value.getByteCount() / 1024;
}
}
My app is crashing with outOfMemory exception. I have also noticed that when my "container fragment" is swapped out for a different one ... usually a similarly structured fragment... the onPause() and onStop() of these sub fragments are not being fired. If it helps the sub fragments are static inner classes while the container fragment is not. I think it is a bitmap related issue, but I'm not sure. I have attempted to use TransactionManager.remove(fragment) on all the sub fragments when the parent hits onPause but it doesn't seem to help.
You're dividing the byte count of each object by 1024, but only dividing the available memory by 8; the result is that the LRU cache could fill up to 128 times the amount of available memory you have. Remove the / 1024 from sizeOf and you should be good.

Libgdx getting Image from facebook at runtime

I have image-url getting from facebook, I want to display that image at runtine in my game in libgdx.I am using facebook graph api and parse data with help of Json parsing. my approach is as follows:
In main activity
protected void gettingfacebookData() {
try {
JSONArray friendArray = new JSONArray(
prefLevel.getFriendFacebookData());
for (int i = 0; i < friendArray.length(); i++) {
JSONObject jsonObject = friendArray.getJSONObject(i);
String name = jsonObject.getString("name");
String score = jsonObject.getString("score");
String fid = jsonObject.getString("fid");
String image = "http://graph.facebook.com/" + fid
+ "/picture?type=large";
//saving score into array list
PlayingScreen.scoreAl.add(score);
//saving image url into arraylist
PlayingScreen.imageUrlAl.add(image);
} }
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
Now how can I display image at run time with this particular image url?
We use a wrapper class, that wraps Texture, for displaying images from web (like facebook profile pictures). This wrapper class takes url of the image and a temporary texture. Just as the wrapper is created, it starts to download image bytes in a background thread. Consumer of this wrapper class simply calls getTexture() to obtain texture and until download has finished, this method returns the temporary texture. When there are bytes available to create a texture getTexture() processes this bytes and starts to return new texture created from url.
Below is a simple version of this wrapper class. Note that, processTextureBytes is called inside getTexture method, not somewhere in background thread. It is because we have to construct texture in the thread which obtains the GLContext. You can add caching and retry mechanisms to this class.
BTW, instead of using http://graph.facebook.com/[uid]/picture url try using one of pic_ urls from FQL. You may want to check this.
public class WebTexture {
private final String url;
private Texture texture;
private volatile byte[] textureBytes;
public WebTexture(String url, Texture tempTexture) {
this.url = url;
texture = tempTexture;
downloadTextureAsync();
}
private void downloadTextureAsync() {
Utils.runInBackground(new Runnable() {
#Override
public void run() {
textureBytes = downloadTextureBytes();
}
});
}
private byte[] downloadTextureBytes() {
try {
return Utils.downloadData(url);
} catch (IOException e) {
e.printStackTrace();
return null;
}
}
public Texture getTexture() {
if (textureBytes != null)
processTextureBytes();
return texture;
}
private void processTextureBytes() {
try {
Pixmap pixmap = new Pixmap(textureBytes, 0, textureBytes.length);
Texture gdxTexture = new Texture(pixmap);
gdxTexture.setFilter(TextureFilter.Linear, TextureFilter.Linear);
texture = gdxTexture;
} catch (Throwable t) {
t.printStackTrace();
} finally {
textureBytes = null;
}
}
}
You should download the image.
Once you have your image as a byte array, you can create a pixmap:
Pixmap pixmap = new Pixmap(imageBytes, 0, imageBytes.length);
Then you can use this pixmap to render the image. For example if are you using scene2d.ui you can set Image's drawable as follows:
image.setDrawable(new TextureRegionDrawable(new TextureRegion(new Texture(profilePicture))));
Hope this helps.

Categories

Resources