Thursday, 26 April 2012

LocalBroadcastManager: Intra application message passing

Using Broadcast receivers is good practice if you want to send and receive data between different applications. However its not good at all if you are using them for communication internal to application.


There are many reasons for NOT using broadcast:
  1.  A broadcast is sent system-wide, so this is not performance efficient.
  2.  When we use broadcast receiver and sender, any other application can send and receives broadcast messages to and from our application. This can be a serious security thread for our application.


Read more about security issues and configuration of broadcast at developer.android
Instead of using normal broadcast we should use Local broadcast for sending and receiving in-app messages between activities and services. Local broadcast is included in android 3.0 and is provided as support package v4 for early release development. For setting up support library read developer.android


ResultReceiver can be used to return data back to activity. Here is a simple IntentService: Providing data back to Activity #android .However by ResultRceiver, we can only return data to that specific activity which started the service.


To send data/intent application-wide, LocalBroadcasts should be used. LocalBroadcastManager is used to send and receive local broadcast. Lets start with a simple example. We have a simple IntentService say MyIntentService:

package sohail.aziz.mylocalbroadcast;

import android.app.IntentService;
import android.content.Intent;
import android.support.v4.content.LocalBroadcastManager;
import android.util.Log;

public class MyIntentService extends IntentService{

//ACTION should include application package convention, just to show that this can
//be any string
    public static final String ACTION="mycustomactionstring";
    
    public MyIntentService() {
        super("MyIntentService");
        // TODO Auto-generated constructor stub
       Log.d("sohail","service started");
    }

    @Override
    protected void onHandleIntent(Intent arg0) {
        // TODO Auto-generated method stub
        
        Log.d("sohail","onHandleIntent called");
        Intent in=new Intent(ACTION);  //you can put anything in it with putExtra
        Log.d("sohail","sending broadcast");
        LocalBroadcastManager.getInstance(this).sendBroadcast(in);
        
        
    }

}


A simple IntentService which sends local broadcast application-wide. Lets receive this in activity.
package sohail.aziz.mylocalbroadcast;

import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.support.v4.content.LocalBroadcastManager;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;

public class MylocalbroadcastExampleActivity extends Activity implements OnClickListener{
    /** Called when the activity is first created. */
       
    TextView tv;
    Button bt;
    @Override
    protected void onPause() {
        // TODO Auto-generated method stub
        super.onPause();
        
        LocalBroadcastManager.getInstance(this).unregisterReceiver(onNotice);
    }
    @Override
    protected void onResume() {
        // TODO Auto-generated method stub
        super.onResume();
        
        IntentFilter iff= new IntentFilter(MyIntentService.ACTION);
        LocalBroadcastManager.getInstance(this).registerReceiver(onNotice, iff);
    }
    
    private BroadcastReceiver onNotice= new BroadcastReceiver() {
        
        @Override
        public void onReceive(Context context, Intent intent) {
            // intent can contain anydata
            Log.d("sohail","onReceive called");
            tv.setText("Broadcast received !");
        
        }
    };
    
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        
        tv=(TextView)findViewById(R.id.tvResults);
        
        bt= (Button)findViewById(R.id.btStart);
        bt.setOnClickListener(this);
        
    }
    @Override
    public void onClick(View v) {
        
        if(v.getId()==R.id.btStart){
            
            Log.d("sohail","starting service");
            Intent i= new Intent(this, MyIntentService.class);
            startService(i);
        }
    }
}

Here we are registering broadcast receiver onNotice as LocalBroadcast Receiver. Intent-filter is defined with ACTION defined in MyIntentService.


You just need to define service in AndroidManifest.xml:
 <service
 android:name=".MyIntentService" 
 ></service>

and thats it !
 
Browse and download source MyLocalbroadcastManager.

Sunday, 22 April 2012

IntentService: Providing data back to Activity #android

