RSS

Most votes on android questions 4

Most votes on android questions 4. #31 How do I display an alert dialog on Android? #32 Fling gesture detection on grid layout #33 Run/install/debug Android applications over Wi-Fi? #34 findViewById in Fragment #35 R cannot be resolved - Android error #36 You need to use a Theme.AppCompat theme (or descendant) with this activity #37 Download a file with Android, and showing the progress in a ProgressDialog #38 Can't create handler inside thread that has not called Looper.prepare() #39 How to make links in a TextView clickable? #40 Android Studio: Add jar as library?

Read all the top votes questions and answers in a single page.

#31: How do I display an alert dialog on Android? (Score: 1133)

Created: 2010-01-22 Last updated: 2021-04-03

Tags: android, android-alertdialog, android-dialog

I want to display a dialog/popup window with a message to the user that shows “Are you sure you want to delete this entry?” with one button that says ‘Delete’. When Delete is touched, it should delete that entry, otherwise nothing.

I have written a click listener for those buttons, but how do I invoke a dialog or popup and its functionality?

#31 Best answer 1 of How do I display an alert dialog on Android? (Score: 1879)

Created: 2010-01-22 Last updated: 2019-02-22

You could use an AlertDialog for this and construct one using its Builder class. The example below uses the default constructor that only takes in a Context since the dialog will inherit the proper theme from the Context you pass in, but there’s also a constructor that allows you to specify a specific theme resource as the second parameter if you desire to do so.

new AlertDialog.Builder(context)
    .setTitle("Delete entry")
    .setMessage("Are you sure you want to delete this entry?")

    // Specifying a listener allows you to take an action before dismissing the dialog.
    // The dialog is automatically dismissed when a dialog button is clicked.
    .setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() {
        public void onClick(DialogInterface dialog, int which) { 
            // Continue with delete operation
        }
     })

    // A null listener allows the button to dismiss the dialog and take no further action.
    .setNegativeButton(android.R.string.no, null)
    .setIcon(android.R.drawable.ic_dialog_alert)
    .show();

#31 Best answer 2 of How do I display an alert dialog on Android?(Score: 375)

Created: 2012-11-22 Last updated: 2015-12-19

Try this code:

AlertDialog.Builder builder1 = new AlertDialog.Builder(context);
builder1.setMessage("Write your message here.");
builder1.setCancelable(true);

builder1.setPositiveButton(
    "Yes",
    new DialogInterface.OnClickListener() {
        public void onClick(DialogInterface dialog, int id) {
            dialog.cancel();
        }
    });

builder1.setNegativeButton(
    "No",
    new DialogInterface.OnClickListener() {
        public void onClick(DialogInterface dialog, int id) {
            dialog.cancel();
        }
    });

AlertDialog alert11 = builder1.create();
alert11.show();

See also original question in stackoverflow

#32: Fling gesture detection on grid layout (Score: 1129)

Created: 2009-06-01 Last updated: 2015-12-28

Tags: android, listener, gesture-recognition

I want to get fling gesture detection working in my Android application.

What I have is a GridLayout that contains 9 ImageViews. The source can be found here: Romain Guys’s Grid Layout.

That file I take is from Romain Guy’s Photostream application and has only been slightly adapted.

For the simple click situation I need only set the onClickListener for each ImageView I add to be the main activity which implements View.OnClickListener. It seems infinitely more complicated to implement something that recognizes a fling. I presume this is because it may span views?

  • If my activity implements OnGestureListener I don’t know how to set that as the gesture listener for the Grid or the Image views that I add.

     public class SelectFilterActivity extends Activity implements
        View.OnClickListener, OnGestureListener { ...
    
  • If my activity implements OnTouchListener then I have no onFling method to override (it has two events as parameters allowing me to determine if the fling was noteworthy).

     public class SelectFilterActivity extends Activity implements
         View.OnClickListener, OnTouchListener { ...
    
  • If I make a custom View, like GestureImageView that extends ImageView I don’t know how to tell the activity that a fling has occurred from the view. In any case, I tried this and the methods weren’t called when I touched the screen.

I really just need a concrete example of this working across views. What, when and how should I attach this listener? I need to be able to detect single clicks also.

// Gesture detection
mGestureDetector = new GestureDetector(this, new GestureDetector.SimpleOnGestureListener() {

    public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
        int dx = (int) (e2.getX() - e1.getX());
        // don't accept the fling if it's too short
        // as it may conflict with a button push
        if (Math.abs(dx) > MAJOR_MOVE && Math.abs(velocityX) > Math.absvelocityY)) {
            if (velocityX > 0) {
                moveRight();
            } else {
                moveLeft();
            }
            return true;
        } else {
            return false;
        }
    }
});

Is it possible to lay a transparent view over the top of my screen to capture flings?

