problems with images in recyclerview using picasso - android

I am downloading an image from internet and this is the path I chose to save it on the phone:
ContextWrapper cw = new ContextWrapper(mContext);
File directory = cw.getDir("imagesDB", Context.MODE_PRIVATE);
OutputStream output = new FileOutputStream(new File(directory,"profile.jpg"));
After the image has been downloaded I'm using this to get the path:
String databasePath = mContext.getDir("", Context.MODE_PRIVATE).getAbsolutePath();
databasePath = databasePath + "imagesDB/profile.jpg";
And then in my recyclerview adapter I use this:
Picasso.with(context).load(databasePath).placeholder(R.mipmap.ic_launcher).into(holder.Photo);
I always get the ic_launcher image displayed instead of the one I downloaded.
Am i using a wrong path for the image?
This is the code I use to download the image:
URL url = null;
try {
url = new URL("http://192.168.0.100/app/image/image1.jpg");
} catch (MalformedURLException e) {
e.printStackTrace();
}
InputStream input = null;
try {
input = url.openStream();
} catch (IOException e) {
e.printStackTrace();
}
try {
ContextWrapper cw = new ContextWrapper(mContext);
File directory = cw.getDir("imagesDB", Context.MODE_PRIVATE);
OutputStream output = new FileOutputStream(new File(directory,"profile.jpg"));
try {
byte[] buffer = new byte[10000];
int bytesRead = 0;
while ((bytesRead = input.read(buffer, 0, buffer.length)) >= 0) {
output.write(buffer, 0, bytesRead);
}
String databasePath = mContext.getDir("", Context.MODE_PRIVATE).getAbsolutePath();
Log.i("","Path1: "+ databasePath.toString());
databasePath = databasePath + "imagesDB/profile.jpg";
Log.i("","Path2: "+ databasePath.toString());
} finally {
output.close();
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
input.close();
} catch (IOException e) {
e.printStackTrace();
}
}

Ok the problem was that I can't pass a String to .load(), instead i have to create a new file like this:
Picasso.with(context).load(new File(databasePath)).into(holder.artistPhoto);
By the way I found the solution in this post:
Picasso Load image from filesystem

Recycler Adapter Using Picasso. Rest of the code if any one needs ask for it I will upload.
public class RecyclerAdapter extends RecyclerView.Adapter<RecyclerAdapter.MyViewHolder> {
private ArrayList<DogInfo> mArrayListInfo;
private Context context;
public RecyclerAdapter(ArrayList<DogInfo> mArrayListInfo,Context context) {
this.mArrayListInfo = mArrayListInfo;
this.context=context;
}
#Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view= LayoutInflater.from(parent.getContext()).inflate(R.layout.lay_display,null);
return new MyViewHolder(view);
}
#Override
public void onBindViewHolder(MyViewHolder holder, int position) {
DogInfo dogInfo=mArrayListInfo.get(position);
holder.mTextView.setText(dogInfo.getmInfo());
Picasso.with(context).load(dogInfo.getmImage()).into(holder.mImageView);
}
#Override
public int getItemCount() {
return mArrayListInfo.size();
}
public class MyViewHolder extends RecyclerView.ViewHolder {
ImageView mImageView;
TextView mTextView;
public MyViewHolder(View itemView) {
super(itemView);
mImageView= (ImageView) itemView.findViewById(R.id.imgShow);
mTextView= (TextView) itemView.findViewById(R.id.txtShow);
}
}
}

Related

generate Gif on Android with AnimatedGifEncoder