It is advisable to use thread/asynTask or Service to handle long running task such as file I/O, internet access etc. IntentService is simple, easy to use and take care of many hectic tasks for You.Read more about IntentService at
developer.android . A simple use case of the topic can be:
  1. Your activity send a web request to IntentService to process.
  2.  Your IntentService execute that request using DefaultHttpClient.
  3.  And Return results (whatever, true,false list of objects/records etc) back to the calling activity.
Now the task is to return the results back to the activity. There are two options available either we can use Broadcast receiver or ResultReceiver.
  • Broadcast should be used if you want to send data/notifications across applications, whenever you send broadcast its sent system wide read more about broadcast receivers at developer.android.
  •  Result receiver is an interface you implement and pass it to the intentService through putExtra. IntentService then fetch this object and call its receiver.send function to send anything (in bundle) to calling activity[who started the intentservice]. Result receiver has preference over broadcast receivers if your all communication is internal to your application.

Lets start, First we need to have our own receiver class extended from ResultReceiver and containing Receiver Interface. Lets say its MyResultReceiver:

package sohail.aziz.service;

import android.os.Bundle;
import android.os.Handler;
import android.os.ResultReceiver;

public class MyResultReceiver extends ResultReceiver {

    private Receiver mReceiver;

    public MyResultReceiver(Handler handler) {
        super(handler);
        // TODO Auto-generated constructor stub
    }

    public interface Receiver {
        public void onReceiveResult(int resultCode, Bundle resultData);

    }

    public void setReceiver(Receiver receiver) {
        mReceiver = receiver;
    }

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

        if (mReceiver != null) {
            mReceiver.onReceiveResult(resultCode, resultData);
        }
    }

}



Now we implements Receiver interface [defined in MyResultReceiver] in our Activity. Lets say this LoginActivity :

package sohail.aziz.view;
import sohail.aziz.service.MyResultReceiver;
import sohail.aziz.service.MyIntentService;
import sohail.aziz.service.MyResultReceiver.Receiver;


public class LoginActivity extends Activity implements OnClickListener,Receiver {
        Button btLogin;   
        Public MyResultReceiver mReceiver;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        // TODO Auto-generated method stub
        super.onCreate(savedInstanceState);
        setContentView(R.layout.login);

        btLogin = (Button) findViewById(R.id.btLogin);
        mReceiver = new MyResultReceiver(new Handler());

        mReceiver.setReceiver(this);
        btLogin.setOnClickListener(this);
        
    }

    @Override
    public void onClick(View arg0) {
        // TODO Auto-generated method stub
                 
             if(arg0.getId()==R.id.btLogin){
                  Intent i = new Intent(this, MyIntentService.class);
                  i.putExtra("nameTag","sohail" );
                  i.putExtra("receiverTag", mReceiver);
                  startService(i);
               
              }


    }
    
    @Override
    public void onReceiveResult(int resultCode, Bundle resultData) {
        // TODO Auto-generated method stub
        
                 Log.d("sohail","received result from Service="+resultData.getString("ServiceTag"));

    }
}




And here is the MyService class :

import android.app.IntentService;
import android.content.Intent;
import android.os.Bundle;
import android.os.ResultReceiver;
import android.util.Log;

public class MyIntentService extends IntentService {

    
    public MyIntentService() {
        super("MyIntentService");
    }

    @Override
    protected void onHandleIntent(Intent intent) {
        // TODO Auto-generated method stub

        
        ResultReceiver rec = intent.getParcelableExtra("receiverTag");
                String recName= intent.getString("nameTag");
                Log.d("sohail","received name="+recName);

        Log.d("sohail","sending data back to activity");

                Bundle b= new Bundle();
                b.putString("ServiceTag","aziz");
        rec.send(0, b);
    }

}



Whenever we call startService , intentService is started if its not been running, and if its already running it put our (new)request in a queue and execute it when it finishes running request. When we call rec.send() , onReceiveResult is called and the value we passed in bundle is received in the activity.


Is it helpful for you?

