Pages

Wednesday, September 18, 2013

Web download

In this post, you learn to create a simple web donwloader app in Android. The web downloader app can download any file (including html pages) that is referred to by a link shown on a browser or a link that the user types in the address text box. To start developing the web download app, you need to create a project in Eclipse. The project name will be called WebDownloader.

web downloader user interface


On the app user interface, we need one EditText, two Buttons, and one Listview. The EditText view allows the user to enter the address or url of the file to be downloaded. If the user selects a link from the browser, this text box will display the address or url of the link. The first Button labeled "Add to download list" is pushed to add the address in the text box to the ListView for later downloading. The second Button will be pushed to start the download process. It is labeled "OK". These views are defined in the activity_main.xml as shown below.

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context=".MainActivity"
android:orientation="vertical"
android:background="@drawable/back_style"
>

<EditText
android:id="@+id/txt_input"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:inputType="text"
android:hint="@string/txt_hint"
/>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
>
<Button
android:id="@+id/bt_add"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/bt_label"
android:onClick="addClick"
/>
<Button
android:id="@+id/bt_ok"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/bt_ok"
android:onClick="okClick"
/>
</LinearLayout>
<TextView
android:id="@+id/txt_view"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
/>
<ListView
android:id="@+id/url_list"
android:layout_width="fill_parent"
android:layout_height="300dp"
android:paddingBottom="20dp"
android:paddingTop="20dp"
android:background="#f8f8f8"
/>

</LinearLayout>

To apply the backround to user interface, we need a resource file called back_style.xml stored in the drawable directory. This file defines the look and feel of the app background. To apply the background style to the user interface this file must be defined as a value of background property of the LinearLayout view (android:background="@drawable/back_style").

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<shape>
<gradient
android:startColor="#ffffff"
android:endColor="#992211"
android:angle="270" />
<stroke
android:width="1dp"
android:color="#171717" />
<corners
android:radius="4dp" />
<padding
android:left="10dp"
android:top="10dp"
android:right="10dp"
android:bottom="10dp" />
</shape>
</item>
</selector>


Some string resources that are used by the views are written in the strings.xml file. The content of the strings.xml file is shown below.

<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name">WebDownloader</string>
<string name="action_settings">Settings</string>
<string name="bt_label">Add to download list</string>
<string name="txt_hint">Enter web page address</string>
<string name="bt_ok">OK</string>
</resources>

As mentioned above, the user can launch the web downloader app by two ways. One is by selecting a link from the browser and another is by launching it directly from the Android applications laucher. For the first way, the web downloader app needs to be listed in the app choices list to view or download the file that is refered to by the link. You can have your apps to diplay in the popup list by defining intent filters in the AndroidManifest.xml file of the app. The intent filters specify the capacity that the web downloader app can do in terms of actions to be performed, and data to operate on. By doing this, the Android system know how to capture intents that match the capacity of the app and ignore intents that do not match. An intent is a data structure that contains data and operations on the data. It can be used to send and receive data in an app or between apps.

Display web downloader in popuup list of apps choices


To define an intent filter, you need to use the <intent_filter> tag. This tag will be placed in the activity, service, or broadcast receiver that will receive the intent. When defining an intent filter, there are three parts that need to be considered. The first part specifies the action the app can do. In this example app, the action that the app can do is VIEW action. The VIEW action tells the Android that the web downloader app can download and display the content of the link. When this action is specified, the intent will contain the address or url of the link and so we can write code to get the link and download data from the link. The code to do these tasks are written in the MainActivity.java file that is shown later in this post. The second part determines the kind of the intents that will be received by the web downloader appp. The DEFAULT category allows the Android system to capture intents that do not have a category. In most cases, we use this category. The BROWABLE category tells Android to filter intents that are in browsable category (displayable and downloadable). The final part can be used to specify the type of data, or url (including scheme, host, and file path). In this app, we allow any file to be downloaded so the type of data can be specified by a value of "*/*" to the mimeType property. Sine the file to be downloaded is from the internet and from any host, the value of the scheme property will be "http" and the value for the host is "*".

