Wednesday, 27 May 2015

Designing Layouts for Wearables Android


So while designing layouts for wearable we need to keep both above types in mind so that our layout design looks perfectly fine on both round and square screens.

Android wearable fall's into two categories :

1. Round Shape
2. Square Shape

Now, question is how should we achieve this.Well i encountered some issues on round screen.My screen layout included text and image.So whenever text was large it was cutting in round edges from left side.

So after sometime,i camed to know about BoxInsetLayout which comes under android.support.wearable.view.BoxInsetLayout included in Wearable UI Library .
This helps us define a single layout that works both in round and square screens for wearbles.

Round Shape View


 Square Shape View


Now how to Make use of this lets have a look :




<?xml version="1.0" encoding="utf-8"?>
<android.support.wearable.view.BoxInsetLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#ffffff"
    android:padding="20dp">

    <android.support.v4.view.ViewPager
        android:id="@+id/myviewpager"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
</android.support.wearable.view.BoxInsetLayout>


1. android:padding="20dp" : Now this gives the padding to the BoxInsetLayout from all directions which creates a kind of rectangle for us and we've to work inside it.And this paddingapplies only to square screen of wearable as window insets on round devices are larger than 15 dp.

Note :BoxInsetLayout act as a parent and we have to create our layout inside this parent(like we do inside linear layout etc).

 2. android:padding="5dp" for our child view in this case view pager is our child : This padding applies on both round and square screens.
 
    For Square screen : this makes 20+5 = 25 dp padding
    For Round  screen :this makes 5    = 5 dp padding
 
 3. app:layout_box="all" :This line ensures that the ViewPager element and its children are boxed inside the area defined by the window insets on round screens. This line has no effect on square screens.



References : https://developer.android.com/training/wearables/ui/layouts.html#add-library


happy coding!!
Cheers !!

Monday, 25 May 2015

Android Wear Host Disconnected even after running connecting commands

A issue normally that we faced when we try to connect android wear(smartwatch) via android wear companion app

Host   : Disconnected.
Target : Connected.

This normally happens if you've connected with an emulator previously, Then it will cause an issue with the connection.

To solve this just follow below steps :

1. open android wear companion app
2. Go to settings
3. click on Emulator.
4. click on FORGET WATCH

That did the trick for me :-)

Posting by keeping in mind that you guys already know how to connect any wearable by running commands :-)

Cheers!!

Thursday, 14 May 2015

Duplicate ID binary XML error in fragments

When dealing Google V2 maps in android tabs and Fragments which generally come across with a issue i.e Duplicate ID binary XML error.

To be more specific Error faced is below :
android.view.InflateException: Binary XML file line #7: Error inflating class fragment

Now why this happens :

Because you already have the fragment added in the FragmentManager, you can't add the same fragment twice which will cause duplication of ID i.e two fragments with same ID.

Now this generally happens when we are adding a fragment that contains a fragment in its layout as well, mostly in case of map fragments.

Our tendency is to add Mapfragment in XML layout like this :

<?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" >

    <fragment

        android:id="@+id/map"

        android:layout_width="match_parent"

        android:layout_height="match_parent"

        class="com.google.android.gms.maps.SupportMapFragment" />



</LinearLayout>


And our Fragment inflate this layout like this :

public class LocationFragment extends Fragment {



View mView;

private static GoogleMap map;

@Override

public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {

mView = inflater.inflate(R.layout.locationfragment, container, false);

return mView;

}

}


Now if we see closely what happening here. We will add this fragment in a tab, which contains a fragment in its layout as well.This is the reason of problem here.

Note: You cannot inflate a layout into a fragment when that layout includes a <fragment>.Nested fragments are only supported when added to a fragment dynamically.

As per Andorid Documentation this approach is not recommended.We need to add map fragments Dynamically in order to accomplish nested fragments as per android guidelines.Check Nested fragments from below link :

http://developer.android.com/about/versions/android-4.2.html#NestedFragments

