SovietSenpai
SovietSenpai

Reputation: 287

How to download a file after clicking a button (Android Studio)

I recently created an activity in my app. Now I wanted the user to download a .pdf file when he/she wants to view the guidelines. I wanted to implement this on a button. Any idea how to do this properly?

Heres my code below:

public class Exhibitor_Registration_Activity extends AppCompatActivity  {

    Button buttonDownload;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_exhibitor_registration_);

        this.setTitle("Buyer Registration");

        Toolbar myToolbar = (Toolbar) findViewById(R.id.my_toolbar);
        setSupportActionBar(myToolbar);
        getSupportActionBar().setDisplayHomeAsUpEnabled(true);
        myToolbar.setNavigationIcon(R.drawable.ic_arrow_back_white_24dp);

        final Button buttonDownload = (Button) findViewById(R.id.buttonDownload);

        buttonDownload.setOnClickListener(new View.OnClickListener(){

            @Override
            public void onClick(View view) {
                try {
                    //this is the file you want to download from the remote server
                    String path ="http://www.manilafame.com/website-assets/downloads/exhibitor-application-kit/local/201704/1-Summary-of-Participation-Details-April-2017_MN_002.pdfp";
                    //this is the name of the local file you will create
                    String targetFileName = null;
                    boolean eof = false;
                    URL u = new URL(path);
                    HttpURLConnection c = (HttpURLConnection) u.openConnection();
                    c.setRequestMethod("GET");
                    c.setDoOutput(true);
                    c.connect();
                    FileOutputStream f = new FileOutputStream(new File("c:\\junk\\"+targetFileName));
                    InputStream in = c.getInputStream();
                    byte[] buffer = new byte[1024];
                    int len1 = 0;
                    while ( (len1 = in.read(buffer)) > 0 ) {
                        f.write(buffer,0, len1);
                    }
                    f.close();
                } catch (MalformedURLException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                } catch (ProtocolException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                } catch (FileNotFoundException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        });
    }
}

I also got the source code from here and here.

Upvotes: 9

Views: 21803

Answers (2)

Anu Martin
Anu Martin

Reputation: 731

if you want resumable, speed of download ... follow this steps

create a class DownloadManager.java