If I choose not to inflate my child image views from XML can I pass the GestureDetector as a constructor parameter to a new subclass of ImageView that I create?

This is the very simple activity that I’m trying to get the fling detection to work for: SelectFilterActivity (Adapted from photostream).

I’ve been looking at these sources:

Nothing has worked for me so far and I was hoping for some pointers.

#32 Best answer 1 of Fling gesture detection on grid layout (Score: 826)

Created: 2009-06-02 Last updated: 2020-05-11

Thanks to Code Shogun, whose code I adapted to my situation.

Let your activity implement OnClickListener as usual:

public class SelectFilterActivity extends Activity implements OnClickListener {

  private static final int SWIPE_MIN_DISTANCE = 120;
  private static final int SWIPE_MAX_OFF_PATH = 250;
  private static final int SWIPE_THRESHOLD_VELOCITY = 200;
  private GestureDetector gestureDetector;
  View.OnTouchListener gestureListener;

  @Override
  protected void onCreate(Bundle savedInstanceState) {
	super.onCreate(savedInstanceState);

	/* ... */

	// Gesture detection
	gestureDetector = new GestureDetector(this, new MyGestureDetector());
	gestureListener = new View.OnTouchListener() {
      public boolean onTouch(View v, MotionEvent event) {
        return gestureDetector.onTouchEvent(event);
      }
	};

  }

  class MyGestureDetector extends SimpleOnGestureListener {
	@Override
	public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
      try {
        if (Math.abs(e1.getY() - e2.getY()) > SWIPE_MAX_OFF_PATH)
          return false;
        // right to left swipe
        if(e1.getX() - e2.getX() > SWIPE_MIN_DISTANCE && Math.abs(velocityX) > SWIPE_THRESHOLD_VELOCITY) {
          Toast.makeText(SelectFilterActivity.this, "Left Swipe", Toast.LENGTH_SHORT).show();
        } else if (e2.getX() - e1.getX() > SWIPE_MIN_DISTANCE && Math.abs(velocityX) > SWIPE_THRESHOLD_VELOCITY) {
          Toast.makeText(SelectFilterActivity.this, "Right Swipe", Toast.LENGTH_SHORT).show();
        }
      } catch (Exception e) {
         // nothing
      }
      return false;
	}

    @Override
    public boolean onDown(MotionEvent e) {
      return true;
    }
  }
}

Attach your gesture listener to all the views you add to the main layout;

// Do this for each view added to the grid
imageView.setOnClickListener(SelectFilterActivity.this); 
imageView.setOnTouchListener(gestureListener);

Watch in awe as your overridden methods are hit, both the onClick(View v) of the activity and the onFling of the gesture listener.

public void onClick(View v) {
  Filter f = (Filter) v.getTag();
  FilterFullscreenActivity.show(this, input, f);
}

The post ‘fling’ dance is optional but encouraged.

#32 Best answer 2 of Fling gesture detection on grid layout(Score: 211)

Created: 2011-04-20 Last updated: 2013-05-29

One of the answers above mentions handling different pixel density but suggests computing the swipe parameters by hand. It is worth noting that you can actually obtain scaled, reasonable values from the system using ViewConfiguration class:

final ViewConfiguration vc = ViewConfiguration.get(getContext());
final int swipeMinDistance = vc.getScaledPagingTouchSlop();
final int swipeThresholdVelocity = vc.getScaledMinimumFlingVelocity();
final int swipeMaxOffPath = vc.getScaledTouchSlop();
// (there is also vc.getScaledMaximumFlingVelocity() one could check against)

I noticed that using these values causes the “feel” of fling to be more consistent between the application and rest of system.

See also original question in stackoverflow

#33: Run/install/debug Android applications over Wi-Fi? (Score: 1116)

Created: 2011-02-04 Last updated: 2018-06-05

Tags: android, debugging, adb, wifi

I thought there was a way to test your applications in development over Wi-Fi. Is this possible?

I’d love to be able to untether my phone and develop wirelessly.

#33 Best answer 1 of Run/install/debug Android applications over Wi-Fi? (Score: 1815)

Created: 2012-04-19 Last updated: 2019-02-09

See forum post Any way to view Android screen remotely without root? - Post #9.

  1. Connect the device via USB and make sure debugging is working;
  2. adb tcpip 5555. This makes the device to start listening for connections on port 5555;
  3. Look up the device IP address with adb shell netcfg or adb shell ifconfig with 6.0 and higher;
  4. You can disconnect the USB now;
  5. adb connect <DEVICE_IP_ADDRESS>:5555. This connects to the server we set up on the device on step 2;
  6. Now you have a device over the network with which you can debug as usual.

To switch the server back to the USB mode, run adb usb, which will put the server on your phone back to the USB mode. If you have more than one device, you can specify the device with the -s option: adb -s <DEVICE_IP_ADDRESS>:5555 usb.