So Android-supported way is to add a fragment to another fragment is via a transaction from the child fragment manager as shown below :

XML Layout :

<?xml version="1.0" encoding="utf-8"?>

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"

xmlns:map="http://schemas.android.com/apk/res-auto"

   android:layout_width="match_parent"

   android:layout_height="match_parent" >

<!-- Lots of fancy layout -->  
<RelativeLayout
        android:id="@+id/map"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">
    </RelativeLayout>
</RelativeLayout>


Java Code Snippet :

public class MyFragment extends Fragment {

private SupportMapFragment fragment;
private GoogleMap map;

@Override

public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    return inflater.inflate(R.layout.layout_with_map, container, false);
}

@Override
public void onActivityCreated(Bundle savedInstanceState) {
    super.onActivityCreated(savedInstanceState);
    FragmentManager fm = getChildFragmentManager();
    fragment = (SupportMapFragment) fm.findFragmentById(R.id.map);
    if (fragment == null) {
        fragment = SupportMapFragment.newInstance();
       fm.beginTransaction().replace(R.id.map, fragment).commit();
    }
}



@Override
public void onResume() {
    super.onResume();
    if (map == null) {
        map = fragment.getMap();
        map.addMarker(new MarkerOptions().position(new LatLng(0, 0)));
    }
}
}

There are other ways to resolve the errors as well if you are willing to you map fragment inside a XML layout.Below are the ways to solve the error :

1. Remove fragment on onDestroyView() :

@Override
public void onDestroyView() {
    super.onDestroyView();
    MapFragment f = (MapFragment) getFragmentManager()
                                         .findFragmentById(R.id.map);

    if (f != null)
        getFragmentManager().beginTransaction().remove(f).commit();
}



2. Remove the parent view if it exists in onCreateView() :

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    if (view != null) {
        ViewGroup parent = (ViewGroup) view.getParent();
        if (parent != null)
            parent.removeView(view);
    }
    try {
        view = inflater.inflate(R.layout.map, container, false);
    } catch (InflateException e) {
    }
    return view;
}
The above two methods will resolve our issue of duplicate ID in map fragment when dealing with fragments and tabs, but its kind of "Jugaad"(tricky way) as we say in HINDI.So this might be working now but might not working in upcoming versions of android.So better way to go is as Android Recommends.


References : http://developer.android.com/about/versions/android-4.2.html#NestedFragments , www.stackoverflow.com.

Happy Coding!!
Cheers.

Wednesday, 13 May 2015

Demo for Android v2 Maps Allowing Free hand drawing for user

First create a project on google apis web console. And get the API KEY for v2 maps. 

Include google-play-services_lib in your project.

 1.MainActivity.java

public class MainActivity extends FragmentActivity implements OnMapLongClickListener,OnMapClickListener,OnMarkerDragListener {

 private static GoogleMap map;
 ArrayList points;
 LatLng mLatlng;
 int i=0;
 float distance;
 @Override
 protected void onCreate(Bundle saveInstance) {
  super.onCreate(saveInstance);

  requestWindowFeature(Window.FEATURE_NO_TITLE);
  setContentView(R.layout.activity_main);
  points = new ArrayList();
  map = ((SupportMapFragment)getSupportFragmentManager().findFragmentById(R.id.map)).getMap();
  map.setOnMarkerDragListener(this);
  map.setOnMapLongClickListener(this);
  map.setOnMapClickListener(this);
  mLatlng=new LatLng(30.7500, 76.7800 );
  CameraPosition INIT =
    new CameraPosition.Builder()
  .target(new LatLng(30.7500, 76.7800))
  .zoom(17.5F)
  .bearing(300F) // orientation
  .tilt( 50F) // viewing angle
  .build();
  // use map to move camera into position
  map.moveCamera( CameraUpdateFactory.newCameraPosition(INIT) );
  points.add(new LatLng(30.7500, 76.7800));
  //create initial marker
  map.addMarker( new MarkerOptions()
  .position( new LatLng(30.7500, 76.7800) )
  .title("Location").draggable(true)
  .snippet("First Marker")).showInfoWindow();
 }