public class DownloadManager extends AsyncTask<String,String,String>{
String downloadlink,fileDestination;
public static final int ON_INIT=100,ON_ERROR=102,ON_PROGRASS=103,ON_COMPLETED=104,STATUS_DOWNLOADED=1500,STATUS_NOT_YET=1501;
private onUpdateListener onUpdateListener;
private String downloadedPath="";
private long downloaded=0;
private File file;
private String returnData=null;
private File cacheDownloadFile;
public DownloadManager(String downloadlink,String fileDestinationPath){
    this.downloadlink=downloadlink;
    this.fileDestination=fileDestinationPath;
    file=new File(fileDestination, Tools.getFileName(downloadlink));
    cacheDownloadFile=new File(AppCostants.CHACHE_PATH+Tools.getFileName(downloadlink));
    try {
        if(cacheDownloadFile.isFile())
            downloaded=Tools.getFileSize(cacheDownloadFile);
        else
            downloaded=0;
        Log.d("FILE_DOWNLOAD_TAG_p",downloaded+" <- "+cacheDownloadFile.getAbsolutePath());
    } catch (IOException e) {
        e.printStackTrace();
    }
    fireOnUpdate(ON_INIT,"init ...");

}
@Override
protected String doInBackground(String... params) {
    try {
        File dir=new File(fileDestination);
        File chacheDir=new File(AppCostants.CHACHE_PATH);
        if(!chacheDir.isDirectory())
            chacheDir.mkdirs();
        if(!dir.isDirectory()){
            dir.mkdirs();
        }

        if(file.exists()) {
            Log.d("FILE_DOWNLOAD_TAG","File exist return complete");
            return "COMPLETED";//file exist
        }
        if(!cacheDownloadFile.exists()){
            cacheDownloadFile.createNewFile();
        }
        Log.d("FILE_DOWNLOAD_TAG","LINK "+downloadlink);
        URL url=new URL(downloadlink);
        HttpURLConnection urlConnection= (HttpURLConnection) url.openConnection();
        if(downloaded>0)
            urlConnection.setRequestProperty("Range","byte="+downloaded);
        urlConnection.connect();
        int status = urlConnection.getResponseCode();
        InputStream inputStream=urlConnection.getInputStream();
        int totalSize=urlConnection.getContentLength();
        if(totalSize<=downloaded){
            returnData= "COMPLETED";
            publishProgress("File checked "+Tools.getFileName(file.getAbsolutePath()));
            return returnData;
        }
        this.downloadedPath=cacheDownloadFile.getAbsolutePath();
        byte[] buffer=new byte[1024];
        int bufferLength=0;
        FileOutputStream fileOutput=new FileOutputStream(cacheDownloadFile);
        long d=0;
        long starttime=System.currentTimeMillis();
        while ((bufferLength=inputStream.read(buffer))>0){
            fileOutput.write(buffer,0,bufferLength);
            downloaded+=bufferLength;
            d+=bufferLength;
            //String l=" "+Tools.getFileName(file.getAbsolutePath())+" ( "+Tools.convertMemory(downloaded)+" / "+Tools.convertMemory(totalSize)+" )";
            String l="  "+Tools.convertMemory(downloaded)+" / "+Tools.convertMemory(totalSize)+" ( "+getDownloadSpeed(starttime,d)+" )";
            publishProgress(l);
            if(downloaded>=totalSize){
                break;
            }
        }
        Log.d("FILE_DOWNLOAD_TAG","DWONLOADED TO "+downloadedPath+" ("+cacheDownloadFile.length()+")");
        fileOutput.close();
        if(Tools.fileCopy(file,cacheDownloadFile)){
            Log.d("FILE_DOWNLOAD_TAG","file Copied, delete cache");
            cacheDownloadFile.delete();
        }
        returnData="COMPLETED";
    } catch (MalformedURLException e) {
        returnData=null;
        e.printStackTrace();
        publishProgress(e.toString());
        Log.d("###################",e+"");

    } catch (IOException e) {
        returnData=null;
        e.printStackTrace();
        publishProgress(e.toString());
    }

    return returnData;
}

@Override
protected void onProgressUpdate(String... values) {
    super.onProgressUpdate(values);
    fireOnUpdate(ON_PROGRASS,values[0]);
}

@Override
protected void onPostExecute(String s) {
    super.onPostExecute(s);
    if(s!=null){
        fireOnUpdate(ON_COMPLETED,downloadedPath);
    }else{
        fireOnUpdate(ON_ERROR,"Download failed");
    }
}

public interface onUpdateListener{
    void onUpdate(int code,String message);
}
public void setOnUpdateListener(onUpdateListener onUpdateListener){
    this.onUpdateListener=onUpdateListener;
}
private void fireOnUpdate(int code,String message){
    if(onUpdateListener!=null)
        onUpdateListener.onUpdate(code,message);
}

private String getDownloadSpeed(long starttime,float totalDownloaded) {
    long elapsedTime = System.currentTimeMillis() - starttime;
    //byte :
    float speed=1000f * totalDownloaded / elapsedTime;
    return convert(speed);
}
private String convert(float value){
    long kb=1024
            ,mb=kb*1024
            ,gb=mb*1024;

    if(value<kb){
        String speed=(value+"");
        speed=speed.substring(0,speed.indexOf('.')+2);
        return speed+" B/s";
    }else if(value<mb){
        value=value/kb;
        String speed=(value+"");
        speed=speed.substring(0,speed.indexOf('.'));
        return (speed)+" KB/s";
    }else if(value<gb){
        value=(value/mb);
        String speed=(value+"");
        speed=speed.substring(0,speed.indexOf('.'));
        return speed+" MB/s";
    }
    return "";
}
}
  1. use this code in onClick() DownloadManager downloadManager = new DownloadManager(url,filepath);

  2. set event

    downloadManager.setOnUpdateListener(new DownloadManager.onUpdateListener() {
    @Override
    public void onUpdate(int code, String message) {
    if (code == DownloadManager.ON_COMPLETED) {
    
                    }
                    if(DownloadManager.ON_PROGRASS==code){}
    
                }
            });
    
  3. start download by

    downloadManager.execute();
    
  4. lib setup

    compile "commons-io:commons-io:+"
    
  5. Tools.java

    public static long getFileSize(File file) throws IOException {
    FileOutputStream fileOutputStream=new FileOutputStream(file);
    fileOutputStream.close();
    return file.length();
    }
    public static boolean fileCopy(File dest,File source){
    try {
        FileUtils.copyFile(source,dest);
        return true;
    } catch (IOException e) {
        e.printStackTrace();
        return false;
    }
    }
    

Upvotes: 4

Andrey Danilov
Andrey Danilov

Reputation: 6602

It is really bad idea to download file in main thread. Use separate Thread for this

Thread thread = new Thread(new Runnable() {
    @Override
    public void run() {
         //your downloading here
    }
});
thread.start();

it`s better, but still not so good. There are some problems with it:

1) User know nothing about downloading

So better to show additional layout which overlays screen with progress bar, probably indeterminate if you want to write less code. Then after downloading is finished you just hide your layout.

You can use runOnUiThread inside run method in thread for it.

runOnUiThread(new Runnable() {
   @Override
   public void run() {
        //just hide some popup
        //or do what you want after downloading is finished
        popupLayout.serVisibility(View.GONE);
   }
});

2) If user will do action which re-creates activity/fragment (like changing screen orientaion) with running thread you will get memory leak and probably activity will not know about end of download.

There are few ways to solve this problem:

  • You can block screen orientation at this screen, at least while downloading. Probably easiest way in your case.
  • You can use downloading in foreground service. Its really good
    practice, but you will have to learn about services.
  • You can try to interrupt downloading by calling thread.interrupt() method in onDestroy of your Activity/Fragment
  • You can use something like rxJava/rxAndroid (so you don not use threads at all, but you need some time for learn rxJava)

UPD

About threads

Not so bad tutorial about threads in android

You can use AsyncTask instead of Thread, but I highly recommend to use threads especially for long operations.

Upvotes: 0

Related Questions