Friday 17 January 2014

Adapters In Android



Adapters in Android are a bridge between the Adapter View (e.g. ListView) and the underlying data for that view. Imagine what would have been the world without adapter !.

Without Adapters, to implement the ListView functionality, you will need to:


  • Create a TextView within a ScrollView group.
  • Then you will have to implement pagination concept for the contents of the TextView.
  • You will also have to write additional code to identify the click event on a particular row in theTextView.

You may be asking why we need Pagination?

Imagine that you are creating an application that needs to display all your emails and the user will be able to scroll through them. I get around 100 emails on a daily basis and even if we consider 10 emails per day, the email data is going to be extremely huge. If you do not implement pagination, you will have major performance issues in retrieving all that data and showing it on the mobile screen. Thank God, we have adapters in Android and adapter views!

Below is a conceptual diagram which shows the high level working of the Android Adapter:







Let us now understand the internal working of an Android Adapter and how it acts as a data pump to the adapter view.


Adapters call the getView() method which returns a view for each item within the adapter view. The layout format and the corresponding data for an item within the adapter view is set in the getView() method. Now, it will be a performance nightmare if getView()returns a new View every time it is called. Creating a new view is very expensive in Android as you will need to loop through the view hierarchy (using the find ViewbyID ()method) and then inflate the view to finally display it on the screen.It also puts a lot of pressure on the garbage collector. That is because when the user is scrolling through the list, if a new view is created; the old view (since it is not recycled) is not referenced and becomes a candidate to be picked up by the garbage collector. So what Android does is that it recycles the views and reuses the view that goes out of focus.

Below is a visual representation of this recycle process:





In the above figure, let us assume we are displaying the months in a year in a ListView. To begin with, the months January till May are shown in the screen. When you scroll the view, the month January goes out of the display area of the mobile screen. As soon as the January view goes out of the screen, the Adapter View (ListView in this case) sends the view to something called a recycler.So when you scroll up, the getView () method is called to get the next view (which is June). This method getView()has a parameter called convertview which points to the unused view in the recycler. Through the convertview, the Adapter tries to get hold of the unused view and reuse it to display the new view (which is June in this case).


Tuesday 3 December 2013

Warning: No DNS servers found in Android Eclipse

Mostly new android users face this problem when they install Android eclipse and run any created project than the below error comes on console of android eclipse and project does not run :

Warning: No DNS servers found

It does not mean that your application has any error. See the solution:

Go to -> Window -> Preferences


Android -> Launch -> Default Emulator Option ->
paste this:    -dns-server 8.8.8.8,8.8.4.4
than Apply -> OK




Now create any new application and run your project.
Share and help others. Thanks... :)

Thursday 5 September 2013

Print Receipt Using Bluetooth with Android Phone

Recently, I was asked to make a program for printing some data to a small or handheld Bluetooth printer device. This can be used for printing receipts, simple tickets, or customer notes. I like how it works because usually, we are getting our program output on a computer screen, but  this time we are getting our output on a tangible paper!

I tried everything for printing but my thermal printer was printing only blank paper. At the end I got the issue that is my printer paper is set from the wrong side. Yes that also may be one issue in your case because I went through it . so cheque your paper side if you are getting blank output page.

Now I am going to explain how I  connect to the Bluetooth printer, then make socket connection and then output the string that you put into the edittext.