 @Override
 public void onMarkerDrag(Marker arg0) {
  LatLng dragPosition = arg0.getPosition();
  double dragLat = dragPosition.latitude;
  double dragLong = dragPosition.longitude;
  Log.i("info", "on drag end :" + dragLat + " dragLong :" + dragLong);
  PolylineOptions polylineOptions = new PolylineOptions();
  // Setting the color of the polyline
  polylineOptions.color(Color.RED);
  // Setting the width of the polyline
  polylineOptions.width(3);
  // Adding the taped point to the ArrayList 
  points.add(dragPosition);
  // Setting points of polyline
  polylineOptions.addAll(points);
  // Adding the polyline to the map
  map.addPolyline(polylineOptions);
  Location locationA = new Location("point A");     
  locationA.setLatitude(mLatlng.latitude); 
  locationA.setLongitude(mLatlng.longitude);
  Location locationB = new Location("point B");
  locationB.setLatitude(dragLat); 
  locationB.setLongitude(dragLong);
  distance = locationA.distanceTo(locationB) ;
  mLatlng=new LatLng(dragLat, dragLong);
 }

 @Override
 public void onMarkerDragEnd(Marker arg0) {
  LatLng dragPosition = arg0.getPosition();
  double dragLat = dragPosition.latitude;
  double dragLong = dragPosition.longitude;
  Log.i("info", "on drag end :" + dragLat + " dragLong :" + dragLong);
  PolylineOptions polylineOptions = new PolylineOptions();
  // Setting the color of the polyline
  polylineOptions.color(Color.RED);
  // Setting the width of the polyline
  polylineOptions.width(3);
  // Adding the taped point to the ArrayList 
  points.add(dragPosition); 
  // Setting points of polyline
  polylineOptions.addAll(points);
  // Adding the polyline to the map
  map.addPolyline(polylineOptions);
  Toast.makeText(getApplicationContext(), "Distance ="+distance, Toast.LENGTH_LONG).show();
 }

 @Override
 public void onMarkerDragStart(Marker arg0) {

 }

 @Override
 public void onMapClick(LatLng arg0) {
  map.animateCamera(CameraUpdateFactory.newLatLng(arg0));
 }


 @Override
 public void onMapLongClick(LatLng arg0) {
 }   
}
XML layouts :

1. activity_main.xml

<RelativeLayout 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"
    tools:context=".MainActivity" >

    <fragment
        android:id="@+id/map"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        class="com.google.android.gms.maps.SupportMapFragment" />

</RelativeLayout>

2. AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>

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

    <uses-sdk
        android:minSdkVersion="8"
        android:targetSdkVersion="21" />

    <permission
        android:name="com.kamal.permission.MAPS_RECEIVE"
        android:protectionLevel="signature" />
    <uses-permission android:name="com.kamal.permission.MAPS_RECEIVE" />
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="com.google.android.providers.gsf.permission.READ_GSERVICES" />
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-feature
        android:glEsVersion="0x00020000"
        android:required="true" />

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name="com.kamal.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>

        <meta-data
            android:name="com.google.android.maps.v2.API_KEY"
            android:value="AIzaSyAchnHfCbb35xPnFfd-dbQ72kQ7glqvVzg" />
        <meta-data
            android:name="com.google.android.gms.version"
            android:value="@integer/google_play_services_version" />
    </application>

</manifest>


OutPut :













Monday, 11 May 2015

Converting an Image to Base64 / Decoding Base64 back to bitmap In Android

Find the following methods which will do :

1. Convert the Image to base64 .

2. Convert Base64 string to Image (Bitmap).


1. Method to Decode base64 to bitmap

 private Bitmap decodeFromBase64ToBitmap(String encodedImage)

{

    byte[] decodedString = Base64.decode(encodedImage, Base64.DEFAULT);

    Bitmap decodedByte = BitmapFactory.decodeByteArray(decodedString, 0, decodedString.length);

    return decodedByte;

    }

   

   

