Reputation: 85
Hello,
I am working on a bookshelf app that imports pdf files so the user can read them. When you click the import books button, it says it imports the books, but does not view them. As soon as you close the app and try to reopen it you get a force close. Here's what logcat says:
Unable to decode stream: java.io.FileNotFoundException: /mnt/sdcard/shelf/preview/LittleBookOfRubypdf.png: open failed: ENOENT (No such file or directory)
Unable to decode stream: java.io.FileNotFoundException: /mnt/sdcard/shelf/preview/best_of_ruby_quizpdf.png: open failed: ENOENT (No such file or directory)
I have
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
in AndroidManifest.xml
Here's my bookshelf code:
package com.sibext.android_shelf;
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Arrays;
import java.util.List;
import com.d4a.tobias.R;
import com.sibext.android_shelf.adapter.ShelfAdapter;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.res.AssetManager;
import android.os.Bundle;
import android.os.Environment;
import android.support.v4.app.Fragment;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ListView;
import android.widget.Toast;
public class Two extends Fragment{
private static final String TARGET_DIRECTORY = "mnt/sdcard/shelf/";
private ListView list;
Context ctx;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.two, container, false);
this.ctx = view.getContext();
File dir = new File(TARGET_DIRECTORY);
if(!dir.exists()){
dir.mkdirs();
//past here
addBooksFromAssetsToCard();
}else{
String files[] = dir.list();
if(files.length == 0){
//past here
addBooksFromAssetsToCard();
}
}
list = (ListView) view.findViewById(R.id.list);
ShelfAdapter adapter = new ShelfAdapter(view.getContext(), TARGET_DIRECTORY);
adapter.setToListView(list);
return view;
}
public void addBooksFromAssetsToCard(){
List<String> books;
try {
books = getBooksFromAsset(ctx);
for(String book : books){
copyFromAssets(book);
}
} catch (Exception e) {
}
}
public List<String> getBooksFromAsset(Context ctx) throws Exception
{
AssetManager assetManager =ctx.getAssets();
String[] files = assetManager.list("books");
List<String> it=Arrays.asList(files);
return it;
}
public void copyFromAssets(String book)
{
AssetManager assetManager = ctx.getAssets();
String[] files = null;
InputStream in = null;
OutputStream out = null;
//String filename = "filename.ext";
try
{
in = assetManager.open("books/"+book);
out = new FileOutputStream(Environment.getExternalStorageDirectory()+File.separator+"/shelf/"+book);
Log.d("Copying...", ""+book);
copyFile(in, out);
in.close();
in = null;
out.flush();
out.close();
out = null;
}
catch(Exception e)
{
Log.e("tag", "Failed to copy asset file: " + book, e);
}
}
public void copyFile(InputStream in, OutputStream out) throws Exception
{
byte[] buffer = new byte[1024];
int read;
while((read = in.read(buffer)) != -1)
{
out.write(buffer, 0, read);
}
Log.d("Copy_State", "Done...");
}
/*public void onImportClicked(View v){
Toast.makeText(v.getContext(), "Please wait...", Toast.LENGTH_LONG).show();
Intent in = new Intent(v.getContext(), ImportBooks.class);
startActivity(in);
}*/
}
Here's the import books code:
package com.sibext.android_shelf;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FilenameFilter;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;
import com.d4a.tobias.R;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.util.Log;
import android.view.View;
import android.widget.TextView;
import android.widget.Toast;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
public class ImportBooks extends Activity {
int index =0;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.import_books);
populateTotal();
try {
copybooks();
} catch (Exception e) {
}
}
public void copybooks() throws Exception{
String rootPath = Environment.getExternalStorageDirectory().toString();
List<String> books = fetchToneFiles(getApplicationContext(), rootPath);
String desPath = rootPath+File.separator+"shelf"+File.separator;
for(String book : books){
File file = new File(desPath+fetchBookName(book));
if(!file.exists()){
Log.d("[BOOK_Status]", "--Not Exist in shelf-- :"+book);
File from = new File(book);
File to = new File(desPath+fetchBookName(book));
copyDirectoryOneLocationToAnotherLocation(from, to);
index++;
new Handler().postDelayed(new Runnable() {
public void run() {
//
((TextView) findViewById(R.id.total)).setText(String.valueOf(index));
}
}, 2 * 1000);
}
}
if(index == 0){
Toast.makeText(getApplicationContext(), "No new book found...", Toast.LENGTH_LONG).show();
}else{
Toast.makeText(getApplicationContext(), "All Books imported successfully...", Toast.LENGTH_LONG).show();
}
new Handler().postDelayed(new Runnable() {
public void run() {
//Intent in = new Intent(getApplicationContext(), MainActivity_old.class);
//startActivity(in);
finish();
}
}, 7 * 1000);
}
public void copyDirectoryOneLocationToAnotherLocation(File sourceLocation, File targetLocation)
throws Exception {
if (sourceLocation.isDirectory()) {
if (!targetLocation.exists()) {
targetLocation.mkdir();
}
String[] children = sourceLocation.list();
for (int i = 0; i < sourceLocation.listFiles().length; i++) {
copyDirectoryOneLocationToAnotherLocation(new File(sourceLocation, children[i]),
new File(targetLocation, children[i]));
}
} else {
InputStream in = new FileInputStream(sourceLocation);
OutputStream out = new FileOutputStream(targetLocation);
// Copy the bits from instream to outstream
byte[] buf = new byte[1024];
int len;
while ((len = in.read(buf)) > 0) {
out.write(buf, 0, len);
}
in.close();
out.close();
}
}
public void populateTotal(){
String rootPath = Environment.getExternalStorageDirectory().toString();
List<String> _str = fetchToneFiles(getApplicationContext(), rootPath);
int index = 0;
for(String str : _str){
//Toast.makeText(getApplicationContext(), fetchBookName(str), Toast.LENGTH_LONG).show();
index++;
}
((TextView) findViewById(R.id.imported)).setText(String.valueOf(index));
}
public static List<String> fetchToneFiles(Context ctx, String rootPath) {
final List<String> tFileList = new ArrayList<String>();
String[] imageTypes = {"pdf"};
FilenameFilter[] filter = new FilenameFilter[imageTypes.length];
int i = 0;
for (final String type : imageTypes) {
filter[i] = new FilenameFilter() {
public boolean accept(File dir, String name) {
return name.endsWith("." + type);
}
};
i++;
}
FileUtils fileUtils = new FileUtils();
File[] allMatchingFiles = fileUtils.listFilesAsArray(
new File(rootPath), filter, -1);
for (File f : allMatchingFiles) {
tFileList.add(f.getAbsolutePath());
}
return tFileList;
}
public String fetchBookName(String basepath){
String bookname = null;
if(basepath.length()>6){
int index = basepath.lastIndexOf("/");
return basepath.substring(index+1, basepath.length());
}else{
return bookname;
}
}
@Override
public void onBackPressed() {
finish();
super.onBackPressed();
}
}
And my shelf item code:
package com.sibext.android_shelf.shelf;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import com.artifex.mupdfdemo.MuPDFCore;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.PointF;
public class ShelfItem {
private File file;
private String imgPath;
public ShelfItem(File file){
if(file == null){
throw new NullPointerException("Impossible init ShelfItem by null file");
}
this.file = file;
imgPath = file.getName().replace(".", "") + ".png";
createPreviewDir();
}
private void createPreviewDir(){
File dir = new File(getPreviewDir());
if(!dir.exists()){
dir.mkdirs();
}
}
public File getFile() {
return file;
}
private String getPreviewPath(){
return getPreviewDir() + imgPath;
}
private String getPreviewDir(){
return file.getParent() + File.separator + "preview" + File.separator;
}
public void savePreview(Bitmap b){
try {
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
b.compress(Bitmap.CompressFormat.JPEG, 40, bytes);
File f = new File(getPreviewPath());
f.createNewFile();
FileOutputStream fo = new FileOutputStream(f);
fo.write(bytes.toByteArray());
fo.close();
} catch (IOException e) {
e.printStackTrace();
}
}
public Bitmap getPreview(int rowHeight){
MuPDFCore core = null;
try {
core = new MuPDFCore(getFile().getAbsolutePath());
} catch (Exception e) {
e.printStackTrace();
}
if(core == null){
return null;
}
core.countPages();
PointF size = core.getPageSize(0);
int h = rowHeight;
int w = (int)(h * (size.x/size.y));
return core.drawPage(0, w, h, 0, 0, w, h);
}
public Bitmap getPreviewFromSD(){
return BitmapFactory.decodeFile(getPreviewPath());
}
}
Any help would be amazing Thanks in advance
Regards
Chris
Upvotes: 0
Views: 763
Reputation: 128
You should never "hardcode" the SD path, since as you may know android devices have several manufacturers. These Manufacturers take the freedom to define the SD card's path to whatever they want (in short: /mnt/sdcard is not the SD card path on every android device)
Use the built in function "Environment.getExternalStorageState()" to get the path. From the android developers documentation:
Environment.getExternalStorageState() returns path to internal SD mount point like "/mnt/sdcard"
Upvotes: 2