MainActivity.java - contains button listeners and functions for bluetooth connection, sending data, etc.


 package mmsl.BluetoothFilePrinter;  
 import java.io.BufferedReader;  
 import java.io.FileNotFoundException;  
 import java.io.IOException;  
 import java.io.InputStream;  
 import java.io.InputStreamReader;  
 import java.io.OutputStream;  
 import mmsl.GetPrintableImage.GetPrintableImage;  
 import android.app.Activity;  
 import android.bluetooth.BluetoothSocket;  
 import android.content.ContentValues;  
 import android.content.Intent;  
 import android.graphics.Bitmap;  
 import android.graphics.BitmapFactory;  
 import android.net.Uri;  
 import android.os.Bundle;  
 import android.os.Environment;  
 import android.provider.MediaStore;  
 import android.view.View;  
 import android.view.View.OnClickListener;  
 import android.widget.Button;  
 import android.widget.CheckBox;  
 import android.widget.CompoundButton;  
 import android.widget.CompoundButton.OnCheckedChangeListener;  
 import android.widget.EditText;  
 import android.widget.RadioButton;  
 import android.widget.Toast;  
 public class MainActivity extends Activity {  
  /** Called when the activity is first created. */  
  EditText mNameEditText;  
  EditText mAmountEditText;  
  Button mPrintButton;  
  byte FontStyleVal;  
  private static BluetoothSocket mbtSocket;  
  private static OutputStream mbtOutputStream;  
  private boolean PrintImage = false;  
  int mPrintType = 0;  
  @Override  
  public void onCreate(Bundle savedInstanceState) {  
   super.onCreate(savedInstanceState);  
   setContentView(R.layout.main);  
   mNameEditText = (EditText) findViewById(R.id.nameEditText);  
   mAmountEditText = (EditText) findViewById(R.id.amountEditText);  
   mPrintButton = (Button) findViewById(R.id.printButton);  
   mPrintButton.setOnClickListener(new OnClickListener() {  
    @Override  
    public void onClick(View v) {  
     mPrintType = 0;  
     StartBluetoothConnection();  
    }  
   });  
  }  
  private int[] Readcsv() {  
   try {  
    InputStream in = getAssets().open("logo.txt");// openFileInput();  
    BufferedReader reader = new BufferedReader(  
      new InputStreamReader(in));  
    int[] mona = new int[14926];  
    int cnt = 0;  
    try {  
     String line;  
     while ((line = reader.readLine()) != null) {  
      String[] RowData = line.split(",");  
      for (int i = 0; i < RowData.length; i++) {  
       mona[cnt] = Integer.parseInt(  
         RowData[i].replace("0x", "").replace(" ", ""),  
         16);  
       cnt++;  
      }  
      // do something with "data" and "value"  
     }  
    } catch (Exception ex) {  
     ex.printStackTrace();  
     // handle exception  
    } finally {  
     try {  
      in.close();  
     } catch (IOException e) {  
      // handle exception  
     }  
    }  
    return mona;  
   } catch (Exception e) {  
    return null;  
   }  
  }  
  protected void StartBluetoothConnection() {  
   if (mbtSocket == null) {  
    Intent BTIntent = new Intent(getApplicationContext(),  
      BTWrapperActivity.class);  
    this.startActivityForResult(BTIntent,  
      BTWrapperActivity.REQUEST_CONNECT_BT);  
   } else {  
    // mbtSocket.connect();  
    OutputStream tmpOut = null;  
    try {  
     tmpOut = mbtSocket.getOutputStream();  
    } catch (IOException e) {  
     e.printStackTrace();  
    }  
    mbtOutputStream = tmpOut;  
    senddatatodevice();  
   }  
  }  
  private void senddatatodevice() {  
   try {  
    mbtOutputStream = mbtSocket.getOutputStream();  
    switch (mPrintType) {  
    case 0:  
     byte[] Command = { 0x1B, 0x21, FontStyleVal };  
     mbtOutputStream.write(Command);  
     String sendingmessage = "Name : "  
       + mNameEditText.getText().toString();  
     byte[] send = sendingmessage.getBytes();  
     mbtOutputStream.write(send);  
     mbtOutputStream.write(0x0D);  
     sendingmessage = "Amount : "  
       + mAmountEditText.getText().toString();  
     send = sendingmessage.getBytes();  
     mbtOutputStream.write(send);  
     mbtOutputStream.write(0x0D);  
     mbtOutputStream.write(0x0D);  
     mbtOutputStream.write(0x0D);  
     mbtOutputStream.write(0x0D);  
     mbtOutputStream.flush();  
     break;  
      default:  
     break;  
    }  
    // outstream.write(0);  
    // mbtOutputStream.close();  
    // mbtOutputStream.flush();  
   } catch (IOException e) {  
    e.printStackTrace();  
   }  
  }  
  @Override  
  protected void onDestroy() {  
   super.onDestroy();  
   try {  
    if (mbtSocket != null) {  
     mbtOutputStream.close();  
     mbtSocket.close();  
     mbtSocket = null;  
    }  
   } catch (IOException e) {  
    e.printStackTrace();  
   }  
  }  
  @Override  
  protected void onActivityResult(int requestCode, int resultCode, Intent data) {  
   super.onActivityResult(requestCode, resultCode, data);  
   switch (requestCode) {  
   case BTWrapperActivity.REQUEST_CONNECT_BT:  
    try {  
     mbtSocket = BTWrapperActivity.getSocket();  
     if (mbtSocket != null) {  
      if (PrintImage == false) {  
       Thread.sleep(100);  
       senddatatodevice();  
      }  
     }  
    } catch (Exception e) {  
     e.printStackTrace();  
    }  
    break;  
   }  
  }  
 }  