No root required!

To find the IP address of the device: run adb shell and then netcfg. You’ll see it there. To find the IP address while using OSX run the command adb shell ip route.


WARNING: leaving the option enabled is dangerous, anyone in your network can connect to your device in debug, even if you are in data network. Do it only when connected to a trusted Wi-Fi and remember to disconnect it when done!


@Sergei suggested that line 2 should be modified, commenting: “-d option needed to connect to the USB device when the other connection persists (for example, emulator connected or other Wi-Fi device)”.

This information may prove valuable to future readers, but I rolled-back to the original version that had received 178 upvotes.


On some device you can do the same thing even if you do not have an USB cable:

  1. Enable ADB over network in developer setting Screenshot Showing the option on It should show the IP address
  2. adb connect <DEVICE_IP_ADDRESS>:5555
  3. Disable the setting when done

Using Android Studio there is a plugin allowing you to connect USB Debugging without the need of using any ADB command from a terminal.

#33 Best answer 2 of Run/install/debug Android applications over Wi-Fi?(Score: 137)

Created: 2016-08-25 Last updated: 2016-08-25

(No root required) There is one best, easy and with UI method for Android Studio

IntelliJ and Android Studio plugin created to quickly connect your Android device over WiFi to install, run and debug your applications without a USB connected. Press one button and forget about your USB cable.

just install plugin Android WiFi ADB

Download and install Android WiFi ADB directly from

Intellij / Android Studio: Preferences/Settings->Plugins->Browse Repositories

enter image description here

enter image description here

.

Remember! for first time to initialize the device you must have to connect using usb

Alternatively, you can download the plugin from the JetBrains plugin site and install it manually in: Preferences/Settings->Plugins->Install plugin from disk.

You can connect and manage your devices easily……. for more information read here https://github.com/pedrovgs/AndroidWiFiADB

See also original question in stackoverflow

#34: findViewById in Fragment (Score: 1104)

Created: 2011-06-27 Last updated: 2017-12-01

Tags: android, android-fragments, android-imageview, findviewbyid

I am trying to create an ImageView in a Fragment which will refer to the ImageView element which I have created in the XML for the Fragment. However, the findViewById method only works if I extend an Activity class. Is there anyway of which I can use it in Fragment as well?

public class TestClass extends Fragment {
	public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        ImageView imageView = (ImageView)findViewById(R.id.my_image);
        return inflater.inflate(R.layout.testclassfragment, container, false);
	}
}

The findViewById method has an error on it which states that the method is undefined.

#34 Best answer 1 of findViewById in Fragment (Score: 1506)

Created: 2011-06-27 Last updated: 2017-09-03

Use getView() or the View parameter from implementing the onViewCreated method. It returns the root view for the fragment (the one returned by onCreateView() method). With this you can call findViewById().

@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
    ImageView imageView = (ImageView) getView().findViewById(R.id.foo);
    // or  (ImageView) view.findViewById(R.id.foo); 

As getView() works only after onCreateView(), you can’t use it inside onCreate() or onCreateView() methods of the fragment .

#34 Best answer 2 of findViewById in Fragment(Score: 638)

Created: 2011-06-27 Last updated: 2015-07-02

You need to inflate the Fragment’s view and call findViewById() on the View it returns.

public View onCreateView(LayoutInflater inflater, 
                         ViewGroup container, 
                         Bundle savedInstanceState) {
     View view = inflater.inflate(R.layout.testclassfragment, container, false);
     ImageView imageView = (ImageView) view.findViewById(R.id.my_image);
     return view;
}

See also original question in stackoverflow

#35: R cannot be resolved - Android error (Score: 1094)

Created: 2009-05-19 Last updated: 2016-06-16

Tags: android, eclipse, compiler-errors, android-resources, android-sdk-tools

I just downloaded and installed the new Android SDK. I wanted to create a simple application to test drive it.

The wizard created this code:

package eu.mauriziopz.gps;

import android.app.Activity;
import android.os.Bundle;

public class ggps extends Activity {
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
    }
}

but Eclipse gives me the error

R cannot be resolved

on line

setContentView(R.layout.main);

Why?

PS: I do have an XML file named main.xml under res/layout/.

#35 Best answer 1 of R cannot be resolved - Android error (Score: 844)

Created: 2010-07-15 Last updated: 2012-08-13

After tracking down this problem as well, I found this note in the Android documentation:

http://source.android.com/source/using-eclipse.html

Note: Eclipse sometimes likes to add an “import android.R” statement at the top of your files that use resources, especially when you ask Eclipse to sort or otherwise manage imports. This will cause your make to break. Look out for these erroneous import statements and delete them.

While going through the Android sample tutorials, I would often use the Ctrl + Shift + O command to “Organize Imports” and generate any missing import statements. Sometimes this would generate the incorrect import statement which would hide the R.java class that is automatically generated when you build.