2. Method to Convert image to Base64 String.


    private String convertToBase64(String imagePath)

{

    Bitmap bm = BitmapFactory.decodeFile(imagePath);

    ByteArrayOutputStream baos = new ByteArrayOutputStream(); 

   bm.compress(Bitmap.CompressFormat.JPEG, 100, baos); 

    byte[] byteArrayImage = baos.toByteArray();

    String encodedImage = Base64.encodeToString(byteArrayImage, Base64.DEFAULT);

    return encodedImage;

    }

Posting Data on server Using Volley Android

This Tutorial let us know how to post data using volley. Here i will be calling a POST service which will accept parameters and returns a json result .

This is method we will be using to add parameters which we want to send to server.

 
@Override
protected Map getParams() throws AuthFailureError 
{
 // TODO Auto-generated method stub 
return super.getParams(); 



Include Volley library in libs folder of your project,you can download the volley library online.


Project Structure goes like this






1. MainActivity.java

public class MainActivity extends Activity implements OnClickListener
{
private String url = "Your URL";

 private Button hitService;

private ProgressDialog mDialog;

 private TextView mName,mEmail;

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

private void intiViews()
{
hitService=(Button)findViewById(R.id.hitservice);
 hitService.setOnClickListener(this);
 mName=(TextView)findViewById(R.id.name);
 mEmail=(TextView)findViewById(R.id.email);
}
 @Override public void onClick(View v)
{
switch (v.getId())
{
 case R.id.hitservice:
 mDialog=new ProgressDialog(this);
 mDialog.setMessage("Loading");
mDialog.show();
 RequestQueue queue = Volley.newRequestQueue(this);
JsonObjectRequest jsonObjReq = new JsonObjectRequest(Method.POST, url, null,  new Response.Listener<JSONObject>()
{                  
@Override                  
public void onResponse(JSONObject response)
{                
  Log.e("Response => ",response.toString());
 }              
}, new Response.ErrorListener()
{                  
@Override                  
public void onErrorResponse(VolleyError error)
{
                  
}              
})
  { //Code to send parameters to server
 @Override
 protected Map getParams() throws AuthFailureError 

  Map<String,String> params = new HashMap<String, String>();
 params.put("name","YOUR NAME VALUE"); 
 params.put("description", "YOUR description");
 params.put("price", "YOUR price"); 
 return params;
 } 
};        
queue.add(jsonObjReq);
 break; 
default: break; 
}
}



Define Internet Permission in manifest file

<uses-permission android:name="android.permission.INTERNET" />
XML Layouts :

1. activity_main.xml

<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:orientation="vertical"
    tools:context=".MainActivity" >

    <Button
        android:id="@+id/hitservice"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Hit Web Service" />

    <TextView
        android:id="@+id/name"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content" />
    <TextView
        android:id="@+id/email"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content" />

</LinearLayout>

Saturday, 9 May 2015

Using Volley to make web/Network Calls in Android

This Tutorial let us know how to use volley. Here i will be calling a Get service which will accept no parameters and returns a json result that includes student info like name,email etc.

I will be using a model to store student data which is fetched from server.

Include Volley library in libs folder of your project,you can download the volley library online.


Project Structure goes like this






1. MainActivity.java

public class MainActivity extends Activity implements OnClickListener{
  private String url = "Your URL";
  private Button hitService;
  private ProgressDialog mDialog;
  private TextView mName,mEmail;


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


  private void intiViews() {
  hitService=(Button)findViewById(R.id.hitservice);
  hitService.setOnClickListener(this);
  mName=(TextView)findViewById(R.id.name);
  mEmail=(TextView)findViewById(R.id.email);
  }



@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.hitservice:
mDialog=new ProgressDialog(this);
mDialog.setMessage("Loading");
mDialog.show();

RequestQueue queue = Volley.newRequestQueue(this);
JsonObjectRequest jsonObjReq = new JsonObjectRequest(Method.GET,
                url, null,
                new Response.Listener<JSONObject>() {
                    @Override
                    public void onResponse(JSONObject response) {
                    Log.e("Response => ",response.toString());
                    parseData(response);
                    }
                }, new Response.ErrorListener() {
                    @Override
                    public void onErrorResponse(VolleyError error) {
                    }
                });
        queue.add(jsonObjReq);
break;
default:
break;
}
}