BTWrapperActivity:- check the Bluetooth connection and list all the available Bluetooth devices in the rage of you phone. Select the name of the Bluetooth printer and it automatically create one socket connection with that device and send the data byte by byte.


 package com.trust.trust_bank;

import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Set;
import java.util.UUID;

import android.app.ListActivity;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothSocket;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.widget.Toast;

// =============== Basically is a state machine, and the communications will happen in a separate thread so as not to obstruct the main UI

public class BTWrapperActivity extends ListActivity{

 static public final int REQUEST_CONNECT_BT = 0x2300;

 static private final int REQUEST_ENABLE_BT = 0x1000;

 static private BluetoothAdapter mBluetoothAdapter = null;

 static private ArrayAdapter<String> mArrayAdapter = null;

 //static private Set<BluetoothDevice> btDevices = null;
 static private ArrayAdapter<BluetoothDevice> btDevices = null;//BluetoothDevice[] btDevices = null; 
 private BluetoothDevice btDevices1=null;
 // Unique UUID for this application, Basically the SPP Profile
 private static final UUID SPP_UUID = 
  // UUID.fromString("fa87c0d0-afac-11de-8a39-0800200c9a66");
  UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");

 static private BluetoothSocket mbtSocket = null;

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

  // Change the title of the activity
  setTitle("Bluetooth Devices");

  // Get the List of paired and available devices
  try {
   if(initDevicesList() != 0) {
    this.finish();
    return;
   }

  } catch(Exception ex) {
   this.finish();
   return;
  }