#35 Best answer 2 of R cannot be resolved - Android error(Score: 393)

Created: 2010-01-27 Last updated: 2012-03-13

Each time I had a problem with R not been generated, or even disappeared, this was due to some problem in the XML layout file that prevented the application from being built.

See also original question in stackoverflow

#36: You need to use a Theme.AppCompat theme (or descendant) with this activity (Score: 1086)

Created: 2014-02-16 Last updated: 2020-01-20

Tags: android, android-layout

Android Studio 0.4.5

Android documentation for creating custom dialog boxes: http://developer.android.com/guide/topics/ui/dialogs.html

If you want a custom dialog, you can instead display an Activity as a dialog instead of using the Dialog APIs. Simply create an activity and set its theme to Theme.Holo.Dialog in the <activity> manifest element:

<activity android:theme="@android:style/Theme.Holo.Dialog" >

However, when I tried this I get the following exception:

java.lang.IllegalStateException: You need to use a Theme.AppCompat theme (or descendant) with this activity

I am supporting the following, and I can’t using something greater than 10 for the min:

minSdkVersion 10
targetSdkVersion 19

In my styles I have the following:

<!-- Base application theme. -->
    <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">

And in my manifest I have this for the activity:

 <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:theme="@android:style/Theme.Holo.Light.Dialog"
            android:name="com.ssd.register.Dialog_update"
            android:label="@string/title_activity_dialog_update" >
        </activity>

Creating the dialog box like this was something I was hopping to do, as I have already completed the layout.

Can anyone tell me how I can get around this problem?

#36 Best answer 1 of You need to use a Theme.AppCompat theme (or descendant) with this activity (Score: 1161)

Created: 2014-02-16 Last updated: 2017-06-13

The reason you are having this problem is because the activity you are trying to apply the dialog theme to is extending ActionBarActivity which requires the AppCompat theme to be applied.

Update: Extending AppCompatActivity would also have this problem

In this case, change the Java inheritance from ActionBarActivity to Activity and leave the dialog theme in the manifest as it is, a non Theme.AppCompat value


The general rule is that if you want your code to support older versions of Android, it should have the AppCompat theme and the java code should extend AppCompatActivity. If you have *an activity that doesn’t need this support, such as you only care about the latest versions and features of Android, you can apply any theme to it but the java code must extend plain old Activity.


NOTE: When change from AppCompatActivity (or a subclass, ActionBarActivity), to Activity, must also change the various calls with “support” to the corresponding call without “support”. So, instead of getSupportFragmentManager, call getFragmentManager.

#36 Best answer 2 of You need to use a Theme.AppCompat theme (or descendant) with this activity(Score: 572)

Created: 2014-09-04 Last updated: 2014-09-04

All you need to do is add android:theme="@style/Theme.AppCompat.Light" to your application tag in the AndroidManifest.xml file.

See also original question in stackoverflow

#37: Download a file with Android, and showing the progress in a ProgressDialog (Score: 1082)

Created: 2010-06-12 Last updated: 2014-11-26

Tags: java, android, download, android-asynctask

I am trying to write a simple application that gets updated. For this I need a simple function that can download a file and show the current progress in a ProgressDialog. I know how to do the ProgressDialog, but I’m not sure how to display the current progress and how to download the file in the first place.

#37 Best answer 1 of Download a file with Android, and showing the progress in a ProgressDialog (Score: 1913)

Created: 2010-06-12 Last updated: 2019-11-06

There are many ways to download files. Following I will post most common ways; it is up to you to decide which method is better for your app.

  1. Use AsyncTask and show the download progress in a dialog =============================================================

This method will allow you to execute some background processes and update the UI at the same time (in this case, we’ll update a progress bar).

Imports:

import android.os.PowerManager;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.FileOutputStream;
import java.net.HttpURLConnection;

This is an example code:

// declare the dialog as a member field of your activity
ProgressDialog mProgressDialog;

// instantiate it within the onCreate method
mProgressDialog = new ProgressDialog(YourActivity.this);
mProgressDialog.setMessage("A message");
mProgressDialog.setIndeterminate(true);
mProgressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
mProgressDialog.setCancelable(true);

// execute this when the downloader must be fired
final DownloadTask downloadTask = new DownloadTask(YourActivity.this);
downloadTask.execute("the url to the file you want to download");

mProgressDialog.setOnCancelListener(new DialogInterface.OnCancelListener() {

    @Override
    public void onCancel(DialogInterface dialog) {
        downloadTask.cancel(true); //cancel the task
    }
});

The AsyncTask will look like this:

// usually, subclasses of AsyncTask are declared inside the activity class.
// that way, you can easily modify the UI thread from here
private class DownloadTask extends AsyncTask<String, Integer, String> {