private void parseData(JSONObject mResponse){
UserInfo mUserModel=new UserInfo();
try {
mUserModel.setName(mResponse.getString("name"));
mUserModel.setEmail(mResponse.getString("email"));
setViewvalues(mUserModel);
} catch (Exception e) {
}finally{
mDialog.dismiss();
}
}



private void setViewvalues(UserInfo mUserModel) {
mName.setText(mUserModel.getName());
mEmail.setText(mUserModel.getEmail());
}
}


2. UserInfo.java


public class UserInfo {
String name="",email="",phone="",home="",mobile="";

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public String getEmail() {
return email;
}


public void setEmail(String email) {
this.email = email;
}

public String getPhone() {
return phone;
}

public void setPhone(String phone) {
this.phone = phone;
}

public String getHome() {
return home;
}

public void setHome(String home) {
this.home = home;
}

public String getMobile() {
return mobile;
}

public void setMobile(String mobile) {
this.mobile = mobile;
}

}
Define Internet Permission in manifest file
<uses-permission android:name="android.permission.INTERNET" />
XML Layouts :

1. activity_main.xml

<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:orientation="vertical"
    tools:context=".MainActivity" >

    <Button
        android:id="@+id/hitservice"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Hit Web Service" />

    <TextView
        android:id="@+id/name"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content" />
    <TextView
        android:id="@+id/email"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content" />

</LinearLayout>

Output:

What is Volley In Android ?

What is Volley ?

Volley is a library that help us making network calls in a easier and faster way in android.

Processing and Caching of network requests is managed by volley in a systematic way.

Volley Library network calls works asynchronously means no need to write Async Task.

Using Volley we can :

1. Request network calls.Response will be fetched by volley from web.

2. It provides memory caching.

3. Cancel Network request as well.

4. It provides Debugging tools as well.

5. Add Request to queue and prioritize.

6. Volley provides Memory Management as well.


So Volley is a networking library to make networking calls much easier, faster by adding requests.


We use Two classes of Volley i.e

1. Request Queue

2. Request


You can find how to use volley to make network calls in my next tutorial.

Cheers!!!!

Thursday, 7 May 2015

Showing Action Bar menu at Top which contains hardware button

Sometime option menu icon in Actionbar is not displayed because the devices has hardware button for option menu.
The below code will help you to show option menu in such devices like Samsung S4.

write code in Application's OnCreate()