<intent-filter>
<action android:name="android.intent.action.VIEW"></action>
<category android:name="android.intent.category.DEFAULT"></category>
<category android:name="android.intent.category.BROWSABLE"></category>
<data android:mimeType="*/*" android:scheme="http" android:host="*"></data>
</intent-filter>

For reference documentation about defining intent filter and its related parts, you can visit android developer website.

In this example app, the AndroidManifest.xml looks like the following.

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.webdownloader"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="8"
android:targetSdkVersion="17" />
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<application
android:allowBackup="true"
android:icon="@drawable/wd"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity android:configChanges="orientation"
android:name="com.example.webdownloader.MainActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW"></action>
<category android:name="android.intent.category.DEFAULT"></category>
<category android:name="android.intent.category.BROWSABLE"></category>
<data android:host="*" android:scheme="http"></data>
</intent-filter>
</activity>

<service
android:name="DownloadService"
android:icon="@drawable/ic_launcher"
android:label="MYSERVICE">
</service>
</application>
</manifest>


In the AndroidManifest.xml file we also define the permissions for the web downloader app. The first permision allows the app to use the internet, the second permision to access the network connection states, and the final permision to read and write data to the external storage (sdcard).

<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

The last part of the AndroidManifest.xml file, we declare a service. The name of the service is the same as the class that extends the Service or IntentService. A service can be used to do operations that need long time to complete. When doing long-time operations, the user interface is locked. So it does not respond to the user and this situation might make the user feel uncomfortable with your app. To avoid this problem, the operations need to be run in background. The IntentService class is used to do the downloading process in background in the web downloader appp because it can take long time to complete. A service can receive data (stored in an intent object) from an activity that requires the long-time process to be passed to the service and send the feedback information to the activity. In this app, the data to be sent from the main activity are the ArrayList object that store the urls of the links that were added to the ListView to download and the output directory to store the files downloaded. You need to override the onHandleIntent method to get the data stored in an intent object that is sent by the main activity.

DownloadService.java file

package com.example.webdownloader;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import android.app.IntentService;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;

public class DownloadService extends IntentService {
private ArrayList<String> urlist;
private String storeDir;
public DownloadService() {
super("SERVICE");
// TODO Auto-generated constructor stub
}

public void onHandleIntent(Intent intent){
Bundle b=intent.getExtras();
if(b!=null){
urlist=b.getStringArrayList("URLS");
storeDir=b.getString("OUTDIR");
startDownload();
}


}

public void startDownload(){
String feedback="";
if(urlist.size()>0){
try {
for(int i=0;i<urlist.size();i++){    

URL url=new URL(urlist.get(i));
readDataStream(url);

}

feedback="Complete! Check the webdownload directory on your sdcard";

} catch (MalformedURLException e) { e.printStackTrace();}
}
else{

feedback="No url is added to the download list.";
}
//send feedback message to the main activity
Intent backIntent=new Intent("com.example.webdownloader");
backIntent.putExtra("BACKMESS", feedback);
sendBroadcast(backIntent);

}
public void readDataStream(URL url){
    try {
   
    File f=new File(storeDir);
    if(f.exists()){
    HttpURLConnection con=(HttpURLConnection)url.openConnection();
    InputStream is=con.getInputStream();
    String path=url.getPath();
    String filename=path.substring(path.lastIndexOf('/')+1);
    FileOutputStream fos=new FileOutputStream(storeDir+"/"+filename);
    int data=0;
    while((data=is.read())!=-1){
    fos.write(data);
    }
    is.close();
    fos.flush();
    fos.close();
    }
    else
    Log.e("Error","Not found "+storeDir);

} catch (IOException e) {
e.printStackTrace();
}
   
    }
}


To download content of a file that is refered to by a link, you can use the HttpURLConnection class. You can have HttpURLConnection object by using the openConnection method of the URL class.

HttpURLConnection con=(HttpURLConnection)url.openConnection();

HttpURLConnection class has the getInputStream method that returns an InputStream object. When you have the InputStream object, you can use its read method to read content of the file and write it to an output file by using the FileOutputStream class.