    private Context context;
    private PowerManager.WakeLock mWakeLock;

    public DownloadTask(Context context) {
        this.context = context;
    }

    @Override
    protected String doInBackground(String... sUrl) {
        InputStream input = null;
        OutputStream output = null;
        HttpURLConnection connection = null;
        try {
            URL url = new URL(sUrl[0]);
            connection = (HttpURLConnection) url.openConnection();
            connection.connect();

            // expect HTTP 200 OK, so we don't mistakenly save error report
            // instead of the file
            if (connection.getResponseCode() != HttpURLConnection.HTTP_OK) {
                return "Server returned HTTP " + connection.getResponseCode()
                        + " " + connection.getResponseMessage();
            }

            // this will be useful to display download percentage
            // might be -1: server did not report the length
            int fileLength = connection.getContentLength();

            // download the file
            input = connection.getInputStream();
            output = new FileOutputStream("/sdcard/file_name.extension");

            byte data[] = new byte[4096];
            long total = 0;
            int count;
            while ((count = input.read(data)) != -1) {
                // allow canceling with back button
                if (isCancelled()) {
                    input.close();
                    return null;
                }
                total += count;
                // publishing the progress....
                if (fileLength > 0) // only if total length is known
                    publishProgress((int) (total * 100 / fileLength));
                output.write(data, 0, count);
            }
        } catch (Exception e) {
            return e.toString();
        } finally {
            try {
                if (output != null)
                    output.close();
                if (input != null)
                    input.close();
            } catch (IOException ignored) {
            }

            if (connection != null)
                connection.disconnect();
        }
        return null;
    }

The method above (doInBackground) runs always on a background thread. You shouldn’t do any UI tasks there. On the other hand, the onProgressUpdate and onPreExecute run on the UI thread, so there you can change the progress bar:

    @Override
    protected void onPreExecute() {
        super.onPreExecute();
        // take CPU lock to prevent CPU from going off if the user 
        // presses the power button during download
        PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
        mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
             getClass().getName());
        mWakeLock.acquire();
        mProgressDialog.show();
    }
    
    @Override
    protected void onProgressUpdate(Integer... progress) {
        super.onProgressUpdate(progress);
        // if we get here, length is known, now set indeterminate to false
        mProgressDialog.setIndeterminate(false);
        mProgressDialog.setMax(100);
        mProgressDialog.setProgress(progress[0]);
    }

    @Override
    protected void onPostExecute(String result) {
        mWakeLock.release();
        mProgressDialog.dismiss();
        if (result != null)
            Toast.makeText(context,"Download error: "+result, Toast.LENGTH_LONG).show();
        else
            Toast.makeText(context,"File downloaded", Toast.LENGTH_SHORT).show();
    }

For this to run, you need the WAKE_LOCK permission.

<uses-permission android:name="android.permission.WAKE_LOCK" />
  1. Download from Service ========================

The big question here is: how do I update my activity from a service?. In the next example we are going to use two classes you may not be aware of: ResultReceiver and IntentService. ResultReceiver is the one that will allow us to update our thread from a service; IntentService is a subclass of Service which spawns a thread to do background work from there (you should know that a Service runs actually in the same thread of your app; when you extends Service, you must manually spawn new threads to run CPU blocking operations).

Download service can look like this:

public class DownloadService extends IntentService {
    public static final int UPDATE_PROGRESS = 8344;

    public DownloadService() {
        super("DownloadService");
    }
    @Override
    protected void onHandleIntent(Intent intent) {

        String urlToDownload = intent.getStringExtra("url");
        ResultReceiver receiver = (ResultReceiver) intent.getParcelableExtra("receiver");
        try {
            
            //create url and connect
            URL url = new URL(urlToDownload);
            URLConnection connection = url.openConnection();
            connection.connect();

            // this will be useful so that you can show a typical 0-100% progress bar
            int fileLength = connection.getContentLength();

            // download the file
            InputStream input = new BufferedInputStream(connection.getInputStream());

            String path = "/sdcard/BarcodeScanner-debug.apk" ;
            OutputStream output = new FileOutputStream(path);

            byte data[] = new byte[1024];
            long total = 0;
            int count;
            while ((count = input.read(data)) != -1) {
                total += count;

                // publishing the progress....
                Bundle resultData = new Bundle();
                resultData.putInt("progress" ,(int) (total * 100 / fileLength));
                receiver.send(UPDATE_PROGRESS, resultData);
                output.write(data, 0, count);
            }

            // close streams 
            output.flush();
            output.close();
            input.close();

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

        Bundle resultData = new Bundle();
        resultData.putInt("progress" ,100);

        receiver.send(UPDATE_PROGRESS, resultData);
    }
}

Add the service to your manifest:

<service android:name=".DownloadService"/>

And the activity will look like this:

// initialize the progress dialog like in the first example

// this is how you fire the downloader
mProgressDialog.show();
Intent intent = new Intent(this, DownloadService.class);
intent.putExtra("url", "url of the file to download");
intent.putExtra("receiver", new DownloadReceiver(new Handler()));
startService(intent);

Here is were ResultReceiver comes to play:

private class DownloadReceiver extends ResultReceiver{