Wednesday, 18 April 2012

Custom adapter for ListView #android beginners

PRE:You must be familiar with simple list view/spinner and simpleAdapter.
 
By default listView only accepts a simple adapter with array of strings. However listView control be customized as you wish. Take a look of various listView use cases The world of listView Google I/O.

We can add custom controls like TextViews, buttons, images etc and make them clickable individually or as a whole. The use case can be a custom class fields you want to display in single row.



To make a listView OUR listView, We need to:
  1.  Create a main xml layout file with a ListView control placed in.
  2.  Create an xml layout which will be used to display one row of the list.
  3.  Create a custom adapter class extended from baseAdapter, and overrid its getView method

So lets define our main layout main.xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >

    <ListView 
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:id="@+id/contactsListViewMain"
      />
        
 </LinearLayout>

 and another layout which will be used to display one row of listView, say rowitem.xml:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical">
    <TextView
        android:id="@+id/contactname"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" 
        android:background="@color/FloralWhite"        
        android:textColor="@color/Black"
        />
    <TextView
        android:id="@+id/contactnum"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:background="@color/LightYellow"
        android:textColor="@color/Gray"
        />
</LinearLayout>


Lets say we want to display Contact Name and Number as one record in listView. A simple Contact class can be:

public class Contact {
         private String contactName;
        private String contactNum;

        Contact(String name,String num){
            this.contactName=name;
            this.contactNum=num;
        }
        public String getContactName() {
            return contactName;
        }
        public void setContactName(String contactName) {
            this.contactName = contactName;
        }

        public String getContactNum() {
            return contactNum;
        }
        public void setContactNum(String contactNum) {
            this.contactNum = contactName;
        }

}

Now the interesting part here we will bind the contact class fields with the rowitem.xml controls. Lets make OUR adapter

public class ContactAdapter extends BaseAdapter{

    Context mycontext;
    ArrayList<Contact> contactsList;
    LayoutInflater mInflater;
    
     public ContactAdapter(Context context, ArrayList<Contact> list) {
          
         this.mycontext=context;
         contactsList = list;
         mInflater = LayoutInflater.from(context);
        
     }
    
    
    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        // TODO Auto-generated method stub

        ContactViewHolder viewHolder;
        
        if(convertView==null){
        
            convertView= mInflater.inflate(R.layout.rowitem, parent,false);
            
            viewHolder= new ContactViewHolder();
            viewHolder.name= (TextView) convertView.findViewById(R.id.contactname);
            viewHolder.number=(TextView)convertView.findViewById(R.id.contactnum);
            convertView.setTag(viewHolder);
        }
        else
        {
            viewHolder=(ContactViewHolder) convertView.getTag();
        }
        
        Contact cont=(Contact) contactsList.get(position);
        
        viewHolder.name.setText(cont.getContactName());
        viewHolder.number.setText(cont.getContactNum());
        
        return convertView; 
        
    }

    
static class ContactViewHolder{
    
    TextView name;
    TextView number;
}


@Override
public int getCount() {
    // TODO Auto-generated method stub
    //return 0;
    
    return contactsList.size();
}


@Override
public Object getItem(int position) {
    // TODO Auto-generated method stub
    //return null;
    return contactsList.get(position);
}


@Override
public long getItemId(int position) {
    // TODO Auto-generated method stub
    return position;
}
    
    
}

Note: Note that rowitem.xml is inflated in getView and these controls are populated with the contact object's fields. We can place as many controls in rowitem.xml and in any order/layout we want and bind them with our custom object's fields.


Next we just need to create a list of custom objects [Contact] and create our adapter and set this adapter to listView. Lets say we want to display list on our starting Activity's onCreate method:

 setContentView(R.layout.main);

///creating a sample list of contacts with name and number
 ArrayList<Contact> list = new ArrayList<Contact>();
  list.add(new Contact("sohail", "11111"));
  list.add(new Contact("aziz", "122222"));
  list.add(new Contact("hassan", "33333333"));