i want to create a gif file with AnimatedGifEncoder, its works my gif was created successfully but i can't change the delay between the frames and other settings like quality and so on.
Have any other use this class at android?
Here is my code:
public final class CreateGifUtil extends AbstractAnimatedResource {
private String filename = null;
public CreateGifUtil(Context ctx, List<QueueItem> queueItems) {
super(ctx, queueItems);
}
#Override
public void generate() {
if (!queueItems.isEmpty()) {
AnimatedGifEncoder encoder = new AnimatedGifEncoder();
BufferedOutputStream bs = null;
try {
File mediaSrc = ResourceUtil.getOutputFolder(ctx, ResourceUtil.Folder.IMAGES);
String filename = "test" + String.valueOf(System.currentTimeMillis()) + ".gif";
outputFile = new File(mediaSrc.getAbsolutePath(), filename);
bs = new BufferedOutputStream(new FileOutputStream(outputFile));
encoder.start(bs);
if (isUseFps()) {
encoder.setFrameRate(getFps());
}
encoder.setRepeat(2);
encoder.setQuality(getQuality());
for (QueueItem item : queueItems) {
if (isUseDelayTime()) {
encoder.setDelay(getDelayTime());
}
encoder.addFrame(getBitmapFromResource(item.getFilepath(), 1));
}
boolean result = encoder.finish();
Log.e("123", String.valueOf(result));
} catch (FileNotFoundException e) {
e.printStackTrace();
} finally {
if (bs != null) {
try {
bs.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
private Bitmap getBitmapFromResource(String filePath, int sampleSize) {
BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = sampleSize;
return BitmapFactory.decodeFile(filePath, options);
}
}
Here is my code:
package autoshooter.draegerit.de.autoshooter.video;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.util.Log;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.List;
import autoshooter.draegerit.de.autoshooter.queue.QueueItem;
import autoshooter.draegerit.de.autoshooter.util.ResourceUtil;
public final class CreateGifUtil extends AbstractAnimatedResource {
private String filename = null;
public CreateGifUtil(Context ctx, List<QueueItem> queueItems) {
super(ctx, queueItems);
}
#Override
public void generate() {
if (!queueItems.isEmpty()) {
AnimatedGifEncoder encoder = new AnimatedGifEncoder();
BufferedOutputStream bs = null;
try {
File mediaSrc = ResourceUtil.getOutputFolder(ctx, ResourceUtil.Folder.IMAGES);
String filename = "test" + String.valueOf(System.currentTimeMillis()) + ".gif";
outputFile = new File(mediaSrc.getAbsolutePath(), filename);
bs = new BufferedOutputStream(new FileOutputStream(outputFile));
encoder.start(bs);
if (isUseFps()) {
encoder.setFrameRate(getFps());
}
encoder.setRepeat(2);
encoder.setQuality(getQuality());
for (QueueItem item : queueItems) {
if (isUseDelayTime()) {
encoder.setDelay(getDelayTime());
}
encoder.addFrame(getBitmapFromResource(item.getFilepath(), 1));
}
boolean result = encoder.finish();
Log.e("123", String.valueOf(result));
} catch (FileNotFoundException e) {
e.printStackTrace();
} finally {
if (bs != null) {
try {
bs.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
private Bitmap getBitmapFromResource(String filePath, int sampleSize) {
BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = sampleSize;
return BitmapFactory.decodeFile(filePath, options);
}
}
I recommend you to use this Library Android NDK GIF Library it's much better than AnimatedGifEncoder :
and here's a full example of how to generate a GIF file and save it into gallery :
#SuppressLint("StaticFieldLeak")
public class GenerateSaveGIF extends AsyncTask<Void, Integer, String> {
Context mContext;
String imageFileName = "APP_" + System.currentTimeMillis() + ".gif";
ArrayList<BitmapGIFUtil> arrayListBitmaps = new ArrayList<>();
boolean isSavingBitmapsFinished = false;
GenerateSaveGIF(Context context) {
mContext = context;
}
#Override
protected void onPreExecute() {
super.onPreExecute();
//Preparing;
// Display ProgressDialog here
}
#SuppressLint("WrongThread")
#Override
protected String doInBackground(Void... voids) {
File storageDir = new File(
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES)
+ "/APP_FOLDER");
boolean success = true;
if (!storageDir.exists()) {
success = storageDir.mkdirs();
}
if (success) {
File imageFile = new File(storageDir, imageFileName);
savedImagePath = imageFile.getAbsolutePath();
FileOutputStream outStream = null;
try {
generateGIF(getArrayBitmaps(), savedImagePath);
} catch (Exception e) {
e.printStackTrace();
}
galleryAddPic(savedImagePath);
}
return savedImagePath;
}
ArrayList<BitmapGIFUtil> getArrayBitmaps() {
for (int i = 0; i < mDrawableGif.getNumberOfFrames(); ++i) {
int GIFDelay = mDrawableGif.getFrameDuration(i); //CHANGE IT IF YOU WANT
try {
Thread.sleep(GIFDelay);
} catch (InterruptedException e) {
e.printStackTrace();
}
//replace createEachFrame() with your method getBitmapFromResource();
arrayListBitmaps.add(new BitmapGIFUtil(createEachFrame(), GIFDelay));
}
isSavingBitmapsFinished = true;
return arrayListBitmaps;
}
void generateGIF(ArrayList<BitmapGIFUtil> arrayList, String path) {
GifEncoder gifEncoder = new GifEncoder();
try {
gifEncoder.init(arrayList.get(0).getBitmap().getWidth(), arrayList.get(0).getBitmap().getHeight(), path, GifEncoder.EncodingType.ENCODING_TYPE_SIMPLE_FAST);
for (int i = 0; i < arrayList.size(); i++) {
gifEncoder.encodeFrame(arrayList.get(i).getBitmap(), arrayList.get(i).getDelay());
}
gifEncoder.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
#Override
protected void onPostExecute(String s) {
super.onPostExecute(s);
Toast.makeText(this, getResources().getString(R.string.gif_saved), Toast.LENGTH_SHORT).show();
}
}
Notify gallery:
private void galleryAddPic(String imagePath) {
Intent mediaScanIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
File f = new File(imagePath);
Uri contentUri = Uri.fromFile(f);
mediaScanIntent.setData(contentUri);
sendBroadcast(mediaScanIntent);
}
BitmapGIFUtil Class:
public class BitmapGIFUtil {
private Bitmap bitmap;
private int Delay;
public BitmapGIFUtil() {
}
public BitmapGIFUtil(Bitmap bitmap, int delay) {
this.bitmap = bitmap;
Delay = delay;
}
public Bitmap getBitmap() {
return bitmap;
}
public void setBitmap(Bitmap bitmap) {
this.bitmap = bitmap;
}
public int getDelay() {
return Delay;
}
public void setDelay(int delay) {
Delay = delay;
}
}

Problems with Picasso and Recyclerview - Images get refreshed on scrolling but in the wrong imageviews

I am working on a simple app where I search for a Tv show, where the app generates a GET request to TMDB. From there I am trying to display the images and details of results in a cardview. I am using Picasso for loading the images from TMDB and it works fine. The problem is when I scroll, the images loaded first get refreshed to the other imageviews instead of those show specific images.
This is my asynctask code
class JsonTask extends AsyncTask<String,String,String[][]>{
private List<FeedItem> persons;
String [][] Finalarray = new String[200][3];
#TargetApi(Build.VERSION_CODES.KITKAT)
#Override
protected String[][] doInBackground(String... params) {
HttpURLConnection urlConnection = null;
StringBuffer buffer = new StringBuffer();
String line;
BufferedReader reader = null;
try{
URL Request1 = new URL(params[0]);
urlConnection = (HttpURLConnection) Request1.openConnection();
urlConnection.setRequestProperty("Accept", "application/json");
urlConnection.setRequestMethod("GET");
urlConnection.setDoInput(true);
urlConnection.connect();
int responseCode = urlConnection.getResponseCode();
Log.d("DEBUG_TAG", "The response code is: " + responseCode + " " + urlConnection.getResponseMessage());
InputStream in = urlConnection.getInputStream();
reader = new BufferedReader(new InputStreamReader(in));
while ((line = reader.readLine())!=null){
Log.i("check","Line is"+line);
buffer.append(line);
}
String jsonobjectt= buffer.toString();
JSONObject parentJson = new JSONObject(jsonobjectt);
JSONArray parentArray = (JSONArray) parentJson.get("results");
dataobtained=parentJson.getInt("total_results");
for(int i = 0; i<parentJson.getInt("total_results"); i++){
JSONObject temp = parentArray.getJSONObject(i);
Finalarray[i][0] = temp.getString("original_name");
Finalarray[i][1] = temp.getString("first_air_date");
Finalarray[i][2] = temp.getString("poster_path");
}
}
catch (MalformedURLException e){
Log.i("I do", "eee1");
e.printStackTrace();
} catch (IOException e) {
Log.i("I do", "eee2");
e.printStackTrace();
} catch (JSONException e) {
e.printStackTrace();
} finally {
Log.i("I do", "eee3");
if(urlConnection!=null)
urlConnection.disconnect();
try {
if(reader!=null)
reader.close();
} catch (IOException e) {
Log.i("I do", "eee4");
e.printStackTrace();
}
}
return Finalarray;
}
#Override
protected void onPostExecute(String[][] result) {
persons = new ArrayList<>();
for(int i=0;i<dataobtained;i++){
//if(!result[i][0].isEmpty()&&result[i][2]!=null)
persons.add(new FeedItem(result[i][0], result[i][1],"http://image.tmdb.org/t/p/w500"+result[i][2],searchpagee.this));
}
new Thread(new Runnable() {
#Override
public void run() {
}
}).start();
mRecyclerView.setLayoutManager(llm);
RVAdapter adapter = new RVAdapter(persons);
mRecyclerView.setAdapter(adapter);
}
}
}
And this is my Recycleradapter code
public class RVAdapter extends RecyclerView.Adapter<RVAdapter.PersonViewHolder>{
List<FeedItem> persons;
RVAdapter(List<FeedItem> persons){
this.persons = persons;
}
public static class PersonViewHolder extends RecyclerView.ViewHolder {
public static ImageView personPhoto;
CardView cv;
TextView personName;
TextView personAge;
PersonViewHolder(View itemView) {
super(itemView);
cv = (CardView)itemView.findViewById(R.id.cv);
personName = (TextView)itemView.findViewById(R.id.titleCir);
personAge = (TextView)itemView.findViewById(R.id.contentsCir);
personPhoto = (ImageView)itemView.findViewById(R.id.person_photo);
}
}
#Override
public PersonViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
View v = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.cardv, viewGroup, false);
PersonViewHolder pvh = new PersonViewHolder(v);
return pvh;
}
#Override
public void onBindViewHolder(PersonViewHolder personViewHolder, int i) {
personViewHolder.personName.setText(persons.get(i).title);
personViewHolder.personAge.setText(persons.get(i).content);
Picasso.with(persons.get(i).context).load(persons.get(i).photoId).placeholder(R.drawable.placeholder).fit().into(PersonViewHolder.personPhoto);
}
#Override
public int getItemCount() {
return persons == null ? 0 : persons.size();
}
}
This is before scrolling
While scrolling. Images get repeated
Add a bindView() in your PersonViewHolder like this,
public static class PersonViewHolder extends RecyclerView.ViewHolder {
public static ImageView personPhoto;
CardView cv;
TextView personName;
TextView personAge;
PersonViewHolder(View itemView) {
super(itemView);
cv = (CardView)itemView.findViewById(R.id.cv);
personName = (TextView)itemView.findViewById(R.id.titleCir);
personAge = (TextView)itemView.findViewById(R.id.contentsCir);
personPhoto = (ImageView)itemView.findViewById(R.id.person_photo);
}
public void bindView(int i) {
personName.setText(persons.get(i).title);
personAge.setText(persons.get(i).content);
Picasso.with(persons.get(i).context).load(persons.get(i).photoId).placeholder(R.drawable.placeholder).fit().into(personPhoto);
}
}
And in bindViewHolder you need to call bindView() to bind each element of the list with appropriate elements.
#Override
public void onBindViewHolder(PersonViewHolder personViewHolder, int i) {
try {
personViewHolder.bindView(i);
} catch(Exception e) {e.printStackTrace();}
}

Android Listview Async Image loading

I have listview at which I am trying to implement an async task that loads the image into the view inside the getView method of my adapter. I have succeeded in creating this however my problem is that since in the listview and the adapter the view gets recycled, there is a short period of time when the user scrolls the listview that the imageView located in the layout shows the image of the view at a previous position. It then shows the correct image. I have tried setting the imageView bitmap to null inside the getView method before the async task is called but it still behaves the same. How do I load an image into a view using an async task without having the previous image shown before the image is finished loading?
hey follow few step to download image from server and show in your list view
Step 1. make this class in your project
OnImageDownloaded.java
public class OnImageDownloaded {
public OnImageDownloaded() {
try {
if (Environment.getExternalStorageState().equals(
Environment.MEDIA_MOUNTED)) {
File file = new File(Environment.getExternalStorageDirectory()
.getAbsolutePath() + File.separator + "your_Dir_name");
if (file.mkdirs()) {
}
} else {
Log.e("testing", "External Directory is not mounted");
}
} catch (Exception e) {
e.printStackTrace();
}
}
public void downloadTheImages(ArrayList<String> imageUrls) {
try {
new downloadingTheImages(imageUrls).execute();
} catch (Exception e) {
e.printStackTrace();
}
}
class downloadingTheImages extends AsyncTask<Void, Void, Void> {
ArrayList<String> imageUrls;
public downloadingTheImages(ArrayList<String> imageUrls) {
this.imageUrls = imageUrls;
}
#Override
protected Void doInBackground(Void... params) {
try {
for (int i = 0; i < imageUrls.size(); i++) {
if (imageUrls.get(i).equals("0")) {
} else
downloadTheImageIfRequired(imageUrls.get(i));
}
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
public void downloadTheImageIfRequired(String imageName) {
try {
String dirPath = Environment.getExternalStorageDirectory()
.getAbsolutePath()
+ File.separator
+ "your_Dir_name"
+ File.separator;
String CompleteFilePath = dirPath + imageName;
File f = new File(CompleteFilePath);
if (f.exists()) {
} else {
URL url = new URL(
"http image URL ::"
+ imageName);
URLConnection conexion = url.openConnection();
conexion.connect();
InputStream input = new BufferedInputStream(url.openStream());
OutputStream output = new FileOutputStream(CompleteFilePath);
byte data[] = new byte[1024];
int count;
while ((count = input.read(data)) != -1) {
output.write(data, 0, count);
}
output.flush();
output.close();
input.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
Step 2.
Check out how you get that image
private class getImage extends AsyncTask<Void, Void, String> {
Dialog dialog;
String url;
#Override
protected void onPreExecute() {
super.onPreExecute();
}
#Override
protected String doInBackground(Void... params) {
url = getResources().getString(R.string.baseurl) + "getNews";
JSONParser jParser = new JSONParser();
String json = jParser.getJSONFromUrl(url);
try {
JSONObject jobject = new JSONObject(json);
Log.e("testing", "url: " + url + " " + json);
int success = jobject.getInt("success");
Log.e("testing", "json length" + jobject.length());
for (int i = 0; i < jobject.length() - 1; i++) {
JSONObject jobj = jobject
.getJSONObject(Integer.toString(i));
if (success == 1) {
HashMap<String, String> hm = new HashMap<String, String>();
ArrayList<String> tempAl1 = new ArrayList<String>();
tempAl1.add(jobj.getString("image"));
if (tempAl1.size() > 0) {
new OnImageDownloaded().downloadTheImages(tempAl1);
}
Log.e("test", "image" + jobj.getString("image"));
hm.put(image, jobj.getString("image"));
aldata.add(hm);
}
}
} catch (JSONException e) {
e.printStackTrace();
}
return null;
}
#Override
protected void onPostExecute(String result) {
super.onPostExecute(result);
if (dialog != null)
if (dialog.isShowing())
dialog.dismiss();
Custom_Adapter adapter = new Custom_Adapter (
(Activity) context, aldata);
lv.setAdapter(adapter);
}
}
Step 3.
Show that image in your adapter like this
call these methods in your getview in adaper
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View view = convertView;
view = null;
if (view == null) {
LayoutInflater inflator = context.getLayoutInflater();
view = inflator.inflate(R.layout.news_view, null);
final ViewHolder viewHolder = new ViewHolder();
initAll(view, viewHolder);
view.setTag(viewHolder);
}
ViewHolder holder = (ViewHolder) view.getTag();
fillAll(holder, position);
return view;
}
public void fillAll(final ViewHolder holder, final int position) {
String dirPath = Environment.getExternalStorageDirectory()
.getAbsolutePath()
+ File.separator
+ "your_Dir_name"
+ File.separator;
String CompleteFilePath = dirPath + allData.get(position).get("image");
File f = new File(CompleteFilePath);
if (f.exists()) {
Log.e("testingTag", "if part");
holder.ivimage.setVisibility(View.VISIBLE);
catchOutOfMemory(holder.ivimage, CompleteFilePath);
} else {
Log.e("testingTag", "else part");
holder.ivimage.setVisibility(View.GONE);
}
Log.e("test", "image" + allData.get(position).get("image"));
}
void catchOutOfMemory(ImageView iv, String path) {
try {
iv.setImageURI(Uri.parse(path));
} catch (OutOfMemoryError e) {
BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = 8;
Bitmap preview_bitmap = BitmapFactory.decodeFile(path, options);
iv.setImageBitmap(preview_bitmap);
}
}
thats all thanks
I had the same problem, then I started using Square's Picasso , it's very simple and handles imageview recycling perfectly!
In your adapter, you need to use a ViewHolder (to recycle views effectively) and set a tag (on the view) to bind the view to the correct image. You already know the position in the getView(...) callback.

Sqlite database saved as file

I've build an app for managing transactions and i'm currently adding dropbox backup. I do this by uploading the databasefiles to dropbox (which seems to be appearing correctly). Then i want to download the files again and overwrite the existing databases. When i do this the databases get saved as files ei. get listed by context.fileList(); instead of context.databaseList(); How do i handle the database files to get them in the right place?
Here is the code i thought relevant:
private static class Downloader extends AsyncTask<Integer, Integer, Boolean>{
Context context;
#Override
protected void onPreExecute(){
context = SpendoBase.getContext();
}
#Override
protected Boolean doInBackground(Integer... arg0) {
System.out.println("DoInBackground:");
try {
List<DropboxAPI.Entry> entries = mDBApi.metadata("/", -1, null, true, null).contents;
File file;
FileOutputStream os;
int count = 0;
for(DropboxAPI.Entry entry: entries){
count++;
System.out.println("Entry.path(): " + entry.path + " " + count + "/" + entries.size());
file = new File(entry.path);
System.out.println("1");
os = context.openFileOutput(file.getName(), Context.MODE_PRIVATE);
System.out.println("2");
DropboxFileInfo info = mDBApi.getFile(entry.path, null, os, null);
os.flush();
os.close();
System.out.println("3 " + info);
}
} catch (DropboxException e) {
e.printStackTrace();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
}
private static class Uploader extends AsyncTask<Integer, Integer, Boolean>{
String[] databaseList;
Context context;
#Override
protected void onPreExecute(){
context = SpendoBase.getContext();
databaseList = context.databaseList();
}
#Override
protected Boolean doInBackground(Integer... params) {
for(String dbName: databaseList){
try {
File f = context.getDatabasePath(dbName);
FileInputStream fis = new FileInputStream(f.getPath());
mDBApi.putFileOverwrite("/" + dbName, fis, f.length(), null);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (DropboxException e) {
e.printStackTrace();
}
}
return null;
}
}
private static class MetaReader extends AsyncTask<Integer, Integer, List<String>>{
#Override
protected List<String> doInBackground(Integer... arg0) {
try {
List<String> result = new Vector<String>();
DropboxAPI.Entry existingEntry = mDBApi.metadata("/", -1, null, true, null);
List<DropboxAPI.Entry> temp = existingEntry.contents;
for(int i = 0; i < temp.size(); i++){
File f = new File(temp.get(i).path);
result.add(f.getName());
}
return result;
} catch (DropboxException e) {
System.out.println("Something went wrong: " + e);
}
return null;
}
#Override
protected void onPostExecute(List<String> result){
for(String str:result){
System.out.println(str);
}
}
}
I don't do much Android development, so I could be way off base here, but why can't you just use context.getDatabasePath(dbName) again in the Downloader and write the file to that path?
I managed to solve it. My error was simply that I saved the database in the wrong place.
Changing:
file = new File(entry.path);
System.out.println("1");
os = context.openFileOutput(file.getName(), Context.MODE_PRIVATE);
to:
file = new File("/data/data/com.SverkerSbrg.SpendoFull/databases/" + entry.path);
System.out.println("1");
os = new FileOutputStream(file.getPath());
Solved the problem
You need to root your target phone to save your file on /data/data/com.SverkerSbrg.SpendoFull/databases/ this location.

Android: Custom ListView and Threading problem

I'm working on a small project on Android and have a serious problem with implementing some multi-threading into my solution. Below is a class that is an activity inside the tab of the main interface, which displays a custom list with pictures and data downloaded from YouTube API.
The class works fine, but it completely blocks the UI when, first the data, and then the images are being loaded from the Internet. I know I need to implement some threading and I have tried various things, but I'm not quite sure which parts of the code I have to launch as separate threads. There's also a chance there is something fundamentally wrong with my code structure.
Ideally I'd like to have the UI shown to the user immediately after the application is launched with a progress dialog on top of it, while the textual data is being loaded from YouTube. Then the user should get control of the UI, while images are being loaded in another thread in the background.
public class VodsActivity extends ListActivity {
private LayoutInflater mInflater;
private Vector<RowData> data;
RowData rd;
//private Handler mHandler;
private ProgressDialog dialog;
//Generic names of custom ListView elements
private static String[] title;
private Vector<String> detail;
private Vector<String> status;
private Vector<String> imgurl;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.custom_list);
mInflater = (LayoutInflater) getSystemService(Activity.LAYOUT_INFLATER_SERVICE);
title = getResources().getStringArray(R.array.yt_channels);
detail = new Vector<String>();
status = new Vector<String>();
imgurl = new Vector<String>();
//mHandler = new Handler();
//dialog = ProgressDialog.show(VodsActivity.this, "","Loading. Please wait...", true);
loadData();
displayData();
//dialog.dismiss();
}
private void loadData() {
String[] values = {"error", "error", "http://www.ephotobay.com/thumb/message-error.jpg" };
for (int i = 0; i < title.length; i++) {
values = getData(title[i]);
values[1] = getTodaysUploads(title[i]);
detail.add(i, values[0]);
status.add(i, values[1]);
imgurl.add(i, values[2]);
}
}
/*** This function gets total number of uploads and thumbnail url for the user from a single feed ***/
private String[] getData (String username) {
String[] result = new String[3];
String ytFeedUrl = "http://gdata.youtube.com/feeds/api/users/" + username + "?v=2";
InputStream inStream = null;
try {
inStream = OpenHttpConnection(ytFeedUrl);
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
Document dom = db.parse(inStream);
Element docEle = dom.getDocumentElement();
inStream.close();
NodeList nl = docEle.getElementsByTagName("entry");
if (nl != null && nl.getLength() > 0) {
for (int i = 0; i < nl.getLength(); i++) {
Element entry = (Element) nl.item(i);
Element thumbnail = (Element) entry.getElementsByTagName("media:thumbnail").item(0);
String thumbUrl = thumbnail.getAttribute("url");
Element feedLink = (Element) entry.getElementsByTagName("gd:feedLink").item(5);
String uploads = feedLink.getAttribute("countHint");
result[0] = uploads + " videos";
result[1] = ""; //not used here
result[2] = thumbUrl;
}
}
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (ParserConfigurationException e) {
e.printStackTrace();
} catch (SAXException e) {
e.printStackTrace();
}
finally {
//
}
return result;
}
/*** This function gets a number of today's uploads of the user ***/
private String getTodaysUploads (String username) {
String result = null;
String ytFeedUrl = "http://gdata.youtube.com/feeds/api/videos?author=" + username + "&time=today&v=2";
InputStream inStream = null;
try {
inStream = OpenHttpConnection(ytFeedUrl);
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
Document dom = db.parse(inStream);
Element docEle = dom.getDocumentElement();
inStream.close();
NodeList nl = docEle.getElementsByTagName("feed");
if (nl != null && nl.getLength() > 0) {
for (int i = 0; i < nl.getLength(); i++) {
Element entry = (Element) nl.item(i);
Element title = (Element)entry.getElementsByTagName("openSearch:totalResults").item(0);
result = title.getFirstChild().getNodeValue();
result += " new today";
}
}
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (ParserConfigurationException e) {
e.printStackTrace();
} catch (SAXException e) {
e.printStackTrace();
}
finally {
//
}
return result;
}
private void displayData () {
//Use vector instead of ArrayList for safe threading
data = new Vector<RowData>();
for (int i = 0; i < title.length; i++) { //Loop needs to be changed based on results
try {
rd = new RowData(i, title[i], detail.get(i), status.get(i));
} catch (Exception e) {
e.printStackTrace();
}
data.add(rd);
}
CustomAdapter adapter = new CustomAdapter (this, R.layout.custom_list_item, R.id.title, data);
setListAdapter(adapter);
getListView().setTextFilterEnabled(true);
}
private InputStream OpenHttpConnection(String strUrl) throws IOException {
InputStream inStream = null;
URL url = new URL(strUrl);
URLConnection conn = url.openConnection();
try {
HttpURLConnection httpConn = (HttpURLConnection) conn;
httpConn.setRequestMethod("GET");
httpConn.connect();
if (httpConn.getResponseCode() == HttpURLConnection.HTTP_OK) {
inStream = httpConn.getInputStream();
}
} catch (Exception ex) {
ex.printStackTrace();
}
return inStream;
}
//This is temporary
public void onListItemClick(ListView parent, View v, int position, long id) {
CustomAdapter adapter = (CustomAdapter) parent.getAdapter();
RowData row = adapter.getItem(position);
Builder builder = new AlertDialog.Builder(this);
builder.setTitle(row.mTitle);
builder.setMessage(row.mDetail + " -> " + position );
builder.setPositiveButton("ok", null);
builder.show();
}
//Private class RowData - holds details of CustomAdapter item
private class RowData {
protected int mId;
protected String mTitle;
protected String mDetail;
protected String mStatus;
RowData (int id, String title, String detail, String status) {
mId = id;
mTitle = title;
mDetail = detail;
mStatus = status;
}
#Override
public String toString() {
return mId + " " + mTitle + " " + mDetail + " " + mStatus;
}
}
//Custom Adapter for the custom list, overrides onView() method
private class CustomAdapter extends ArrayAdapter<RowData> {
public CustomAdapter(Context context, int resource, int textViewResourceId, List<RowData> objects) {
super (context, resource, textViewResourceId, objects);
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder = null;
TextView title = null;
TextView detail = null;
TextView status = null;
ImageView image = null;
RowData rowData = getItem(position);
//Reuse existing row views
if(convertView == null) {
convertView = mInflater.inflate(R.layout.custom_list_item, null);
holder = new ViewHolder(convertView);
convertView.setTag(holder);
}
holder = (ViewHolder) convertView.getTag();
title = holder.getTitle();
title.setText (rowData.mTitle);
detail = holder.getDetail();
detail.setText(rowData.mDetail);
status = holder.getStatus();
status.setText(rowData.mStatus);
//add if statements here for colors
image = holder.getImage();
/**** This loads the pictures ****/
BitmapFactory.Options bmOptions;
bmOptions = new BitmapFactory.Options();
bmOptions.inSampleSize = 1;
String imageUrl = imgurl.get(rowData.mId);
Bitmap bm = LoadImage(imageUrl, bmOptions);
image.setImageBitmap(bm);
return convertView;
}
//Load image from the URL
private Bitmap LoadImage(String url, BitmapFactory.Options options) {
Bitmap bitmap = null;
InputStream inStream = null;
try {
inStream = OpenHttpConnection(url);
bitmap = BitmapFactory.decodeStream(inStream, null, options);
inStream.close();
} catch (IOException ioex) {
ioex.printStackTrace();
}
return bitmap;
}
}
/*** Wrapper for row data ***/
private class ViewHolder {
private View mRow;
private TextView title = null;
private TextView detail = null;
private TextView status = null;
private ImageView image = null;
public ViewHolder (View row) {
mRow = row;
}
public TextView getTitle() {
if (title == null) {
title = (TextView) mRow.findViewById(R.id.title);
}
return title;
}
public TextView getDetail() {
if (detail == null) {
detail = (TextView) mRow.findViewById(R.id.detail);
}
return detail;
}
public TextView getStatus() {
if (status == null) {
status = (TextView) mRow.findViewById(R.id.status);
}
return status;
}
public ImageView getImage() {
if (image == null) {
image = (ImageView) mRow.findViewById(R.id.thumbnail);
}
return image;
}
}
}
Thanks a lot for any pointers.
Check out the AsyncTask. This will let you background your long-running processes while showing the UI.
Also, you can find good/official tutorial on Android threading here.
I ended up using standard java Thread to load the data from API in the background and created a separate class for loading images in separate threads as well. In case you're wondering it now looks like this, and seem to work fine.
Loading the data:
public void onCreate(...) {
//...
mHandler = new Handler();
dialog = ProgressDialog.show(VodsActivity.this, "","Loading. Please wait...", true);
getData.start();
}
private Thread getData = new Thread() {
public void run() {
try {
loadData();
mHandler.post(showData);
} catch (Exception ex) {
ex.printStackTrace();
}
}
};
private Runnable showData = new Runnable() {
public void run() {
try {
displayData();
dialog.dismiss();
} catch (Exception ex) {
ex.printStackTrace();
}
}
};
Loading images (in CustomAdapter):
String imageUrl = imgurl.get(rowData.mId);
final ImageView image = holder.getImage();
//Reuse downloaded images or download new in separate thread
image.setTag(imageUrl);
Drawable cachedImage = imageLoader.loadDrawable(imageUrl, new ImageCallback() {
public void imageLoaded(Drawable imageDrawable, String imageUrl) {
ImageView imageViewByTag = (ImageView) image.findViewWithTag(imageUrl);
if (imageViewByTag != null) {
imageViewByTag.setImageDrawable(imageDrawable);
}
}
});
image.setImageDrawable(cachedImage);
ImageLoader class:
public class ImageLoader {
private HashMap<String, SoftReference<Drawable>> imageCache;
private static final String TAG = "ImageLoader";
public ImageLoader() {
imageCache = new HashMap<String, SoftReference<Drawable>>();
}
//Loads image from the cache if it exists or launches new thread to download it
public Drawable loadDrawable(final String imageUrl, final ImageCallback imageCallback) {
Log.d(TAG, "loadDrawable(" + imageUrl + ")");
if (imageCache.containsKey(imageUrl)) {
SoftReference<Drawable> softReference = imageCache.get(imageUrl);
Drawable drawable = softReference.get();
if (drawable != null) {
return drawable;
}
}
final Handler handler = new Handler() {
#Override
public void handleMessage(Message message) {
imageCallback.imageLoaded((Drawable) message.obj, imageUrl);
}
};
new Thread() {
#Override
public void run() {
Drawable drawable = loadImageFromUrl(imageUrl);
imageCache.put(imageUrl, new SoftReference<Drawable>(drawable));
Message message = handler.obtainMessage(0, drawable);
handler.sendMessage(message);
}
}.start();
return null;
}
//Downloads image from the url
public static Drawable loadImageFromUrl(String url) {
Log.d(TAG, "loadImageFromUrl(" + url + ")");
InputStream inputStream;
try {
inputStream = new URL(url).openStream();
} catch (IOException e) {
throw new RuntimeException(e);
}
return Drawable.createFromStream(inputStream, "src");
}
public interface ImageCallback {
public void imageLoaded(Drawable imageDrawable, String imageUrl);
}
}

Categories

Resources