    public DownloadReceiver(Handler handler) {
        super(handler);
    }

    @Override
    protected void onReceiveResult(int resultCode, Bundle resultData) {

        super.onReceiveResult(resultCode, resultData);

        if (resultCode == DownloadService.UPDATE_PROGRESS) {

            int progress = resultData.getInt("progress"); //get the progress
            dialog.setProgress(progress);

            if (progress == 100) {
                dialog.dismiss();
            }
        }
    }
}

2.1 Use Groundy library

Groundy is a library that basically helps you run pieces of code in a background service, and it is based on the ResultReceiver concept shown above. This library is deprecated at the moment. This is how the whole code would look like:

The activity where you are showing the dialog…

public class MainActivity extends Activity {

    private ProgressDialog mProgressDialog;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        findViewById(R.id.btn_download).setOnClickListener(new View.OnClickListener() {
            public void onClick(View view) {
                String url = ((EditText) findViewById(R.id.edit_url)).getText().toString().trim();
                Bundle extras = new Bundler().add(DownloadTask.PARAM_URL, url).build();
                Groundy.create(DownloadExample.this, DownloadTask.class)
                        .receiver(mReceiver)
                        .params(extras)
                        .queue();

                mProgressDialog = new ProgressDialog(MainActivity.this);
                mProgressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
                mProgressDialog.setCancelable(false);
                mProgressDialog.show();
            }
        });
    }

    private ResultReceiver mReceiver = new ResultReceiver(new Handler()) {
        @Override
        protected void onReceiveResult(int resultCode, Bundle resultData) {
            super.onReceiveResult(resultCode, resultData);
            switch (resultCode) {
                case Groundy.STATUS_PROGRESS:
                    mProgressDialog.setProgress(resultData.getInt(Groundy.KEY_PROGRESS));
                    break;
                case Groundy.STATUS_FINISHED:
                    Toast.makeText(DownloadExample.this, R.string.file_downloaded, Toast.LENGTH_LONG);
                    mProgressDialog.dismiss();
                    break;
                case Groundy.STATUS_ERROR:
                    Toast.makeText(DownloadExample.this, resultData.getString(Groundy.KEY_ERROR), Toast.LENGTH_LONG).show();
                    mProgressDialog.dismiss();
                    break;
            }
        }
    };
}

A GroundyTask implementation used by Groundy to download the file and show the progress:

public class DownloadTask extends GroundyTask {    
    public static final String PARAM_URL = "com.groundy.sample.param.url";

    @Override
    protected boolean doInBackground() {
        try {
            String url = getParameters().getString(PARAM_URL);
            File dest = new File(getContext().getFilesDir(), new File(url).getName());
            DownloadUtils.downloadFile(getContext(), url, dest, DownloadUtils.getDownloadListenerForTask(this));
            return true;
        } catch (Exception pokemon) {
            return false;
        }
    }
}

And just add this to the manifest:

<service android:name="com.codeslap.groundy.GroundyService"/>

It couldn’t be easier I think. Just grab the latest jar from Github and you are ready to go. Keep in mind that Groundy’s main purpose is to make calls to external REST apis in a background service and post results to the UI with easily. If you are doing something like that in your app, it could be really useful.

2.2 Use https://github.com/koush/ion

  1. Use DownloadManager class (GingerBread and newer only) =============================================================

GingerBread brought a new feature, DownloadManager, which allows you to download files easily and delegate the hard work of handling threads, streams, etc. to the system.

First, let’s see a utility method:

/**
 * @param context used to check the device version and DownloadManager information
 * @return true if the download manager is available
 */
public static boolean isDownloadManagerAvailable(Context context) {

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD) {
        return true;
    }
    return false;
}

Method’s name explains it all. Once you are sure DownloadManager is available, you can do something like this:

String url = "url you want to download";
DownloadManager.Request request = new DownloadManager.Request(Uri.parse(url));
request.setDescription("Some descrition");
request.setTitle("Some title");
// in order for this if to run, you must use the android 3.2 to compile your app
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
    request.allowScanningByMediaScanner();
    request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);
}
request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, "name-of-the-file.ext");

// get download service and enqueue file
DownloadManager manager = (DownloadManager) getSystemService(Context.DOWNLOAD_SERVICE);
manager.enqueue(request);

Download progress will be showing in the notification bar.

Final thoughts

