Monday 3 August 2015

making #hashtag and @usertag clickable to a textview same as twitter with a single string

Hello all,

Today I am going to share a very nice example for making #hashtag and @user_name is clickable in a  single string .

I have tried many example for this,  but now it is working

First I have make a textview in the layout , I am assuming that the layout design is not needed to share , as It is simply a textview (having the is textview1) in a Relative Layout.

Now I have to add two base classes which is used to get the symbols(#, @) in the string

I have made two base classes one is for the @ symbol and another is for # symbol. If you want to make string clickable on any other symbol alos like: $ then you have to make another base class for $ symbol also, But for now I will work with the two base classes for the two symbols .

One base class name is :  Hashtag.java  (This class is for # symbol)

import android.content.Context;
import android.text.Spanned;
import android.text.TextPaint;
import android.text.style.ClickableSpan;
import android.util.Log;
import android.view.View;
import android.widget.TextView;
import android.widget.Toast;

public class Hashtag extends ClickableSpan{
Context context;
TextPaint textPaint;
    public Hashtag(Context ctx) {
   super();
   context = ctx;
}

@Override
public void updateDrawState(TextPaint ds) {
   textPaint = ds;
  ds.setColor(ds.linkColor);
   ds.setARGB(255, 30, 144, 255);
}

@Override
public void onClick(View widget) {
   TextView tv = (TextView) widget;
   Spanned s = (Spanned) tv.getText();
   int start = s.getSpanStart(this);
   int end = s.getSpanEnd(this);
   String theWord = s.subSequence(start + 1, end).toString();
   // you can start another activity here 
   Toast.makeText(context, String.format("Tag : %s", theWord), 10 ).show();

}

}


Another base class name is :  CalloutLink.java  (This class is for @ symbol)

import android.content.Context;
import android.graphics.Color;
import android.text.Spanned;
import android.text.TextPaint;
import android.text.style.ClickableSpan;
import android.view.View;
import android.widget.TextView;
import android.widget.Toast;

public class CalloutLink extends ClickableSpan {
Context context;
public CalloutLink(Context ctx) {
   super();
   context = ctx;
}

@Override
public void updateDrawState(TextPaint ds) {
 ds.setARGB(255, 51, 51, 51);
 ds.setColor(Color.RED);

}

@Override
public void onClick(View widget) {
   TextView tv = (TextView) widget;
   Spanned s = (Spanned) tv.getText();
   int start = s.getSpanStart(this);
   int end = s.getSpanEnd(this);
   String theWord = s.subSequence(start + 1, end).toString();
  // you can start another activity here 
   Toast.makeText(context, String.format("Here's a cool person: %s", theWord), 10).show();
    }
}


Now let's move to the MainActivity .java 

import java.util.ArrayList;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import com.libs.CalloutLink;
import com.libs.Hashtag;
import android.app.Activity;
import android.os.Bundle;
import android.text.SpannableString;
import android.text.method.LinkMovementMethod;
import android.util.Log;
import android.widget.TextView;

public class MainActivity extends  Activity{

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

String str  =  "@People , You've gotta #dance like there's nobody watching,#Love like you'll never be #hurt,#Sing like there's @nobody listening,And live like it's #heaven on #earth.";

TextView txt = (TextView)findViewById(R.id.textView1);
ArrayList<int[]> hashtagSpans1 = getSpans(str, '#');
    ArrayList<int[]> calloutSpans1 = getSpans(str, '@');
    
    SpannableString commentsContent1 =
            new SpannableString(str);

   setSpanComment(commentsContent1,hashtagSpans1) ;
   setSpanUname(commentsContent1,calloutSpans1) ;
   
   txt.setMovementMethod(LinkMovementMethod.getInstance());
   txt.setText(commentsContent1);
}
public ArrayList<int[]> getSpans(String body, char prefix) {
   ArrayList<int[]> spans = new ArrayList<int[]>();

   Pattern pattern = Pattern.compile(prefix + "\\w+");
   Matcher matcher = pattern.matcher(body);

   // Check all occurrences
   while (matcher.find()) {
       int[] currentSpan = new int[2];
       currentSpan[0] = matcher.start();
       currentSpan[1] = matcher.end();
       spans.add(currentSpan);
   }

   return  spans;
}

private void setSpanComment(SpannableString commentsContent, ArrayList<int[]> hashtagSpans) {
for(int i = 0; i < hashtagSpans.size(); i++) {
       int[] span = hashtagSpans.get(i);
       int hashTagStart = span[0];
       int hashTagEnd = span[1];

       commentsContent.setSpan(new Hashtag(MainActivity.this),
               hashTagStart,
               hashTagEnd, 0);

   }

   
}
private void setSpanUname(SpannableString commentsUname, ArrayList<int[]> calloutSpans) {
for(int i = 0; i < calloutSpans.size(); i++) {
        int[] span = calloutSpans.get(i);
        int calloutStart = span[0];
        int calloutEnd = span[1];
        commentsUname.setSpan(new CalloutLink(MainActivity.this),
                calloutStart,
                calloutEnd, 0);

    }
}

}


That's all , no permission is required in the menifest.

I am attaching the screen shot for this task:
                                                                                                                                                                 
   

 screenshots for #tag   and @username clickable textview

Please leave a comment if you have any query regarding to this example


Monday 22 June 2015

XML Parsing

Hello all,

In the previous blog I have shared the json parsing ,now I am sharing the xml parsing.

I have pasted an api having xml format :


<menu>

<item>

<id>1</id>

<name>Margherita</name>

<cost>155</cost>

<description>Single cheese topping</description>
</item>

<item>

<id>2</id>

<name>Double Cheese Margherita</name>

<cost>225</cost>

<description>Loaded with Extra Cheese</description>
</item>

.
.
.
.
.
.
.

<item>

<id>10</id>

<name>Chicken Golden Delight</name>

<cost>490</cost>

<description>Golden corn, Double Barbeque and Cheese</description>
</item>
</menu>


First I have made a class which is used to connect with the server.
and I have made another class which is used to check the internet connection
I have made a class named ConnectionDetector.java to check the internet connection:
public class ConnectionDetector { private Context _context; public ConnectionDetector(Context context){ this._context = context; } public boolean isConnectingToInternet(){ ConnectivityManager connectivity = (ConnectivityManager)_context
.getSystemService(Context.CONNECTIVITY_SERVICE); if (connectivity != null) { NetworkInfo[] info = connectivity.getAllNetworkInfo(); if (info != null) for (int i = 0; i < info.length; i++) if (info[i].getState() == NetworkInfo.State.CONNECTED) { return true; } } return false; } }


Now let's make another class which is used to connect with the server and help to fetch the values of the nodes. I have named it XMLParser.java :

import java.io.IOException; import java.io.StringReader; import java.io.UnsupportedEncodingException; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; import org.apache.http.client.ClientProtocolException; import org.apache.http.client.methods.HttpPost; import org.apache.http.impl.client.DefaultHttpClient; import org.apache.http.util.EntityUtils; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import org.xml.sax.InputSource; import org.xml.sax.SAXException; import android.util.Log; public class XMLParser { // constructor public XMLParser() { } /** * Getting XML from URL making HTTP request * @param url string * */ public String getXmlFromUrl(String url) { String xml = null; try { // defaultHttpClient DefaultHttpClient httpClient = new DefaultHttpClient(); HttpPost httpPost = new HttpPost(url); HttpResponse httpResponse = httpClient.execute(httpPost); HttpEntity httpEntity = httpResponse.getEntity(); xml = EntityUtils.toString(httpEntity); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } catch (ClientProtocolException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } // return XML return xml; } /** * Getting XML DOM element * @param XML string * */ public Document getDomElement(String xml){ Document doc = null; DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); try { DocumentBuilder db = dbf.newDocumentBuilder(); InputSource is = new InputSource(); is.setCharacterStream(new StringReader(xml)); doc = db.parse(is); } catch (ParserConfigurationException e) { Log.e("Error: ", e.getMessage()); return null; } catch (SAXException e) { Log.e("Error: ", e.getMessage()); return null; } catch (IOException e) { Log.e("Error: ", e.getMessage()); return null; } return doc; } /** Getting node value * @param elem element */ public final String getElementValue( Node elem ) { Node child; if( elem != null){ if (elem.hasChildNodes()){ for( child = elem.getFirstChild(); child != null; child = child.getNextSibling() ){ if( child.getNodeType() == Node.CDATA_SECTION_NODE ||child.getNodeType() == Node.TEXT_NODE ){ return child.getNodeValue(); } } } } return ""; } /** * Getting node value * @param Element node * @param key string * */ public String getValue(Element item, String str) { NodeList n = item.getElementsByTagName(str); return this.getElementValue(n.item(0)); } }

Now I have make a layout for showing response in a list, containing a listview ,named :
first.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"
    android:orientation="vertical" 
    android:background="#FFFFFF">

    <ListView
        android:id="@+id/listView1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:layout_alignParentTop="true"
         >
    </ListView>

</RelativeLayout>

I have made another xml which contains the design for the single row of the listview ,I have named it : row.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="30sp"
    android:orientation="vertical" >

    <TextView
        android:id="@+id/textView1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="TextView"
        android:textColor="#000000"
        android:layout_margin="5sp"/>

</LinearLayout>

Now let's move to the main activity,in which all the main codes and functionality to fetch the responses has been described ,I have named it : XmlParsingActivity.java

import java.util.ArrayList;
import java.util.HashMap;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.ProgressDialog;
import android.os.AsyncTask;
import android.os.Build;
import android.os.Bundle;
import android.widget.ListView;
import android.widget.Toast;
import com.adapter.FirstAdapter;
import com.json.libs.ConnectionDetector;
import com.json.libs.XMLParser;

public class XmlParsingActivity extends Activity{
ListView list;
ProgressDialog dlg;
ArrayList<HashMap<String,String>> Show = null;
static final String URL = "";// mention the api url of xml format
    // XML node keys
   public static final String KEY_ITEM = "item"; // parent node
   public static final String KEY_ID = "id";
   public  static final String KEY_NAME = "name";
   public static final String KEY_COST = "cost";
   public static final String KEY_DESC = "description";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.first);
list = (ListView)findViewById(R.id.listView1);
InItAction();
}

private void InItAction() {
ConnectionDetector cd = new ConnectionDetector(getApplicationContext());
if (cd.isConnectingToInternet()) {
new AsyncTaskLoad().execute();
}
else{
Toast.makeText(getApplicationContext(),"Interent not available!",Toast.LENGTH_LONG).show();
}
}
class AsyncTaskLoad extends AsyncTask<String,String,String>
{
@Override
protected void onPreExecute() {
super.onPreExecute();
if (Build.VERSION.SDK_INT >= 11 ) {
  dlg = new ProgressDialog(XmlParsingActivity.this,AlertDialog.THEME_HOLO_LIGHT );
     } else {
        dlg = new ProgressDialog(XmlParsingActivity.this);
       }
       dlg.setMessage("Loading...");
       dlg.show();
}
@Override
protected String doInBackground(String... params) {
Show = new ArrayList<HashMap<String,String>>();
try {
//http://api.androidhive.info/pizza/?format=xml
XMLParser parser = new XMLParser();
       String xml = parser.getXmlFromUrl(URL); // getting XML
       Document doc = parser.getDomElement(xml); // getting DOM element
 
       NodeList nl = doc.getElementsByTagName(KEY_ITEM);
       // looping through all item nodes <item>
       for (int i = 0; i < nl.getLength(); i++) {
           // creating new HashMap
           HashMap<String, String> map = new HashMap<String, String>();
           Element e = (Element) nl.item(i);
           // adding each child node to HashMap key => value
           map.put(KEY_ID, parser.getValue(e, KEY_ID));
           map.put(KEY_NAME, parser.getValue(e, KEY_NAME));
           map.put(KEY_COST, "Rs." + parser.getValue(e, KEY_COST));
           map.put(KEY_DESC, parser.getValue(e, KEY_DESC));
 
           // adding HashList to ArrayList
           Show.add(map);
       }
} catch (IllegalStateException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
@Override
protected void onPostExecute(String result) {
super.onPostExecute(result);
dlg.dismiss();
if (Show.size()==0) {
list.setAdapter(null);
Toast.makeText(getBaseContext(),"no contacts!!",Toast.LENGTH_LONG).show();
}
else
{
FirstAdapter adapter = new FirstAdapter(XmlParsingActivity.this,Show);
list.setAdapter(adapter);
}
}
}
}


Now we have to make an adapter to show all the items in a listview I have named it :
FirstAdapter.java

import java.util.ArrayList;
import java.util.HashMap;
import com.blogdemo.R;
import com.blogdemo.XmlParsingActivity;
import android.app.Activity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.TextView;

public class FirstAdapter extends BaseAdapter{

Activity activity;
ArrayList<HashMap<String, String>> Show = new ArrayList<HashMap<String,String>>();
ViewHolder holder ;
public FirstAdapter(Activity mactivity,
ArrayList<HashMap<String, String>> show) {
this.activity = mactivity;
this.Show = show;
}

@Override
public int getCount() {
return Show.size();
}

@Override
public Object getItem(int position) {
return Show.get(position);
}

@Override
public long getItemId(int position) {
return Show.size();
}
private class ViewHolder {
public TextView txt;
}

@Override
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null) {
LayoutInflater mLayoutInflater = LayoutInflater.from(activity);
convertView = mLayoutInflater.inflate(R.layout.row,
null);
       holder = new ViewHolder();
holder.txt = (TextView)convertView.findViewById(R.id.textView1);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
holder.txt.setText("id: "+Show.get(position).get(XmlParsingActivity.KEY_ID)+" \n"
   +"Name: "+Show.get(position).get(XmlParsingActivity.KEY_NAME)
   +" \n"+"Price:"+Show.get(position).get(XmlParsingActivity.KEY_COST)
    +" \n"+"Detail:"+Show.get(position).get(XmlParsingActivity.KEY_DESC));
return convertView;
}
}

That's all... Don't forgot to add following permission in the menifest :

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








  Screen shot for the response of an api using xml parsing technique







Advanced Kotlin Coroutines : Introduction

 Hi,  Today I am unwraping the topic in Kotin world i.e. Coroutine . If you want to get started with Kotlin coroutine and ease your daily de...