Site icon NgDeveloper

AsyncTask with Broadcast Receiver in Android – Tutorial and Example

asynctask-with-broadcast-receiver-android-tutorial-example-featured
asynctask-with-broadcast-receiver-android-tutorial-example-blog

AsyncTask with Broadcast Receiver in Android:

What we are going to do ?
We are going to see an example for AsyncTask in Android with Broadcastreceiver. In our example we will be fetching the operator and circle information for the received
new SMS sender phone number.

What is AsyncTask & BroadcastReceiver?

AsyncTask:

AsyncTask is basically to do a aynchronous jobs in android, which is nothing but the background processes. We can use AsynCTask to call URL’s, to fetch some details from internet and any business logics which needs some URL to be called/some details need to be sent to any URL’s.

BroadCast Receiver:
Broadcast receiver is basically to observe the incoming requests such as messages/bluetooth requests etc. If we want any business logics on receiving new messages then onReceive method of BroadCast Receiver can help us to achieve it.

But we need to ensure always that the related permissions are added into the “AndroidManifest.xml

Below are the required permissions

To read the incoming messages,

<uses-permission android:name="android.permission.WRITE_SMS" />
<uses-permission android:name="android.permission.READ_SMS" />
<uses-permission android:name="android.permission.RECEIVE_SMS" />

To read/write files in the SDCard,

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

Internet, Network related permissions [wifi],

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />

Do we have anything like AsyncTask in android?

Yes. We have services, handlers and threads for similar requirements and out of all “services and AsyncTask” is the most recommended for any background process requirments in android.

 

When should I use What ?

AsyncTask: If your business logics need to be completed in 10Secs or it’s just a information fetching from internet like “fetching some result”, “sending messages through API”, “Fetching cricket score” etc.

Services: If you want to run the background processes for a long time says more than 30 secs to fetch wether details(background process should run all the time) or to download any files from internet etc.,

Note: I have used jSoup-1.7.2.jar to hit the URL and read the responses.

 

How to add an External Jar into the android project ?

1. Paste the jSoup.jar to the libs folder, libs folder exist in app folder.

Project structure for your reference,

2. Right click on the pasted jSoup JAR and Add as Library… to add the jar into the build path.
Add to module –> ok

 

 

How to create the apk file from the command prompt ?

1. Go to the project path in the command prompt

2. Run the “gradlew.bat assembleDebug” command

3. Now the apk file will be generated in the below path,
PROJECT\app\build\outputs\apk

URL to get the circle and Operator Details:

http://demo.ngdeveloper.com/AsyncTaskAndroid/GetCircleOpr.php?input=8124066089

We have called the above URL in our AsyncTask extended below class to get the operator and circle info. It’s just an example to hit the URL and to get some response. So exact operator and circle informations will not come.

doInBackground | onPostExecute | onPreExecute

When you execute this line, it will call the 

AsyncTask extended class

 FetchOprCircleInfo 

doInBackground

 method, which receives the inputs as String array. Its completely an independent process to the UI threads, once this process is done, it will return the response to the 

onPostExecute

 method, where you can write the UI display logics if any.

If you want to display any Progress Dialog of the background process status [which is mandatory when your application is downloading something from the internet], then you can override the 

onPreExecute

 method and show the progress, this will be called whenever the publish method is called.
fetchOprCircleInfo.execute(new String[]{jdCircleOprInfoURL});

MainActivity.java source code:

package com.ngdeveloper.asynctaskexample;

import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.AsyncTask;
import android.os.Bundle;
import android.telephony.SmsMessage;
import android.widget.TextView;
import android.widget.Toast;

import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;

public class MainActivity extends Activity {
private TextView incomeNum, incomeMsg,numOpr, numCircle;
IntentFilter iFilter;

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
iFilter = new IntentFilter("android.provider.Telephony.SMS_RECEIVED");
registerReceiver(myReceiver, iFilter);
incomeNum = (TextView) findViewById(R.id.Income_Msg_Number);
numOpr = (TextView) findViewById(R.id.Num_Operator);
numCircle = (TextView) findViewById(R.id.Num_Circle);
incomeMsg = (TextView) findViewById(R.id.Income_Msg);
}
private final BroadcastReceiver myReceiver = new BroadcastReceiver() {
public static final String SMS_BUNDLE = "pdus";

@Override
public void onReceive(Context context, Intent intent) {
Bundle intentExtras = intent.getExtras();
if (intentExtras != null) {
Object[] sms = (Object[]) intentExtras.get(SMS_BUNDLE);
String smsMessageStr = "";
for (int i = 0; i < sms.length; ++i) {
SmsMessage smsMessage = SmsMessage.createFromPdu((byte[]) sms[i]);
String smsBody = smsMessage.getMessageBody().toString();
// SMS body content
if (null!=smsBody) {
incomeMsg.setText("SMS Content :"+smsBody);
}

String address = smsMessage.getOriginatingAddress();
smsMessageStr += "SMS From: " + address + "\n";
Toast.makeText(context, smsMessageStr, Toast.LENGTH_LONG).show();
incomeNum.setText("SMS Received From :"+address.substring(3,address.length()));
try {
String jdCircleOprInfoURL = "http://demo.ngdeveloper.com/AsyncTaskAndroid/GetCircleOpr.php?input="+address.substring(3,address.length())+"";
FetchOprCircleInfo fetchOprCircleInfo = new FetchOprCircleInfo();
fetchOprCircleInfo.execute(new String[]{jdCircleOprInfoURL});
} catch (Exception e) {
Toast.makeText(context, "Javadomain.in-->" + e.getMessage(), Toast.LENGTH_LONG).show();
}
}
}
}

};