First and second methods are just the tip of the iceberg. There are lots of things you have to keep in mind if you want your app to be robust. Here is a brief list:

  • You must check whether user has an internet connection available
  • Make sure you have the right permissions (INTERNET and WRITE_EXTERNAL_STORAGE); also ACCESS_NETWORK_STATE if you want to check internet availability.
  • Make sure the directory were you are going to download files exist and has write permissions.
  • If download is too big you may want to implement a way to resume the download if previous attempts failed.
  • Users will be grateful if you allow them to interrupt the download.

Unless you need detailed control of the download process, then consider using DownloadManager (3) because it already handles most of the items listed above.

But also consider that your needs may change. For example, DownloadManager does no response caching. It will blindly download the same big file multiple times. There’s no easy way to fix it after the fact. Where if you start with a basic HttpURLConnection (1, 2), then all you need is to add an HttpResponseCache. So the initial effort of learning the basic, standard tools can be a good investment.

This class was deprecated in API level 26. ProgressDialog is a modal dialog, which prevents the user from interacting with the app. Instead of using this class, you should use a progress indicator like ProgressBar, which can be embedded in your app’s UI. Alternatively, you can use a notification to inform the user of the task’s progress. For more details Link

#37 Best answer 2 of Download a file with Android, and showing the progress in a ProgressDialog(Score: 110)

Created: 2011-08-29 Last updated: 2015-04-24

Don’t forget to add permissions to your manifest file if you’re gonna be downloading stuff from the internet!

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.helloandroid"
    android:versionCode="1"
    android:versionName="1.0">

        <uses-sdk android:minSdkVersion="10" />
    
        <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"></uses-permission>
        <uses-permission android:name="android.permission.INTERNET"></uses-permission>
        <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"></uses-permission>
        <uses-permission android:name="android.permission.READ_PHONE_STATE"></uses-permission>
    
        <application 
            android:icon="@drawable/icon" 
            android:label="@string/app_name" 
            android:debuggable="true">

        </application>

</manifest>

See also original question in stackoverflow

#38: Can't create handler inside thread that has not called Looper.prepare() (Score: 1069)

Created: 2010-10-06 Last updated: 2018-06-29

Tags: android, ui-thread, android-toast

What does the following exception mean; how can I fix it?

This is the code:

Toast toast = Toast.makeText(mContext, "Something", Toast.LENGTH_SHORT);

This is the exception:

java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
     at android.os.Handler.<init>(Handler.java:121)
     at android.widget.Toast.<init>(Toast.java:68)
     at android.widget.Toast.makeText(Toast.java:231)

#38 Best answer 1 of Can't create handler inside thread that has not called Looper.prepare() (Score: 890)

Created: 2012-03-22 Last updated: 2017-05-23

You need to call Toast.makeText(...) from the UI thread:

activity.runOnUiThread(new Runnable() {
  public void run() {
    Toast.makeText(activity, "Hello", Toast.LENGTH_SHORT).show();
  }
});

This is copy-pasted from another (duplicate) SO answer.

#38 Best answer 2 of Can't create handler inside thread that has not called Looper.prepare()(Score: 755)

Created: 2010-10-06 Last updated: 2021-03-24

You’re calling it from a worker thread. You need to call Toast.makeText() (and most other functions dealing with the UI) from within the main thread. You could use a handler, for example.

Look up Communicating with the UI Thread in the documentation. In a nutshell:

// Set this up in the UI thread.

mHandler = new Handler(Looper.getMainLooper()) {
    @Override
    public void handleMessage(Message message) {
        // This is where you do your work in the UI thread.
        // Your worker tells you in the message what to do.
    }
};

void workerThread() {
    // And this is how you call it from the worker thread:
    Message message = mHandler.obtainMessage(command, parameter);
    message.sendToTarget();
}

Other options:

You could use Activity.runOnUiThread(). Straightforward if you have an Activity:

@WorkerThread
void workerThread() {
    myActivity.runOnUiThread(() -> {
        // This is where your UI code goes.
    }
}

You could also post to the main looper. This works great if all you have is a Context.

@WorkerThread
void workerThread() {
    ContextCompat.getMainExecutor(context).execute(()  -> {
        // This is where your UI code goes.
    }
}

Deprecated:

You could use an AsyncTask, that works well for most things running in the background. It has hooks that you can call to indicate the progress, and when it’s done.

It’s convenient, but can leak contexts if not used correctly. It’s been officially deprecated, and you shouldn’t use it anymore.

See also original question in stackoverflow

Created: 2010-04-29 Last updated: 2019-11-27

Tags: android, hyperlink, textview, clickable

I have the following TextView defined:

<TextView android:layout_width="wrap_content"
	android:layout_height="wrap_content" android:text="@string/txtCredits"
	android:autoLink="web" android:id="@+id/infoTxtCredits"
	android:layout_centerInParent="true"
	android:linksClickable="true"></TextView>

where @string/txtCredits is a string resource that contains <a href="some site">Link text</a>.

Android is highlighting the links in the TextView, but they do not respond to clicks. Can someone tell me what I’m doing wrong? Do I have to set an onClickListener for the TextView in my activity for something as simple as this?

Looks like it has to do with the way I define my string resource. This does not work:

<string name="txtCredits"><a href="http://www.google.com">Google</a></string>

But this does:

<string name="txtCredits">www.google.com</string>

Which is a bummer because I would much rather show a text link than show the full URL.

Created: 2010-04-30 Last updated: 2017-07-26

Buried in the API demos I found the solution to my problem:

Link.java:

    // text2 has links specified by putting <a> tags in the string
    // resource.  By default these links will appear but not
    // respond to user input.  To make them active, you need to
    // call setMovementMethod() on the TextView object.

    TextView t2 = (TextView) findViewById(R.id.text2);
    t2.setMovementMethod(LinkMovementMethod.getInstance());

I removed most of the attributes on my TextView to match what was in the demo.

<TextView
    android:id="@+id/text2"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="@string/txtCredits"/>

That solved it. Pretty difficult to uncover and fix.

Important: Don’t forget to remove autoLink="web" if you are calling setMovementMethod().

Created: 2010-04-29

I’m using only android:autoLink="web" and it works fine. A click on the link opens the browser and shows the correct page.

One thing I could guess is that some other view is above the link. Something that is transparent fills the whole parent but don’t displays anything above the link. In this case the click goes to this view instead of the link.

See also original question in stackoverflow

#40: Android Studio: Add jar as library? (Score: 1050)

Created: 2013-05-17 Last updated: 2019-02-27

Tags: android, gradle, android-gradle-plugin, gson, dependency-management

I’m trying to use the new Android Studio but I can’t seem to get it working correctly.

I’m using the Gson library to serialize/deserialize JSON-objects. But the library somehow isn’t included in the build.

I had created a new project with just a MainActivity. Copied gson-2.2.3.jar in the /libs folder and added it as a library dependancy(right click->Add as library). This includes the jar in android studio so it can be referenced from the source files.

When I try to run the project it cannot compile so I added:

compile files('libs/gson-2.2.3.jar')

to the dependencies in de .gradle file. After that it compiles correctly but when running the application I get a ClassDefNotFoundException.

Does anyone know what I’m doing wrong?

#40 Best answer 1 of Android Studio: Add jar as library? (Score: 1543)

Created: 2013-05-18 Last updated: 2018-04-13

I’ve been struggling with the same thing for many hours, trying to get the Gson jar to work no less. I finally cracked it – here are the steps I took:

  1. Put the Gson jar (in my case, gson-2.2.4.jar) into the libs folder

  2. Right click it and hit ‘Add as library’

  3. Ensure that compile files('libs/gson-2.2.4.jar') is in your build.gradle file (or compile fileTree(dir: 'libs', include: '*.jar') if you are using many jar files)

    Edit : Use implementation files('libs/gson-2.2.4.jar') (or implementation fileTree(dir: 'libs', include: '*.jar')) in Android Studio 3.0+

  4. Do a clean build (you can probably do this fine in Android Studio, but to make sure I navigated in a terminal to the root folder of my app and typed gradlew clean. I’m on Mac OS X, the command might be different on your system

After I did the above four, it started working fine. I think the ‘Add as library’ step was the one I’d previously missed, and it didn’t work until I cleaned it either.

[Edit - added the build.gradle step which is also necessary as others have pointed out]

#40 Best answer 2 of Android Studio: Add jar as library?(Score: 271)

Created: 2013-08-19 Last updated: 2015-12-18

Here are the instructions for adding a local jar file as a library to a module:

  1. Create a ‘libs’ folder in the top level of the module directory (the same directory that contains the ‘src’ directory)

  1. In the build.gradle file add the following so that your dependencies closure has:

     dependencies {
         // ... other dependencies
         compile files('libs/<your jar's name here>')
     }
    
  2. Android Studio should have already setup a gradlew wrapper. From the command line, navigate to the top level of your project (the directory that has a gradlew file).

Run ./gradlew assemble. This should compile the project with the library. You may need to fix errors in your build.gradle file as necessary.

  1. In order to have Android Studio recognize the local jar files as libraries for support while coding in the IDE, you need to take a few more steps:

4.1. Right click on the module in the left hand panel and choose Open Library Settings.

4.2. On the left panel of the dialog, choose Libraries.

4.3. Click the + sign above the panel second from the left -> Java

Menu

4.4. Select your local jar and add it to the project.

  1. You may need to run the above ./gradlew command one more time

See also original question in stackoverflow


Notes:
  1. This page use API to get the relevant data from stackoverflow community.
  2. Content license on this page is CC BY-SA 3.0.
  3. score = up votes - down votes.