......................


 /*
   * This block is used to show Action bar menu icon at Top Right of The Action bar. because some Device has there    * hardware button for menu and in that Devices menu button on ActionBar Hide Automatically. like Samsung S4    */   try {    ViewConfiguration config = ViewConfiguration.get(this);    Field menuKeyField = ViewConfiguration.class.getDeclaredField("sHasPermanentMenuKey");    if (menuKeyField != null) {     menuKeyField.setAccessible(true);     menuKeyField.setBoolean(config, false);    }   } catch (Exception ex) {    // Ignore   }

Applying Filters in Listview using Custom Model with BaseAdapter

This Demo provides a filterable list which is been filter according to the custom model. here we are using a Student model which can be replace as per need .

1. MainActivity.java


public class MainActivity extends ActionBarActivity {



    EditText mEditText;

    ListAdapter mAdapter;

    private ListView mListView;

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

        setContentView(R.layout.activity_main);
        showAlertDialog();
        mListView = (ListView) findViewById(R.id.listview);
        mEditText = (EditText) findViewById(R.id.editText);
        int student_name = 0;
        String[] names = {"Nishant", "Umang", "Vikrant", "Danish", "Sunil", "Kamal", "Nitesh", "Amit", "Sarthak", "Aman", "Naresh", "Yoginder"};
        //arrayList of Students      

      ArrayList<Student> array_list = new ArrayList<Student>();

        for (int x = 1; x <= 5000; x++) {

            if (student_name > 11) {
                student_name = 0;
            }

            Student student = new Student(x, names[student_name]);
            array_list.add(student);
            student_name++;
        }

        mAdapter = new ListAdapter(this, array_list);

        mListView.setAdapter(mAdapter);

        //on Text change in Search EditText.       

       mEditText.addTextChangedListener(new TextWatcher() {

            @Override           
            public void beforeTextChanged(CharSequence s, int start, int count, int after)                {

            }

            @Override            
          public void onTextChanged(CharSequence s, int start, int before, int count) {

                // Filter arrayList on TextChanged in EditText                
            MainActivity.this.mAdapter.getFilter().filter(s);
            }

            @Override            
          public void afterTextChanged(Editable s) {

            }

        });


        mListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {

            @Override           
       public void onItemClick(AdapterView<?> parent, View view, int position, long id) {

                // get current clicked Item data.                Student student = (Student) parent.getItemAtPosition(position);

                Toast.makeText(getApplicationContext(), student.getName() + " " + student.getStudentId(), Toast.LENGTH_SHORT).show();

            }

        });

    }


    @Override    
public boolean onCreateOptionsMenu(Menu menu) {

        // Inflate the menu; this adds items to the action bar if it is present.        getMenuInflater().inflate(R.menu.menu_main, menu);

        return true;

    }


    @Override    
public boolean onOptionsItemSelected(MenuItem item) {

        // Handle action bar item clicks here. The action bar will        // automatically handle clicks on the Home/Up button, so long        // as you specify a parent activity in AndroidManifest.xml.        int id = item.getItemId();

        //noinspection SimplifiableIfStatement        if (id == R.id.action_info) {


            showAlertDialog();

            return true;

        }


        return true;

    }

    void showAlertDialog() {
        AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(this);
        // set title     
 alertDialogBuilder.setTitle(getResources().getString(R.string.alert_dialog_title));
        // set dialog message     
alertDialogBuilder.setMessage(getResources().getString(R.string.alert_dialog_desc))
                .setCancelable(true)
                .setPositiveButton(getResources().getString(R.string.alert_dialog_button_text), new DialogInterface.OnClickListener() {

                  

public void onClick(DialogInterface dialog, int id) {

                        // if this button is clicked, close dialog                                        dialog.cancel();
                    }
                });
        // create alert dialog        AlertDialog alertDialog = alertDialogBuilder.create();
        // show the alert dialog        alertDialog.show();
    }
}
2. Student.java

public class Student {

    private int studentId;

    private String name;

    /*

    * constructor of the Student class which accepting two parameters.

    * @parameters id : Student Id.

    * @parameters name : Name of the Student

    */

    public Student(int id, String name) {

        this.studentId = id;

        this.name = name;

    }

    public String getName() {

        return name;

    }

    public int getStudentId() {

        return studentId;

    }


}


3. ListAdapter.java

public class ListAdapter extends BaseAdapter implements Filterable {



    private final Object mLock = new Object();

    private List<Student> mArrayList;

    private Context mContext;

    // A copy of the original mObjects array, initialized from and then used instead as soon as

    // the mFilter ArrayFilter is used. mObjects will then only contain the filtered values.

    private ArrayList<Student> mOriginalValues;

    private ArrayFilter mFilter;


    public ListAdapter(Context context, ArrayList<Student> arrayList) {

        mContext = context;

        mArrayList = arrayList;

    }

    @Override

    public int getCount() {

        return mArrayList.size();

    }

    @Override

    public Object getItem(int position) {

        return mArrayList.get(position);

    }

    @Override

    public long getItemId(int position) {

        return 0;

    }

    @Override

