I'm new to coding for Android, and I need some help with the same.
I made a Live Wallpaper 1080x1920 and it works well on my Z2 and OPO. However, I cannot figure out how to resize it when it runs on any other resolution. Any help is appreciated.
Thanks.
Make a still wallpaper in vector and try it out, if a still vector image is resizeable, then u won't have problem with moving wallpapers.
If you use OpenGl just resize your viewport accordingly and everything should work fine.
Here you go
public static Bitmap resizeBitmapAccordingToDevice(Context context,int id_res) {
DisplayMetrics displayMetrics = context.getResources().getDisplayMetrics();
Bitmap bitmap = BitmapFactory.decodeResource(context.getResources(), id_res);
return getResizedBitmap(bitmap,displayMetrics.widthPixels,displayMetrics.heightPixels);
}
public static Bitmap getResizedBitmap(Bitmap bm, int newWidth, int newHeight) {
int width = bm.getWidth();
int height = bm.getHeight();
float scaleWidth = ((float) newWidth) / width;
float scaleHeight = ((float) newHeight) / height;
// CREATE A MATRIX FOR THE MANIPULATION
Matrix matrix = new Matrix();
// RESIZE THE BIT MAP
matrix.postScale(scaleWidth, scaleHeight);
// "RECREATE" THE NEW BITMAP
Bitmap resizedBitmap = Bitmap.createBitmap(
bm, 0, 0, width, height, matrix, false);
bm.recycle();
return resizedBitmap;
}
Sent from my SM-G530H using XDA Free mobile app
Related
Hi folks,
i've got a problem while developing my "learning app". just developing it to learn how to solve things on windows mobile... blah.. to the problem.
When loading & drawing an image into my app it reduces the colors of at least one image so it looks kind of crap.
The used image is a jpeg file loaded into an IImage via IImagingFactory.
Screenshot: http://img22.yfrog.com/i/myappr.jpg/ (how it looks)
Background: http://img36.yfrog.com/i/backgroundwzu.jpg/ (how it should look lke)
Most interesting parts of the class i wrote for drawing all that stuff:
Code:
#include "stdafx.h"
#include <imaging.h>
#include <initguid.h>
#include <imgguids.h>
#include <aygshell.h>
class gfx
{
public:
gfx(void) {
CoInitializeEx(NULL, COINIT_MULTITHREADED);
if (SUCCEEDED(CoCreateInstance (CLSID_ImagingFactory,
NULL,
CLSCTX_INPROC_SERVER,
IID_IImagingFactory,
(void **)&this->pImgFactory)))
{
// Initialize backbuffer
this->hdcBackbuffer = NULL;
this->hdcArtwork = NULL;
this->bmBackbuffer = CreateBitmap( 480, 536, 1, 16, NULL);
this->bmArtwork = CreateBitmap( 480, 536, 1, 16, NULL);
// Do some unrelated initialisation assignments ....
// Done! :D
// Load images
if (!SUCCEEDED(this->pImgFactory->CreateImageFromFile(TEXT("\\Program Files\\ForsakenToday\\Background.jpg"), &this->pImageBackground))) return;
// Load some more images
// Loading done, ready to draw.
this->bReady = true;
}
};
bool Draw(HDC hdc, RECT *rc_update) {
if (this->bReady) {
this->rgnUpdate = CreateRectRgn(rc_update->left, rc_update->top, rc_update->right, rc_update->bottom);
if (this->hdcArtwork == NULL) {
RECT rc_background = {0, 0, 480, 536};
RECT rc_clock = {80, 0, 400, 96};
this->hdcArtwork = CreateCompatibleDC(hdc);
SelectObject(this->hdcArtwork, this->bmArtwork);
this->gDrawImage(this->hdcArtwork, rc_background, this->pImageBackground);
this->gDrawImage(this->hdcArtwork, rc_clock, this->pImageClock);
}
if (this->hdcBackbuffer == NULL) {
this->hdcBackbuffer = CreateCompatibleDC(hdc);
SelectObject(this->hdcBackbuffer, this->bmBackbuffer);
}
SelectClipRgn(this->hdcBackbuffer, this->rgnUpdate);
BitBlt(this->hdcBackbuffer, rc_update->left, rc_update->top, (rc_update->right-rc_update->left), (rc_update->bottom-rc_update->top),
this->hdcArtwork, rc_update->left, rc_update->top, SRCCOPY);
// Painting all that overlaying stuff that changed ...
// Done! :D
BitBlt(hdc, rc_update->left, rc_update->top, (rc_update->right-rc_update->left), (rc_update->bottom-rc_update->top),
this->hdcBackbuffer, rc_update->left, rc_update->top, SRCCOPY);
return true;
}
return false;
};
void gDrawImage(HDC hdc, RECT rc, IImage *pImage) {
pImage->Draw(hdc, &rc, NULL);
};
}
If i forgot anything, tell me
I would be happy about to know where exactly the image's colors are reduced and/or how to prevent this.
Best regards
Jens
Ultimate answer to your problem lays in fact that Windows Mobile can display only 65536 colors. This is 16 bits per pixel, and pixel color is coded R5 G6 B5, meaning 5 bits for red and blue, and 6 for green, which gives 32 red levels, 64 green levels and 32 blue levels (this makes 32*64*32 = 65536 possible colors). Not bad, BUT... when comes to grayscale, there's a small problem - since "gray levels" are made in RGB using same level for R, G and B (for example, gray level 15 in RGB is 15-15-15). Because of that, you can have only 32 gray levels! And what you see in your app is approximation of each pixel to one of those 32 gray levels... So only thing you can do is to save this image with 16-bit color and use dithering to improve color representation, but I don't know app that can do so... If you find one, please tell me...
This is the best dithering I can get, but this is not 16-bit, it's dithering on 256 color Mac palette:
Ah okay that explains why all other (colored) images look fine...
thanks for your quick reply
Actually, any gradient image will look crappy because of this...
As for now, only solution is to dither it or avoid gradients...
Hi All,
I am attempting to generate a signal at a dynamically chosen frequency (i.e. 50-20000 Hz approx.) I am starting to get frustrated. I've read the documentation over and over again, looked at numerous examples and forum posts but have not resolved the problem.
The code works BUT the signal is not stable going up and down slightly.
Code:
final float frequency = freq;
float increment = (float)((2*Math.PI) * frequency / 44100); // angular increment for each sample
float angle = 0;
AndroidAudioDevice device = new AndroidAudioDevice( );
float samples[] = new float[1024];
while(threadIsRunning)
{
for( int i = 0; i < samples.length; i++ )
{
samples[i] = (float)Math.sin( angle );
angle += increment;
}
device.writeSamples( samples );
}
and the the AndroidAudioDevice Class is as follows:
Code:
import android.media.AudioFormat;
import android.media.AudioManager;
import android.media.AudioTrack;
public class AndroidAudioDevice {
AudioTrack track;
short[] buffer = new short[1024];
public AndroidAudioDevice( )
{
int minSize =AudioTrack.getMinBufferSize( 44100, AudioFormat.CHANNEL_CONFIGURATION_MONO, AudioFormat.ENCODING_PCM_16BIT );
track = new AudioTrack( AudioManager.STREAM_MUSIC, 44100,
AudioFormat.CHANNEL_CONFIGURATION_MONO, AudioFormat.ENCODING_PCM_16BIT,
minSize, AudioTrack.MODE_STREAM);
track.play();
}
public void writeSamples(float[] samples)
{
fillBuffer( samples );
track.write( buffer, 0, samples.length );
}
private void fillBuffer( float[] samples )
{
if( buffer.length < samples.length )
buffer = new short[samples.length];
for( int i = 0; i < samples.length; i++ )
buffer[i] = (short)(samples[i] * Short.MAX_VALUE);
}
public void releaseTrack(){
track.release();
}
}
Where is the problem here? Is there an alternative way of solving this problem?
I would very much appreciate if you were able to help, even if its only a pointer in the right direction! Have lost a lot of hours over this puppy.
-Thanks in advance
do you really need a wavelike form? why not just plot each point as Y-axis and keep the x as time...just do it really fast and you get a wave-sorta.....
-hope i helped
? I'm not exactly sure what you mean. I am essentially plotting a wave function, just filling a buffer "x-axis" with "y-axis" the sine values.
You actually are not creating a perfect sin wave because the samples array does not have a complete period.
According your code you need frequency * 44100 samples to have the entire period.
Your actual implementation create a wave that does not match the end of samples array with the beginning of the next samples array sent to the device, it creates a little peak and it is what you notice.
Could you please expand on that Alerias.The way I see it the samples don't contain a full sine wave but they do keep going where they left of from one sample to the next. And I don't think there should be a peak changing from one sample to the next.
Code:
angle += increment;
The angle Variable is continuously and uniformly incremented. So if the sample a's last entry is
Code:
samples[i] = (float)Math.sin( angle );
The first entry of the next sample will be
Code:
samples[i] = (float)Math.sin( angle +increment);
I therefore don't see a discontinuity. The angle variable does not get re-initiated to 0.
Thanks a lot,
FlyingSwissman
I want to share some codes of a small effect that I implemented in my Android app called Arithmetic Puzzles. This is also a chance for me to listen to other people and make improvements. At the end of this post there is a link to the app so that you can see the code in action.
It is a pseudo-3D effect of the playing board items which are looking like rotating slightly based on your viewing angle when you move the device. The effect is not something of very visible but this small non-disturbing animations usually please the user and make the app look cooler.
Why I call it "pseudo"? Because there is no 3D animation behind, and not even a View animation like rotation around some axis or so. The solution is really simple - I just change the border of the item on gyroscope events which somehow fakes the viewing angle change.
The board item is a simple round rectangle and its border is drawn with a gradient of white color going to transparent. This creates the "fake viewing angle" effect.
So here is our BoardItemView class which is just a simple View:
Code:
public class BoardItemView extends View {
// the color of the board itself (blue)
private int mBoardBack;
// the color of the border (white)
private int mBorderColor;
// the color of the gradient end (transparent)
private int mGradientEndColor;
// constructors
public ToolboxItemView(Context context) {
super(context);
init(context);
}
public ToolboxItemView(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
}
private void init(Context context) {
// initialize the colors
Resources r = context.getResources();
mBorderColor = r.getColor(R.color.item_border);
mBoardBack = r.getColor(R.color.item_background);
int transparent = r.getColor(android.R.color.transparent);
setBackgroundColor(transparent);
mGradientEndColor = transparent;
}
As you see, there is nothing special about its initialization. I skipped the other member variables so that it doesn't have any info that is not yet needed for understanding, I will add them later.
Let's go to the onDraw() function:
Code:
...
private static final float RECT_PADDING_PERCENTAGE = 0.05f;
private static final float RECT_RADIUS_PERCENTAGE = 0.1f;
private RectF mRoundRect = new RectF();
private Rect mBounds = new Rect();
private float mRadius = 0.0f;
...
@Override
protected void onDraw(Canvas canvas) {
// step 1: collect information needed for drawing
canvas.getClipBounds(mBounds);
float padding = mBounds.height() * RECT_PADDING_PERCENTAGE;
mRoundRect.set(mBounds);
mRoundRect.inset(padding, padding);
mRadius = RECT_RADIUS_PERCENTAGE * mBounds.height();
...
In the first lines of onDraw() I am taking the clip bounds with getClipBounds() function - I need it to understand where I should do my drawing. My experience showed that it is a good idea to get clip bounds, usually you draw between (0, 0) and (width, height), but I have seen some ugly cases (when I was dealing with Android's Launcher codes) where this is not true.
Then I calculate the round rect parameters, like size and corner radius. As you noticed, no "new" calls in onDraw(), all the needed variables are kept as data members and created when this View is instantiated.
Next comes the drawing of the board itself, nothing special:
Code:
...
private Paint mRectPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
...
@Override
protected void onDraw(Canvas canvas) {
...
// step 2: draw the background fill
mRectPaint.setShader(null);
mRectPaint.setDither(false);
mRectPaint.setStyle(Paint.Style.FILL);
mRectPaint.setColor(mBoardBack);
canvas.drawRoundRect(mRoundRect, mRadius, mRadius, mRectPaint);
...
As you can see, I am just drawing a board item as a round rectangle. Before drawing I am setting up the Paint: setting shader to null, dither to false, style to FILL and color to mBoardBack (blue). I will explain the shader and dither in the next step where they are being set. Here I just need to reset (disable) them back. Style is set to FILL so that any shape I paint is also filled with the color of the Paint.
Let's go to the border part, which is interesting:
Code:
...
private LinearGradient mBorderGradient;
...
@Override
protected void onDraw(Canvas canvas) {
...
// step 3: draw the background border
mRectPaint.setStyle(Paint.Style.STROKE);
mRectPaint.setColor(mBorderColor);
createGradient();
mRectPaint.setDither(true);
mRectPaint.setShader(mBorderGradient);
canvas.drawRoundRect(mRoundRect, mRadius, mRadius, mRectPaint);
// step 4: draw the content of a board item here, like text, image, etc...
}
First of all, I am setting the paint style to STROKE. This means that any shape I draw will not be filled with the color, only the border will be drawn. There is also FILL_AND_STROKE style which both draws the border of the shape and fills it with the paint (remember that in previous step we just filled the round rectangle). Since I am not setting the width of the border stroking it will be just one pixel wide. This is enough to see the effect and not big enough for eyes to see the "pseudo"-ness of the 3D effect.
After that I am setting the color of the Paint and then calling a createGradient() function. We will come to that function in a few minutes. Then I am enabling the dither mode on the Paint and setting a shader on it to be the gradient that I just created with that createGradient() function call.
What does all that mean and what is a Shader in Android's Paint system? Its basically quite simple - a Shader is an object from where the Paint gets color information during drawing any shape (except drawing bitmaps). When the shader is null then the Paint object uses the color it was set, otherwise it asks the Shader object what color to use when painting a pixel at some coordinate. As an example you can see a picture acting as a shader and what will happen if a Paint will draw letter 'R' using that shader.
{
"lightbox_close": "Close",
"lightbox_next": "Next",
"lightbox_previous": "Previous",
"lightbox_error": "The requested content cannot be loaded. Please try again later.",
"lightbox_start_slideshow": "Start slideshow",
"lightbox_stop_slideshow": "Stop slideshow",
"lightbox_full_screen": "Full screen",
"lightbox_thumbnails": "Thumbnails",
"lightbox_download": "Download",
"lightbox_share": "Share",
"lightbox_zoom": "Zoom",
"lightbox_new_window": "New window",
"lightbox_toggle_sidebar": "Toggle sidebar"
}
Seems like there are fixed number of shaders in Android, although BitmapShader is covering almost all of the possibilities. In my case I use LinearGradient class which extends Shader class.
TO BE CONTINUED in the thread, seems there is limit on post size...
...CONTINUATION of the original post.
We also set dither to 'true'. It is always a good idea to set dither to true when you are drawing gradients. For more information you can go here where this famous Android Guy is showing some examples of dithering.
Lets go to the createGradient() function:
Code:
...
private Float mXAngle = null;
private Float mYAngle = null;
...
private void createGradient() {
if (mBounds.height() == 0) {
return;
}
int startColor = mBorderColor;
float x0 = mBounds.left;
float y0 = mBounds.bottom;
float x1 = mBounds.right;
float y1 = mBounds.top;
if (mXAngle != null && mYAngle != null) {
if (mXAngle == 0 && mYAngle == 0) {
startColor = mGradientEndColor;
} else {
float h = mBounds.height();
float w = mBounds.width();
float radius = (float) Math.sqrt(h * h + w * w) / 2.0f;
float norm = radius / (float) Math.sqrt(mXAngle * mXAngle + mYAngle * mYAngle);
x0 = mBounds.centerX() + mXAngle * norm;
y0 = mBounds.centerY() + mYAngle * norm;
x1 = mBounds.centerX() - mXAngle * norm;
y1 = mBounds.centerY() - mYAngle * norm;
}
}
mBorderGradient = new LinearGradient(x0, y0, x1, y1,
startColor, mGradientEndColor, Shader.TileMode.CLAMP);
}
The variables mXAngle and mYAngle are set from outside using gyroscope data. We will come to that later. Now think of them as of a vector - they are showing a direction. We are using this direction as a direction of our gradient.
In order to fully define a linear gradient we need 2 (x,y) points on the plane - a start point and end point as shown in the picture below.
Note that these points should be in the coordinate system of the view, that is why are using mBounds variable. The shader mode is set to CLAMP so that outside these bounds the color of the corresponding point is used.
Then comes some math. We set the default "view angle" to the direction from left-bottom to top-right. After that, if there is a direction set, we calculate these 2 gradient points as an intersection of the rectangle's outer circle and the direction line passing through the center of the rectangle. If the direction vector is zero then both gradient colors are set to transparent and no border is drawn (view angle "from top"). First we calculate the radius of rectangle's outer circle - the distance from the center of the rectangle to its corners. Then we calculate a normalization factor and finally put the view direction vector in the center of the rectangle and multiply by normalization factor in order to put its endpoint on the outer circle. The gradient is ready.
In the picture below you can see the result of drawing a round rectangle border with a linear gradient shader:
The final step is to set the "view angle" based on gyroscope values:
Code:
public void onGyroChanged(float xAngle, float yAngle) {
mXAngle = xAngle;
mYAngle = yAngle;
invalidate();
}
This function sets the new angle values and calls invalidate() to redraw self.
The gyroscope processing is out of the scope of this post, so I will just paste the code here. It is mostly copied from Android documentation:
Code:
public class GyroHelper implements SensorEventListener {
private static final float NS2S = 1.0f / 1000000000.0f;
private Display mDisplay;
private boolean mStarted = false;
private SensorManager mManager;
private long mLastTime = 0;
private float mAngleX = 0.0f;
private float mAngleY = 0.0f;
public GyroHelper(Context c) {
mManager = (SensorManager) c.getSystemService(Context.SENSOR_SERVICE);
WindowManager wm = (WindowManager) c.getSystemService(Context.WINDOW_SERVICE);
mDisplay = wm.getDefaultDisplay();
}
public static boolean canBeStarted(Context c) {
SensorManager manager = (SensorManager) c.getSystemService(Context.SENSOR_SERVICE);
return manager.getDefaultSensor(Sensor.TYPE_GYROSCOPE) != null;
}
public void start() {
mStarted = false;
Sensor sensor = mManager.getDefaultSensor(Sensor.TYPE_GYROSCOPE);
if (sensor == null) {
return;
}
mStarted = true;
reset();
mManager.registerListener(this, sensor, SensorManager.SENSOR_DELAY_UI);
}
public void stop() {
mStarted = false;
reset();
mManager.unregisterListener(this);
}
public boolean isStarted() {
return mStarted;
}
public float getXAngle() {
switch (mDisplay.getRotation()) {
case Surface.ROTATION_0: return -mAngleY;
case Surface.ROTATION_90: return -mAngleX;
case Surface.ROTATION_180: return mAngleY;
case Surface.ROTATION_270: return mAngleX;
}
return mAngleX;
}
public float getYAngle() {
switch (mDisplay.getRotation()) {
case Surface.ROTATION_0: return -mAngleX;
case Surface.ROTATION_90: return mAngleY;
case Surface.ROTATION_180: return mAngleX;
case Surface.ROTATION_270: return -mAngleY;
}
return mAngleY;
}
@Override
public void onSensorChanged(SensorEvent event) {
if (mLastTime != 0) {
final float dT = (event.timestamp - mLastTime) * NS2S;
mAngleX += event.values[0] * dT;
mAngleY += event.values[1] * dT;
}
mLastTime = event.timestamp;
}
@Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
}
private void reset() {
mLastTime = 0;
mAngleX = 0.0f;
mAngleY = 0.0f;
}
}
Somebody needs to start this GyroHelper and periodically call BorderItemView.onGyroChanged(GyroHelper.getXAngle(), GyroHelper.getYHelper()). That can be done right when onSensorChanged() is fired, but it is not a good idea since that can be too often, you might want to have your own timer controlling your frame rate, sensor updates can come 200 times in a second.
Finally, to see this code in action, you can have a look at the app itself, its free:
Google Play:
Direct link:
Download
It would be nice to get some comments and suggestions, let me know your thoughts!
I'm making an app for a friends gym that has a BMI and BMR calculator. It works but if any editText field is left blanc the app crashes.
It crashes once I press the "male" button...
Code:
View rootView = inflater.inflate(R.layout.fragment_bmr, container, false);
//step2 : get all the views from xml file.
feet = (EditText) rootView.findViewById(R.id.feet);
inch = (EditText) rootView.findViewById(R.id.inch);
weight = (EditText) rootView.findViewById(R.id.weight2);
age = (EditText) rootView.findViewById(R.id.age2);
bmr = (TextView) rootView.findViewById(R.id.editText3);
male = (Button) rootView.findViewById(R.id.male);
b2 = (Button) rootView.findViewById(R.id.female);
//step3 : write add functionality.
male.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
String f = feet.getText().toString();
int feet = Integer.parseInt(f);
String i = inch.getText().toString();
int inch = Integer.parseInt(i);
String w = weight.getText().toString();
int weight = Integer.parseInt(w);
String a = age.getText().toString();
int age = Integer.parseInt(a);
double result = 66+(6.23*weight)+(12.7*(feet*12+inch))-(6.8*age);
result = Math.round(result*10.0)/10.0;
String res = String.valueOf(result);
bmr.setText(res);
}
});
I don't post code on here much so if did it wrong I'd appreciate if someone corrects me
Sent from my Nexus 6 using XDA Free mobile app
jeb192004 said:
I'm making an app for a friends gym that has a BMI and BMR calculator. It works but if any editText field is left blanc the app crashes.
It crashes once I press the "male" button...
Code:
View rootView = inflater.inflate(R.layout.fragment_bmr, container, false);
//step2 : get all the views from xml file.
feet = (EditText) rootView.findViewById(R.id.feet);
inch = (EditText) rootView.findViewById(R.id.inch);
weight = (EditText) rootView.findViewById(R.id.weight2);
age = (EditText) rootView.findViewById(R.id.age2);
bmr = (TextView) rootView.findViewById(R.id.editText3);
male = (Button) rootView.findViewById(R.id.male);
b2 = (Button) rootView.findViewById(R.id.female);
//step3 : write add functionality.
male.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
String f = feet.getText().toString();
int feet = Integer.parseInt(f);
String i = inch.getText().toString();
int inch = Integer.parseInt(i);
String w = weight.getText().toString();
int weight = Integer.parseInt(w);
String a = age.getText().toString();
int age = Integer.parseInt(a);
double result = 66+(6.23*weight)+(12.7*(feet*12+inch))-(6.8*age);
result = Math.round(result*10.0)/10.0;
String res = String.valueOf(result);
bmr.setText(res);
}
});
I don't post code on here much so if did it wrong I'd appreciate if someone corrects me
Sent from my Nexus 6 using XDA Free mobile app
Click to expand...
Click to collapse
I'm guessing its because you can't parseInt on an empty string (or one that's not an integer). You need to run an assert on your strings to make sure its not null.
Sorry empty string is not null. There will be parseInt error on string and not null pointer exception.
@jeb192004
Check if input string is numeric then do parseInt.
Note:
This answer was not to Jonny.
Sent from my XT1033 using XDA Free mobile app
I did this:
Code:
male.setOnClickListener(new OnClickListener() { [user=439709]@override[/user]
public void onClick(View v) {
String f = feet.getText().toString();
String i = inch.getText().toString();
String w = weight.getText().toString();
String a = age.getText().toString();
if(feet.getText().toString().equals("") ){
feet.setError("Please Fill Out Your Height");}
else if(inch.getText().toString().equals("") ){
inch.setError("Please Fill Out Your Height");}
else if(weight.getText().toString().equals("") ){
weight.setError("Please Fill Out Your weight");}
else if( age.getText().toString().equals(""))
{
age.setError("Please Fill Out Your Age");
}
else{
int feet = Integer.parseInt(f);
int inch = Integer.parseInt(i);
int weight = Integer.parseInt(w);
int age = Integer.parseInt(a);
double result = 66+(6.23*weight)+(12.7*(feet*12+inch))-(6.8*age);
result = Math.round(result*10.0)/10.0;
String res = String.valueOf(result);
bmr.setText(res);
}
}
});
[\CODE]
I did this a different way at first, using "||" between each if/else if statement instead of the if/else if between each one and it worked except for my "inch" edittext. That one still made the app crash. Doing it the way I have shown works but my error message doesn't always show up. Sometimes I have to click the edit text field for it to show up. The red dot does show up in the text field every time tho.
It took a bit of searching to figure out what you guys were talking about and how to get it to work. I'm really new to this and learning as I go. Doing this more as a hobby...
Sent from my Nexus 6 using XDA Free mobile app
I surround mine with a try/catch. Then if the edittext is blank, I prompt the user with a toast to input something, even a zero. Might not be the best way, but hey, I'm a F'n noob....
Hi, on my gridview (like a gallery images) i can show photos on sd card, but some pictures aren't shown by the grid. But if i tap on it i can show it, it exist obviously. So i have some white square instead of the "preview" of the image. It would seem it doesn't load.
Can someone help me?
Are you getting any errors in LogCat? like bitmap too large?
Can you post your image loading code? wo that it's pretty difficult to know what the issue is.
registered-user said:
Are you getting any errors in LogCat? like bitmap too large?
Can you post your image loading code? wo that it's pretty difficult to know what the issue is.
Click to expand...
Click to collapse
I don't have errors in logcat, my image loading code is:
new AsyncTask<ViewHolder, Void, Bitmap>() {
private ViewHolder v;
@override
protected Bitmap doInBackground(ViewHolder... params) {
Bitmap bm = null;
boolean haveThumbNail = false;
try {
ExifInterface exifInterface =
new ExifInterface(imageList.get(position));
if(exifInterface.hasThumbnail()){
byte[] thumbnail = exifInterface.getThumbnail();
bm = BitmapFactory.decodeByteArray(thumbnail, 0, thumbnail.length);
}
haveThumbNail = true;
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if(!haveThumbNail){
bm = decodeSampledBitmapFromUri(
imageList.get(position), 220, 220);
}
v = params[0];
return bm;
}
protected void onPostExecute(Bitmap result) {
super.onPostExecute(result);
v.image.setImageBitmap(result);
}
}.execute(holder);
return convertView;
}
That looks OK but you're loading images in a list/grid? Instead of passing in your ViewHolder you should probably only pass the ImageView and use a WeakReference.
Example here: https://developer.android.com/training/displaying-bitmaps/process-bitmap.html
If you skip the ExifInterface.getthumbnail() do images display correctly? Maybe the Exif data is incorrect?
registered-user said:
That looks OK but you're loading images in a list/grid? Instead of passing in your ViewHolder you should probably only pass the ImageView and use a WeakReference.
Example here: https://developer.android.com/training/displaying-bitmaps/process-bitmap.html
If you skip the ExifInterface.getthumbnail() do images display correctly? Maybe the Exif data is incorrect?
Click to expand...
Click to collapse
First of change a lot of code i would want to solve it simply if it is possible. With debugging i can see that in this two lines:
byte[] thumbnail = exifInterface.getThumbnail();
bm = BitmapFactory.decodeByteArray(thumbnail, 0, thumbnail.length);
in some of image i have bm = null, that would mean that exifInterface has not thumbnail, so it skip to if(!haveThumbnail)..maybe
bm = decodeSampledBitmapFromUri(imageList.get(position), 220, 220); is wrong.
Are your images from MediaStore? Have you tried the static MediaStore methods for thumbnails?
http://developer.android.com/refere...#getThumbnail(android.content.ContentResolver, long, long, int, android.graphics.BitmapFactory.Options)
registered-user said:
Are your images from MediaStore? Have you tried the static MediaStore methods for thumbnails?
http://developer.android.com/refere...#getThumbnail(android.content.ContentResolver, long, long, int, android.graphics.BitmapFactory.Options)
Click to expand...
Click to collapse
thanks for help, i solve the problem.. a f*** bug that it never skip inside
if(!haveThumbNail){
bm = decodeSampledBitmapFromUri(
imageList.get(position), 220, 220);
}
so, some images without thumbnail remained null. and decodeSampledbitmapFromUri was never used. Now it work fine.