@Override
public void onDestroy() {
super.onDestroy();
unregisterReceiver(myReceiver);

}
public class FetchOprCircleInfo extends AsyncTask<String, Void, String> {
@Override
protected String doInBackground(String... reqArray) {
String responseStatus = "";
try {
if(reqArray!=null) {
if (null != reqArray[0]) {
// Jsoup used here
Document doc = Jsoup.connect(reqArray[0]).timeout(0).get();
if (doc != null) {
String result = doc.select("body").text();
responseStatus = result;
}
}
}
} catch (Throwable t) {
t.printStackTrace();
}
return responseStatus;
}

@Override
protected void onPostExecute(String result) {
String opr = "";
String circle = "";
if(null!=result && !result.isEmpty()){
if(result.contains("|")){
String[] splitPipe = result.split("\\|");
opr = splitPipe[0];
circle = splitPipe[1];
}
}

numOpr.setText("Operator : "+opr.toString());
numCircle.setText("Circle : "+circle.toString());
}
}
}

AndroidManifest.xml:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="in.javadomain.asynctaskexample" >
	<uses-permission android:name="android.permission.WRITE_SMS" />
	<uses-permission android:name="android.permission.READ_SMS" />
	<uses-permission android:name="android.permission.RECEIVE_SMS" />
	<uses-permission android:name="android.permission.INTERNET" />
	<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="AsyncTaskExample"
android:theme="@style/AppTheme" >
		<activity
android:name=".MainActivity"
android:label="@string/app_name" >
			<intent-filter>
				<action android:name="android.intent.action.MAIN" />

				<category android:name="android.intent.category.LAUNCHER" />
			</intent-filter>
		</activity>
	</application>
</manifest>

activity_main.xml:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:id="@+id/MainLayout">
	<TextView
android:layout_width="wrap_content"
android:layout_height="30dp"
android:textAppearance="?android:attr/textAppearanceLarge"
android:text="Javadomain.in AsyncTask"
android:id="@+id/textView"
android:layout_gravity="center_horizontal"
android:layout_marginTop="30dp" />
	<TextView
android:id="@+id/Income_Msg_Number"
android:layout_width="match_parent"
android:layout_height="30dp"
android:text=""
android:height="10dp"
android:layout_marginLeft="20dp"
android:layout_marginTop="50dp">
	</TextView>
	<TextView
android:id="@+id/Income_Msg"
android:layout_width="match_parent"
android:layout_height="30dp"
android:text=""
android:height="10dp"
android:layout_marginLeft="20dp"
android:layout_marginTop="50dp">
	</TextView>
	<TextView
android:id="@+id/Num_Operator"
android:layout_width="match_parent"
android:layout_height="30dp"
android:text=""
android:layout_marginLeft="20dp"
android:layout_marginTop="10dp">
	</TextView>
	<TextView
android:id="@+id/Num_Circle"
android:layout_width="match_parent"
android:layout_height="30dp"
android:text=""
android:layout_marginLeft="20dp"
android:layout_marginTop="10dp">
	</TextView>
</LinearLayout>

Output:

 Is it possible to call more than one AsyncTask ?

AsyncTask inside Asynctask like writting many URL hitting/accessing the internet one by one in doInBackground is bad practise and I could not make it work the way I want when I tried.

So if you want to try more than one URL hitting then you can do in the below way,

Write all your business logics in one file [accessing the internet many times with many URL’s] then move this file to your server.

Now you can hit only this URL, which internally hits all the other URL’s and returns the results. Which you can access in onPostExecute method.

If you want to continue any of your business logics or UI display works you can write all those logics/codes in onPostExecute method.

Note:

You can use more than one AsyncTask, but if all AsyncTask’s are dependent with each other, then we can not make it the way we want, since its a asynchronous process and result can not be sequentially provided to the next AsyncTask to continue the process.  Which may take more time at the background which may cause the ANR (Application Not Responding) issue.

If all the processes are independent then we can have more than one AsyncTask, but still there may be a chance for ANR.

How to return the onPostExecute response to UI ?

private TextView txtView;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
txtView = (TextView) findViewById(R.id.txtViewID);
}

then in onPostExecute method,

@Override
protected void onPostExecute(String result) {
numOpr.setText("AsyncTask Response : "+result);
}

Below are the solutions shared in the stackoverflow.com site for the onPostExecute result return issue, so try and share your comments,

super not called exception:

If you are getting the super not called exception then ensure that you have this below line, inside the onDestory() method. Always super.onDestory() should be called in first line.

super.onDestroy();
@Override
public void onDestroy() {
super.onDestroy();
unregisterReceiver(myReceiver);
}

Share your comments in comments section if any……

Exit mobile version