    public View getView(int position, View convertView, ViewGroup parent) {

        ViewHolder viewHolder;

        if (convertView == null) {

            LayoutInflater inflater = ((Activity) mContext).getLayoutInflater();

            convertView = inflater.inflate(R.layout.list_item, parent, false);

            viewHolder = new ViewHolder();

            viewHolder.tvStudentName = (TextView) convertView.findViewById(R.id.tv_listitem);

            viewHolder.tvStudentId=(TextView)convertView.findViewById(R.id.tv_student_id);

            convertView.setTag(viewHolder);

        } else {

            viewHolder = (ViewHolder) convertView.getTag();

        }

        if (mArrayList.get(position) != null) {

            viewHolder.tvStudentName.setText(mArrayList.get(position).getName());

            viewHolder.tvStudentId.setText(""+mArrayList.get(position).getStudentId());

            viewHolder.tvStudentName.setTag(mArrayList.get(position));

        }

        return convertView;

    }

    /**

     * <p>Returns a filter that can be used to constrain data with a filtering

     * pattern.</p>

     * <p/>

     * <p>This method is usually implemented by {@link android.widget.Adapter}

     * classes.</p>

     *

     * @return a filter used to constrain data

     */
    @Override
    public Filter getFilter() {
        if (mFilter == null) {

            mFilter = new ArrayFilter();

        }

        return mFilter;

    }
    private class ViewHolder {

        TextView tvStudentName,tvStudentId;

    }

    private class ArrayFilter extends Filter {

        @Override

        protected FilterResults performFiltering(CharSequence prefix) {

            FilterResults results = new FilterResults();

            if (mOriginalValues == null) {

                synchronized (mLock) {

                    mOriginalValues = new ArrayList<Student>(mArrayList);

                }

            }

            if (prefix == null || prefix.length() == 0) {

                ArrayList<Student> list;

                synchronized (mLock) {

                    list = new ArrayList<Student>(mOriginalValues);

                }

                results.values = list;

                results.count = list.size();

            } else {

                String prefixString = prefix.toString().toLowerCase();

                ArrayList<Student> values;

                synchronized (mLock) {

                    values = new ArrayList<Student>(mOriginalValues);

                }

                final int count = values.size();

                final ArrayList<Student> newValues = new ArrayList<Student>();

                for (int i = 0; i < count; i++) {

                    final Student value = values.get(i);

                    final String valueText = value.getName().toLowerCase();

                    final String valueTextId = String.valueOf(value.getStudentId()).toLowerCase();

                    // First match against the whole, non-splitted value

                       if (valueText.contains(prefixString) || valueTextId.contains(prefixString)) {

                        newValues.add(value);

                    } else {

                        final String[] words = valueText.split(" ");

                        final int wordCount = words.length;

                        // Start at index 0, in case valueText starts with space(s)

                        for (int k = 0; k < wordCount; k++) {

                            if (words[k].startsWith(prefixString)) {

                                newValues.add(value);

                                break;

                            }

                        }

                    }

                }

                results.values = newValues;

                results.count = newValues.size();

            }

            return results;

        }

        @Override

        protected void publishResults(CharSequence constraint, FilterResults results) {

            mArrayList = (List<Student>) results.values;

            if (results.count > 0) {

                notifyDataSetChanged();

            } else {

                notifyDataSetInvalidated();

            }

        }

    }

}
XML Layouts :

 1. activity_main.xml
<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:orientation="vertical" tools:context=".MainActivity">

    <EditText

        android:layout_width="fill_parent"

        android:layout_height="wrap_content"

        android:id="@+id/editText"

        android:hint="Enter Text"

        android:layout_above="@+id/listview"

        android:layout_centerHorizontal="true"

       />

    <ListView

        android:layout_width="wrap_content"

        android:layout_height="wrap_content"

        android:id="@+id/listview"

        android:choiceMode="singleChoice" />

</LinearLayout>


2. list_item.xml