The final part of the web downloader app is MainActivity.java file. In this file, we use the ArrayList to store the addresses or urls that are added to the ListView. To use the ArrayList object as an datasource of the ListView, you need to create an ArrayAdapter object to encaptulate the ArrayList object. When creating the ArrayAdapter object you need to provide three values: context, layout of the ListView, and the ArrayList object. Then supply this adapter object to the ListView by using its setAdapter method.

aa=new ArrayAdapter<String>(this,R.layout.listlayout,urlist);
lv.setAdapter(aa);

The layout of the ListView view is defined in the listlayout.xml file in res/layout directory.

<?xml version="1.0" encoding="utf-8"?>
<!-- Single List Item Design -->
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/label"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:padding="10sp"
android:textSize="16sp"
android:textStyle="bold" >
</TextView>

MainActivity.java file

package com.example.webdownloader;
import java.io.File;
import java.util.ArrayList;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.util.Log;
import android.view.Menu;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.TextView;


public class MainActivity extends Activity {

    private ListView lv;
    private ArrayList<String> urlist;
    private ArrayAdapter<String> aa;
    private String storeDir;
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        urlist=new ArrayList<String>();
        aa=new ArrayAdapter<String>(this,R.layout.listlayout,urlist);
        lv=(ListView)findViewById(R.id.url_list);
        lv.setAdapter(aa);
        Intent intent=getIntent();
        String action=intent.getAction();      
        if(Intent.ACTION_VIEW.equals(action)){        
        Uri uri=intent.getData();
        EditText txturl=(EditText)findViewById(R.id.txt_input);
        txturl.setText(uri.toString());
       
        }

     
    }

    protected void onStart(){
    super.onStart();
    createStoreDir();
    }
 
    protected void onResume(){
    super.onResume();
    registerReceiver(receiver, new IntentFilter("com.example.webdownloader"));    
    }
 
    protected void onPause(){
    super.onPause();
    unregisterReceiver(receiver);
   

    }
 
    private BroadcastReceiver receiver=new BroadcastReceiver(){
    public void onReceive(Context context,Intent intent){
   
        Bundle b=intent.getExtras();
        if(b!=null){
        TextView tv=(TextView)findViewById(R.id.txt_view);
        tv.setText(b.getString("BACKMESS"));
        }
    }
    };

 
    public void createStoreDir(){
    storeDir=Environment.getExternalStorageDirectory()+"/webdownload";
File f=new File(storeDir);
if(!f.exists())
if(!f.mkdir()){
Log.e("Error","Can't create webdownload directory");
disableButtons();
}
    }
 
    public void disableButtons(){
    Button btadd=(Button)findViewById(R.id.bt_add);
    Button btok=(Button)findViewById(R.id.bt_ok);
    btadd.setEnabled(false);
    btok.setEnabled(false);
    }
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }
     
    public void addClick(View view){
    EditText txturl=(EditText)findViewById(R.id.txt_input);
    String url=txturl.getText().toString();
    if(url.length()>0){
    urlist.add(url);
    aa.notifyDataSetChanged();
    }
    }
    public void okClick(View view){
    TextView tv=(TextView)findViewById(R.id.txt_view);
    tv.setText("Please wait...");
    Intent newIntent=new Intent(this,DownloadService.class);
    newIntent.putStringArrayListExtra("URLS", urlist);
    newIntent.putExtra("OUTDIR",storeDir);    
    startService(newIntent);

    }

}


The Intent object (called intent) can be obtained by using the getIntent method of the Activity class. This intent object contains the url of the selected link. To get the url from the intent object, you need to use the getData method of the Intent class.
Intent intent=getIntent();
String action=intent.getAction();
if(Intent.ACTION_VIEW.equals(action)){
Uri uri=intent.getData();
//more code here
}

To receive feedback message from the Service (DownloadService), the MainActivity needs to register a BroadcastRecevier by using the registerReceiver method when the activity starts.

registerReceiver(receiver, new IntentFilter("com.example.webdownloader"));