//listView control
ListView mylistview= (ListView)findViewById(R.id.contactsListViewMain);

//here we are creating our custom adapter defined above
ContactAdapter contadapter= new ContactAdapter(this, list);

//setting listView adapter
mylistview.setAdapter(contadapter);


Thats it! One row of listView will show two items , name and number. You can change their font, color, style, alignment etc.


Download complete source contactEmail.


 Is it helpful ? Your feedback is welcomed.

Friday, 13 April 2012

Intent filters for #android beginners

Much have been written and discussed about Intent filters and their types (explicit and implicit). I am just going to discuss their usage in basic/simple android applications.
 
You don't need to define any intent-filter (other that the launcher activity) if your application doesn't call external intents e.g reading contacts, and you are not intended to receive any broadcast from other applications e.g receiving incoming call notification.

You should call your all activities and services with explicit intents i.e calling them with their names. For example if you have two activites and a service named:

1-FirstActiviy.java [launcher activity]
2-SecondActivity.java
3-MyService.java

your AndroidManifest.xml should look like this:

?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="sohail.aziz"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk android:minSdkVersion="9" />


    <application
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name" >

        <activity
            android:name=".FirstActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <activity
            android:name=".SecondActivity"
            android:label="@string/app_name" >
        </activity>
        <service android:name=".MyService" >
        </service>
</application>
</manifest>

To start service/activity you should use explicit intent like this

Intent i=new Intent(this,SecondActivity.class)
startActivity(i);

Intent ii=new Intent(this,Myservice.class);
startService(ii);

Do you have anything to tell? tell me.

Thursday, 12 April 2012

Passing custom objects between android activities

Passing primitive datatypes between activities is straight froward, you can use intent.putExtra() and put anything like boolean,strings and integers etc. However you can’t pass custom objects  between activities in this way.
To pass custom objects between activities/services, we  must implement  parcelable or serializable interface to custom class. However parcelable is specifically designed for android and is advised for best performance.
Lets start with simple class:
public class User {
String UserName;
String  Password;
int Action;

public User(String name,String pass,int ac){
UserName=name;
Password=pass;
Action=ac;
}

}
above is a simple User class with three private fields and getters and setters.
We can't pass objects of this class between activities/services. To do this we need to make this class parcelable. Lets see:
public class User implements Parcelable{

String UserName;
String  Password;
int Action;


public User(String name,String pass,int ac){
UserName=name;
Password=pass;
Action=ac;
}


//parcel part
public User(Parcel in){
String[] data= new String[3];

in.readStringArray(data);
this.UserName= data[0];
this.Password= data[1];
this.Action= Integer.parseInt(data[2]);
}
@Override
public int describeContents() {
// TODO Auto-generated method stub
return 0;
}

@Override
public void writeToParcel(Parcel dest, int flags) {
// TODO Auto-generated method stub

dest.writeStringArray(new String[]{this.UserName,this.Password,String.valueOf(this.Action)});
}

public static final Parcelable.Creator<User> CREATOR= new Parcelable.Creator<User>() {

@Override
public User createFromParcel(Parcel source) {
// TODO Auto-generated method stub
return new User(source);  //using parcelable constructor
}

@Override
public User[] newArray(int size) {
// TODO Auto-generated method stub
return new User[size];
}
};

}
Note that order of variable writing and reading is important, you should read and write variable in same order. One thing more pay attention to CREATOR its capital( It wasted my entire day :( ).
Now you can send and receive User objects by putting as parcelableExtra. For example in sender activity
User obj= new User("sohail","1234",1);

Intent i=new Intent(this,receiverActivity.class);

i.putExtra("userTag",obj);

startActivity(i);

and on receiverActivity, probably in onCreate receive object by getparcelableExtra.

User uobj= getIntent().getParcelableExtra("userTag"); 

Browse and download source parcelableIntentServiceExample.