  // Register the Broadcast receiver for handling new BT device discovery
  IntentFilter btIntentFilter = new IntentFilter(BluetoothDevice.ACTION_FOUND);
  registerReceiver(mBTReceiver, btIntentFilter);
 }

 public static BluetoothSocket getSocket() {
  return mbtSocket;
 }

 private void flushData() {
  try {
   if(mbtSocket != null) {
    mbtSocket.close();
    mbtSocket = null;
   }

   if(mBluetoothAdapter != null) {
    mBluetoothAdapter.cancelDiscovery();
   }

   if(btDevices != null) {
    btDevices.clear();
    btDevices = null;
   }

   if(mArrayAdapter != null) {
    mArrayAdapter.clear();    
    mArrayAdapter.notifyDataSetChanged();
    mArrayAdapter.notifyDataSetInvalidated();
    mArrayAdapter = null;
   }

   finalize();

  } catch(Exception ex){} 
  catch (Throwable e) {}

 }


 // Do not forget to add the permission for Bluetooth to use this method
 // Also this method is very tightly coupled with the above method, for getting the status of bt connection 

 private int initDevicesList() {

  // Flush any Pending Data
  flushData();

  // Get the Bluetooth Adaptor of the device
  mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
  if(mBluetoothAdapter == null) {
   // Weird Condition ==== Implies that the device does not have a bluetooth module ?????
   Toast.makeText(getApplicationContext(), "Bluetooth not supported!!", Toast.LENGTH_LONG).show();    
   return -1;
  }

  if(mBluetoothAdapter.isDiscovering()) {
   mBluetoothAdapter.cancelDiscovery();
  }

  mArrayAdapter = new ArrayAdapter<String>(getApplicationContext(), android.R.layout.simple_list_item_1);

  mArrayAdapter.setDropDownViewResource(android.R.layout.simple_dropdown_item_1line);
  
  
  setListAdapter(mArrayAdapter);


  // get the list of devices already paired
  Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
  try {
   startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
  } catch(Exception ex){
   //ex.getStackTrace();
   return -2;
  }


  Toast.makeText(getApplicationContext(), "Getting all available Bluetooth Devices", Toast.LENGTH_SHORT).show();

  return 0;

 } // End getDeviceList

 
 
 @Override
 protected void onActivityResult(int reqCode, int resultCode, Intent intent) {
  super.onActivityResult(reqCode, resultCode, intent);

  switch(reqCode) {
  case REQUEST_ENABLE_BT:

   if(resultCode == RESULT_OK) {
    // Start getting the paired devices list
    Set<BluetoothDevice> btDeviceList = mBluetoothAdapter.getBondedDevices();
    // If there are paired devices
    try {
     if (btDeviceList.size() > 0) {

      // Loop through paired devices
      for (BluetoothDevice device : btDeviceList) {
       if(btDeviceList.contains(device) == false) {

        btDevices.add(device); // Add the device to the device list

        // Add the name and address to an array adapter to show in a ListView
        mArrayAdapter.add(device.getName() + "\n" + device.getAddress() /*+ "\n" + "Status : Paired"*/);
        //mArrayAdapter.notifyDataSetChanged();
        mArrayAdapter.notifyDataSetInvalidated();
       }
      }
     }
    } catch(Exception ex){}
   }


   break;
  }

  // Also register for new devices which are discovered
  mBluetoothAdapter.startDiscovery();

 } // End onActivityResult

 private final BroadcastReceiver mBTReceiver = new BroadcastReceiver() {

  @Override
  public void onReceive(Context context, Intent intent) {
   String action = intent.getAction();
   // When discovery finds a device
   if (BluetoothDevice.ACTION_FOUND.equals(action)) {
    // Get the BluetoothDevice object from the Intent
    BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);

    try{     

     // No paired device found
     if(btDevices == null )
     {    
      btDevices = new ArrayAdapter<BluetoothDevice>(getApplicationContext(), android.R.id.text1);      
     }

     // Ensure non repetability
     if( btDevices.getPosition(device) < 0 ) {
      btDevices.add(device);     
      // Add the name and address to an array adapter to show in a ListView
      mArrayAdapter.add(device.getName() + "\n" + device.getAddress() +"\n" /*+ "Status : Unpaired"*/);
      //mArrayAdapter.notifyDataSetChanged();
      mArrayAdapter.notifyDataSetInvalidated();
     }
    } catch(Exception ex) 
    {
     //ex.fillInStackTrace();
    }
   }
  }
 };

 @Override
 protected void onListItemClick(ListView l, View v, final int position, long id) {
  super.onListItemClick(l, v, position, id);

  // Dont proceed if the bluetooth adapter is not valid
  if(mBluetoothAdapter == null) {
   return;
  }

  // Cancel the dicovery if still going on
  if(mBluetoothAdapter.isDiscovering()) {   
   mBluetoothAdapter.cancelDiscovery();
  }

  // Try to connect with the selected device,
  Toast.makeText(getApplicationContext(), "Connecting to " + btDevices.getItem(position).getName() + "," + btDevices.getItem(position).getAddress(), Toast.LENGTH_SHORT).show();

  // made the thread different as the connecting proceedure might break down the system
  Thread connectThread = new Thread(new Runnable() {

   @Override
   public void run() {
    try {
     try {
      Method m = btDevices.getItem(position).getClass().getMethod("createInsecureRfcommSocket", 
        new Class[] {int.class});
      try {
       //================================================================
       
       String address=btDevices.getItem(position).toString();
       mBluetoothAdapter.getRemoteDevice(address);
       btDevices1=mBluetoothAdapter.getRemoteDevice(address);
      UUID uuid = UUID.fromString("00001101-0000-1000-8000-00805f9b34fb");
       mbtSocket = btDevices1.createRfcommSocketToServiceRecord(uuid);
       mbtSocket.connect();
       //=================================================================
       //mbtSocket = (BluetoothSocket) m.invoke(btDevices.getItem(position), 1);
       //m.invoke(receiver, args)
      } catch (IllegalArgumentException e) {
       e.printStackTrace();
      } /*catch (IllegalAccessException e) {
       e.printStackTrace();
      } catch (InvocationTargetException e) {
       e.printStackTrace();
      } */
     } catch (SecurityException e) {
      e.printStackTrace();
     } catch (NoSuchMethodException e) {
      e.printStackTrace();
     } 
    // mbtSocket = btDevices.getItem(position).createRfcommSocketToServiceRecord(SPP_UUID);
     
    // mbtSocket.connect();
    } catch(IOException ex) {
     //Toast.makeText(getApplicationContext(), "Unable to connect to " + btDevices.getItem(position).getName(), Toast.LENGTH_LONG).show();
     runOnUiThread(socketErrorRunnable);
     //Handler myHandler = new Handler();
     //myHandler.post(socketErrorRunnable);
     try {
      mbtSocket.close();
     } catch (IOException e) {
      //e.printStackTrace();
     }
     mbtSocket = null;
     return;
    } finally {
     runOnUiThread(new Runnable() {

      @Override
      public void run() {
       //flushData();
       unregisterReceiver(mBTReceiver);
       finish();

      }
     });
    }
   }
  });

  connectThread.start();
 }

 private Runnable socketErrorRunnable = new Runnable() {

  @Override
  public void run() {
   Toast.makeText(getApplicationContext(), "Cannot establish connection", Toast.LENGTH_SHORT).show();
   mBluetoothAdapter.startDiscovery();

  }
 };

 @Override
 public boolean onCreateOptionsMenu(Menu menu) {
  super.onCreateOptionsMenu(menu);

  // Add the menu options
  menu.add(0, Menu.FIRST, Menu.NONE, "Refresh Scanning");

  return true;
 }

 @Override
 public boolean onOptionsItemSelected(MenuItem item) {
  super.onOptionsItemSelected(item);

  switch(item.getItemId()) {
  case Menu.FIRST:
   initDevicesList();
   break;
  }

  return true;
 }
} // End of class definition
 