The receiver can be unregistered by using the unregisterReceiver method. This code fragment is usually placed in the onPause or onStop mehtod of the activity.

unregisterReceiver(receiver);

In the onReceive method of the BroadcastReceiver class, you can write some code to get the feedback message sent by the Service (stored in the intent object). The intent object has a method called getExtra that returns a Bundle object that the message is stored.

Bundle b=intent.getExtras();
if(b!=null){
TextView tv=(TextView)findViewById(R.id.txt_view);
tv.setText(b.getString("BACKMESS"));
}

When the user clicks the Add to download list button, the addClick method is called to add the address shown in the text box to the ArrayList and the ListView. When the OK button is pushed and the okClick method is called, the main activity sends an intent object that contains the ArrayList and output directory to the DownloadService. In this case, the intent object is constructed by specifying the context and the service class to start (DownloadService). Then you can call the startService to start the service.

Intent newIntent=new Intent(this,DownloadService.class);
newIntent.putStringArrayListExtra("URLS", urlist);
newIntent.putExtra("OUTDIR",storeDir);
startService(newIntent);

Now run the web downloader app. Then upload and install the WebDownload.apk to your real device. In your real device, make sure the internet is working. Start your web browser and find a download link. Select the download link and choose WebDownloader from the popup list. When the address of the download link shown in the text box, select the Add to download list button to add the address to the ListView then click the OK button.

run web download app for testing

Download apk file of the Web Downloader app