<?xml version="1.0" encoding="utf-8"?>

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"

    android:layout_width="match_parent" android:layout_height="match_parent">

    <TextView

        android:layout_width="match_parent"

        android:layout_height="wrap_content"

        android:text="New Text"

        android:id="@+id/tv_listitem"

        android:layout_centerVertical="true"

        android:paddingBottom="10dp"

        android:paddingTop="10dp"

        android:layout_centerHorizontal="true" />



    <TextView

        android:layout_width="wrap_content"

        android:layout_height="wrap_content"

        android:text="New Text"

        android:id="@+id/tv_student_id"

        android:layout_centerInParent="true" />

</RelativeLayout>



3. menu_main.xml

<menu xmlns:android="http://schemas.android.com/apk/res/android"

    xmlns:app="http://schemas.android.com/apk/res-auto"

    xmlns:tools="http://schemas.android.com/tools" tools:context=".MainActivity">

    <item android:id="@+id/action_info" android:title="@string/action_info"

        android:orderInCategory="100" app:showAsAction="never" />

</menu>


4. strings.xml

<resources>

    <string name="app_name">Filterable List</string>
    <string name="action_info">Info</string>

    <string name="alert_dialog_desc">This is demo about Offline Filtering from ListView. You can filter with any parameters of list like (Student name or student Id).</string>

    <string name="alert_dialog_title">List with Filter Option</string>

    <string name="alert_dialog_button_text">OK</string>

</resources>

Output :





Tuesday, 5 May 2015

Android Studio Important Shortcut Keys

Alt+F7                : To find usage of a method or class in whole project
alt+ctrl+L           : Reformat code
shift+f6               : Renaming a variable
ctrl+Y                 : Delete a line
ctrl+D                 : Place cursor on a line and press ctrl+D to create a duplicate line
Ctrl+R             : To find and replace particular keywords or text in a class
Alt+Enter+Enter : To extract a string in a resource

Debugging in Android Studio 
F8 to move to next
F9 to move to next debugging point


Shift+f9       : To run app in debug mode
Shift+f10     : To run app
ctrl+9          : Build project

Monday, 4 May 2015

FragmentStatePagerAdapter vs FragmentPagerAdapter

FragmentStatePagerAdapter

1. FragmentStatePagerAdapter destroy the fragment which is no longer needed i.e which is not visible to user.Similar to a recylerview/Listview which recyles the view memory      when goes out of sight.
2. FragmentStatePagerAdapter Saves the Fragment bundle from the SaveInstance and re-stores the fragment when user comes back to the destroyed fragment.

FragmentPagerAdapter

1. In FragmentPagerAdapter fragment of each page which user visited is kept in memory.Which causes memory issues in case of heavy fragments.
2. FragmentPagerAdapter calls detach(Fragment) on the transaction instead of remove(Fragment).This only removes the fragment view but fragment Instance remains in memory.


So, When to use FragmentPagerAdapter And FragmentStatePagerAdapter?

When we know the amount of data to be display or content is static or another case can when we know devices we are targetting never gonna run out of memory, Because this causes alot of memory consumption as it loads fragment in memory once visited by user.

And In case when we do not know the size, then we prefer FragmentStatePagerAdapter.Because it allows us adding fragments without causing memory issues.As it destroy the fragment which is no longer visible kinds of recyling the memory from those memory.

Code Snipnet for FragmentStatePagerAdapter:

class MyAdapter extends FragmentStatePagerAdapter {

        public MyAdapter(FragmentManager fm) {

            super(fm);

        }

        @Override

        public int getCount() {

            return NUM_ITEMS;

        }

        @Override

        public Fragment getItem(int position) {

            return new Fragment(params if any);

        }

    }



Code Snipnet for FragmentPagerAdapter:

class MyAdapter extends FragmentPagerAdapter {

        public MyAdapter(FragmentManager fm) {

            super(fm);

        }

        @Override

        public int getCount() {

            return NUM_ITEMS;

        }

        @Override

        public Fragment getItem(int position) {

            return new Fragment(params if any);

        }

    }





References Stackoverflow,http://developer.android.com/