Main.xml:- contains the layout of the app.


 <?xml version="1.0" encoding="utf-8"?>  
 <ScrollView xmlns:android="http://schemas.android.com/apk/res/android"  
   android:layout_width="fill_parent"  
   android:layout_height="fill_parent" >  
   <LinearLayout  
     android:layout_width="fill_parent"  
     android:layout_height="fill_parent"  
     android:orientation="vertical" >  
     <TableRow  
       android:id="@+id/TableRow01"  
       android:layout_width="fill_parent"  
       android:layout_height="wrap_content" >  
       <TextView  
         android:id="@+id/nameTextView"  
         android:layout_width="wrap_content"  
         android:layout_height="wrap_content"  
         android:text="Enter Name  : " >  
       </TextView>  
       <EditText  
         android:id="@+id/nameEditText"  
         android:layout_width="fill_parent"  
         android:layout_height="wrap_content"  
         android:singleLine="true"  
         android:text="" >  
       </EditText>  
     </TableRow>  
     <TableRow  
       android:id="@+id/TableRow02"  
       android:layout_width="fill_parent"  
       android:layout_height="wrap_content" >  
       <TextView  
         android:id="@+id/amountTextView"  
         android:layout_width="wrap_content"  
         android:layout_height="wrap_content"  
         android:text="Enter Amount : " >  
       </TextView>  
       <EditText  
         android:id="@+id/amountEditText"  
         android:layout_width="fill_parent"  
         android:layout_height="wrap_content"  
         android:numeric="decimal"  
         android:singleLine="true"  
         android:text="" >  
       </EditText>  
     </TableRow>  
           <Button  
             android:id="@+id/printButton"  
             android:layout_width="fill_parent"  
             android:layout_height="wrap_content"  
             android:text="Print Form" >  
           </Button>  
     </LinearLayout>  
     </ScrollView>  


Note :-Most importantally you have to take the permission of Bluetooth access. Without taking permission you cannot access Bluetooth of your phone. And app will crash automatically.


Add below code into the manifest.xml:-


 <uses-permission android:name="android.permission.BLUETOOTH"></uses-permission>  
 <uses-permission android:name="android.permission.BLUETOOTH_ADMIN"></uses-permission>  

Hope this code will help someone...

Happy coding....:)