18 comments:


  1. Diệp Âm Trúc nói:
    -Tốt lắm. Thân là đội trưởng,mệnh lệnh thứ nhất của ta là, bất luận lần này các ngươi nhìn thấy gì, biết cái gì đều không được tiết lộ ra ngoài. Nếu không, tự gánh lấy hậu quả.

    Thường Hạo lẩm bẩm:
    -Có cần nghiêm trọng vậy không? Diệp Âm Trúc, ngươi nói quá không đấy?

    Mã Lương huých Thường Hạo một cái, trừng mắt nhìn Thường Hạo.
    Diệp Âm Trúc nhíu mày, nói:
    -Cũng không phải ta nói quá, mà sự thật là vậy. Nếu bây giờ ngươi cảm thấy không ổn, rời khỏi còn kịp.

    Hắn và Thường Hạo tịnh khôđồng tâm
    game mu
    cho thuê nhà trọ
    cho thuê phòng trọ
    nhac san cuc manh
    số điện thoại tư vấn pháp luật miễn phí
    văn phòng luật
    tổng đài tư vấn pháp luật
    dịch vụ thành lập công ty
    http://we-cooking.com/
    chém gió
    trung tâm tiếng anhng giống như hắn và Mã Lương quen biết từ trước. Chỉ là bởi vì Thường Hạo cũng là một trong những đệ tử của Đông long bát tông. lần này chọn hắn đi thường. Dầu sao, Thường Hạo đối với không gian ma pháp quả thực cũng có tạo nghệ phi thường.

    Thường Hạo nhún vai, nói:
    -Thì ta có nói gì đâu. Chúng ta đi như thế nào đây? Ta có bản đồ nơi này, ngươi có muốn tham khảo một

    ReplyDelete
  2. شركة تنظيف مكيفات بالرياض
    شركة غسيل مكيفات بالرياض
    أفضل شركة تنظيف مكيفات بالرياض
    شركة تنظيف مكيفات اسبليت بالرياض

    الكثير منا يتساءل عن عدم كفاءة المكيف بعد فترة من استخدامه ولا نعلم أن عدم تنظيف المكيف بشكل دوري يجعله يقوم بالعمل بأقل كفاءة لذا يجب أن نقوم بتنظيف المكيف بالطريقة الصحيحة والملائمة فيقوم فريق عمل أفضل شركة تنظيف مكيفات بالرياض بفك المكيف بطريقة سليمة والقيام بتنظيفه بأحدث الطرق العلمية كما تزوده الشركة بأحدث المواد المستخدمة والمعدات اللازمة لفك وتركيب المكيف بالإضافة إلى استخدام أجود أنواع المنظفات عالية الجودة والكفاءة الحاصله على تصريح من وزارة الصحة ولإرضاء عملائنا الكرام تقوم الشركة بتقديم عروض خاصة لكافه العملاء لتصل الخدمة لكافه الطبقات والفئات

    ReplyDelete
  3. Thanks for sharing such a good article and for informative things. Your articles are really amazing and I got a lot of information and guidance reading them.

    ReplyDelete

  4. Great post ! I am pretty much pleased with your good post.You put really very helpful information


    เว็บไซต์คาสิโนออนไลน์ที่ได้คุณภาพอับดับ 1 ของประเทศ
    เป็นเว็บไซต์การพนันออนไลน์ที่มีคนมา สมัคร Gclub Royal1688
    และยังมีหวยให้คุณได้เล่น สมัครหวยออนไลน์ ได้เลย
    สมัครสมาชิกที่นี่ >>> Gclub Royal1688
    ร่วมลงทุนสมัครเอเย่นคาสิโนกับทีมงานของเราได้เลย

    ReplyDelete
  5. thanks for sharing helpful article with us. Please write on the yojana also just like saral haryana.

    ReplyDelete
  6. Profesional Washing &

    Try My Items, a cost-free Job Me instrument so as to you deal with your listings. I've my own housekeeper, to whom I value significantly. They have got not usual to obtain two hours each time and 80 miles. Alternatively an certain cleaner is certainly by forget about means guaranteed sound operate, today they could get hired but once a home owner says they could no more have any dollars they are the first ever to proceed. They own charges and households and actions you can take and if indeed they are actually making subsequent to almost nothing with you, specifically how happen to be that they visualize to survive.افضل شركات تنظيف بالرياض
    الرحمة للخدمات المنزلية .شركة تنظيف ثريات بالرياض


    I've acquired and managed a rug cleaning program assistance for over 18 years and I am going to get also the last founder and owner of Aromatherapy Naturals- Natural Aromatherapy Washing Merchandise. We've had different cleaning people, but won't felt so pleased and happy. Just what a great experience working with Cleaning program Sailors. As far as persons saying that cleaners generate a lot for the task they do, you should bear in mind that they have bills also. This is very odd..... I just known as a neighbor of mine therefore that he and his wife can come to wash house for me. I actually is handy-capped so I actually is very restricted in what I can and cannot do. I are unable to use household cleaners (like for the bathroom since they choke me. I actually have had several extremely good house cleaners however they have gone to work making more cash.
    خدمات شركة تنظيف خزانات بالرياض
    ارخص شركة تنظيف فلل بالرياض
    شركة غسيل مكيفات بالرياض

    As a professional cleaner I can easily tell you that they have not even that terrible. Make all of them understand that you can be a professional in business regarding yourself (as perfectly while they happen to be); Our friendly, professional epidermis cleansers are trained, reliable, referenced, covered and dependable. For more facts on our services, preparation, or employee training, look free to call. I perform not require time nor perform I just want to clean my personal own condo. All of our house hold cleaners are interviewed, processed and professionally trained meant for a 2 to 5 week period working side-by-side with our manager to fully understandشركة تنظيف موكيت بالرياض
    شركة جلي بلاط في الرياض


    It alleviates their concerns and why don't we them recognize that almost all their home is great hands. You will seem to be for clients that really take pleasure in you and your hard operate. Besides gas, cleansing items, insurance, they aswell sometimes have to pay their particular medical health insurance of an individual or family program. But, you do not go in to nursing for the money you went into this to help people or fulfill a physician. We all can easily answer this which possesses a large amount of presumptions, personal experiences or perhaps easily come to a great arrangement on 2-5 several hours.ارخص شركة تنظيف منازل بالرياض
    اسعار رش مبيدات بالرياض

    ReplyDelete
  7. This comment has been removed by the author.

    ReplyDelete
  8. The team at Al-Nisr Al-Dhahabi Company is distinguished by its professionalism and dynamism, as it deals with each home individually and ensures that the client’s requirements are met effectively.

    ReplyDelete