Thursday, April 21, 2016

[Đồ thị] Lý thuyết đồ thị - Đường đi, Chu trình, Đồ thị liên thông

Đồ thị: là một cấu trúc dữ liệu rời rạc bao gồm các đỉnh và các cạnh nối các cặp đỉnh này. Chúng ta phân biệt đồ thị thông qua kiểu và số lượng cạnh nối giữa các cặp đỉnh của đồ thị.
Dưới đây là một ví dụ về mạng máy tính bao gồm: mỗi máy tính là một đỉnh, mỗi kênh điện thoại kết nối là cạnh của đồ thị
Đồ thị: Mạng máy tính

Trong mạng máy tính trên, mỗi máy tính là một đỉnh của đồ thị, các kênh điện thoại là cạnh của đồ thị, không có hai cặp cạnh nào nối cùng một cặp đỉnh. Ta gọi đây là đơn đồ thị vô hướng.
Đơn đồ thị vô hướng: Đơn đồ thị vô hướng G = <V,E> bao gồm V là tập các đỉnh, E là tập các cặp có thứ tự gồm hai phần tử khác nhau của V gọi là các cạnh.
Trong trường hợp giữa máy tính nào đó thường xuyên phải truyền tải thông tin nên người ta xây dựng thêm một kênh điện thoại nữa để tăng khả năng truyền tải thông tin, khi đó hai máy tính sẽ có nhiều hơn một kênh điện thoại kết nối. Ta gọi đây là đa đồ thị vô hướng.
Mạng máy tính đa kênh thoại

Đa đồ thị vô hướng: G = <V, E> bao gồm V là tập các đỉnh, E là họ các cặp không có thứ tự gồm hai phần tử khác nhau của V gọi là tập các cạnh. e1, e2 được gọi là cạnh lặp nếu chúng cùng tương ứng với một cặp đỉnh.
Mạng máy tính đa kênh thoại có khuyên

Giả đồ thị vô hướng: G = <V, E> bao gồm V là tập đỉnh, E là họ các cặp không có thứ tự gồm hai phần tử (hai phần tử không nhất thiết phải khác nhau) trong V được gọi là các cạnh. Cạnh e được gọi là khuyên nếu có dạng e =(u, u), trong đó u là đỉnh nào đó thuộc V.

Trong nhiều mạng, các kênh kết nối giữa hai máy tính chỉ có thể truyền tải thông tin theo một chiều.Chẳng hạn máy tính đặt tại Hà Nội có thể truy cập dữ liệu của máy tính đặt tại Hải Phòng, nhưng máy tính ở Hải Phòng không thể truy cập dữ liệu của máy tính ở Hà Nội. Để mô tả mạng máy tính này chúng ta dùng khái niệm đồ thị có hướng.
Mạng máy tính có hướng

Đơn đồ thị có hướng G = <V, E> bao gồm V là tập các đỉnh, E là tập các cặp có thứ tự gồm hai phần tử của V gọi là các cung.
Trong trường hợp có nhiều hơn một kênh có hướng kết nối giữa hai đỉnh của đồ thị, để mô tả mạng máy tính này ta dùng khái niệm đa đồ thị có hướng.
Mạng máy tính đa kênh một chiều 

Đa đồ thị có hướng G = <V, E> bao gồm V là tập đỉnh, E là cặp có thứ tự gồm hai phần tử của V được gọi là các cung. Hai cung e1, e2 tương ứng với cùng một cặp đỉnh được gọi là cung lặp.
Loại đồ thị Cạnh Có cạnh bội Có khuyên
Đơn đồ thị vô hướng Vô hướng Không Không
Đa đồ thị vô hướng Vô hướng Không
Giả đồ thị vô hướng Vô hướng
Đồ thị có hướng Có hướng Không
Đa đồ thị có hướng Có hướng
*Hai đỉnh u và v của đồ thị vô hướng G =<V, E> được gọi là kề nhau nếu (u,v) là cạnh thuộc đồ thị G. Nếu e =(u, v) là cạnh của đồ thị G thì ta nói cạnh này liên thuộc với hai đỉnh u và v, hoặc ta nói cạnh e nối đỉnh u với đỉnh v, đồng thời các đỉnh u và v sẽ được gọi là đỉnh đầu của cạnh (u,v).
*Ta gọi bậc của đỉnh v trong đồ thị vô hướng là số cạnh liên thuộc với nó và ký hiệu là deg(v).
deg(a) = 2, deg(b) =deg(c) = deg(f) = 4, deg(e) = 3, deg(d) = 1, deg(g)=0.
Đồ thị có hướng G
Nếu e=(u,v) là cung của đồ thị có hướng G thì ta nói hai đỉnh u và v là kề nhau, và nói cung (u, v) nối đỉnh u với đỉnh v. Đỉnh u sẽ được gọi là đỉnh đầu v là đỉnh cuối của cung (u,v).
Ta gọi bán bậc ra (bán bậc vào) của đỉnh v trong đồ thị có hướng là số cung của đồ thị đi ra khỏi nó (đi vào nó) và ký hiệu là deg+(v) và deg-(v).
deg-(a) = 1, deg-(b) = 2, deg-(c) = 2, deg-(d) = 2, deg-(e) = 2. deg+(a) = 3, deg+(b) = 1, deg+(c) = 1, deg+(d) = 2, deg+(e) = 2.
Đường đi: Đường đi độ dài n từ đỉnh u đến đỉnh v trên đồ thị vô hướng G=<V,E> là dãy: x0, x1,..., xn-1, xn trong đó n là số nguyên dương, x0=u, xn=v, (xi, xi+1)∈E, i =0, 1, 2,..., n-1.
Đường đi như trên còn có thể biểu diễn thành dãy các cạnh:
(x0, x1), (x1,x2),..., (xn-1, xn).
Đỉnh u là đỉnh đầu, đỉnh v là đỉnh cuối của đường đi. Đường đi có đỉnh đầu trùng với đỉnh cuối (u=v) được gọi là chu trình. Đường đi hay chu trình được gọi là đơn nếu như không có cạnh nào lặp lại.
Đồ thị vô hướng được gọi là liên thông nếu luôn tìm được đường đi giữa hai đỉnh bất kỳ của nó.

Wednesday, February 17, 2016

[Android] Swipe RecyleView cho Android

Sau một thời gian sử dụng sử dụng Gmail và Outlook mình bắt đầu tìm hiểu và tìm kiếm một thư viện hỗ trợ để có được những hiệu ứng tương tự.

Sau khi Google mình tìm thấy thư viện AndroidSwipeLayout có hỗ trợ các hiệu ứng khá đẹp. Thư viện khi kết hợp với RecycleView sẽ tạo ra nhiều option cho người dùng chọn khi swipe trái/phải màn hình.
Bài viết này mình sẽ hướng dẫn các bạn thêm thư viện AndroidSwipeLayout kết hợp với RecyclerView vào project.
Các bước thực hiện như sau:
Bước 1: Add thư viện
Mở file gradle và thêm dòng sau.
compile 'com.daimajia.swipelayout:library:1.2.0@aar'
Bước 2: Định nghĩa item của listview
Trong phần res/layout, thêm file swipe_row_item.xml dùng để định nghĩa một thành phần của Listview.
<?xml version="1.0" encoding="utf-8" ?>
<com.daimajia.swipe.SwipeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:swipe="http://schemas.android.com/apk/res-auto"
    android:id="@+id/swipe"
    android:layout_width="match_parent"
    android:layout_height="73dp"
    swipe:leftEdgeSwipeOffset="0dp"
    swipe:rightEdgeSwipeOffset="0dp">

    <!--Bottom View For Right to Left-->

    <LinearLayout
        android:id="@+id/bottom_wrapper"
        android:layout_width="240dp"
        android:layout_height="match_parent"
        android:weightSum="3">

        <TextView
            android:id="@+id/tvEdit"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:background="#0076a5"
            android:gravity="center"
            android:text="Edit"
            android:textColor="#fff" />

        <TextView
            android:id="@+id/tvShare"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:background="#003c54"
            android:gravity="center"
            android:text="Share"
            android:textColor="#fff" />

        <TextView
            android:id="@+id/tvDelete"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:background="#0076a5"
            android:gravity="center"
            android:text="Delete"
            android:textColor="#fff" />
    </LinearLayout>


    <!-- Another Bottom View For Left to Right -->

    <LinearLayout
        android:id="@+id/bottom_wrapper1"
        android:layout_width="80dp"
        android:layout_height="match_parent"
        android:weightSum="1">

        <ImageButton
            android:id="@+id/btnLocation"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:background="@null"
            android:gravity="center"
            android:src="@drawable/location_icon" />
    </LinearLayout>

    <!-- Top View,  Row itemView of RecyclerView -->
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="73dp"
        android:background="?android:selectableItemBackground"
        android:orientation="horizontal">
        <RelativeLayout
            android:layout_width="85dp"
            android:layout_height="match_parent"
            android:paddingLeft="18dp"
            android:paddingRight="18dp"
            android:paddingTop="8dp"
            android:paddingBottom="8dp">
            <ImageView
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:src="@drawable/contact_default"/>
        </RelativeLayout>
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:orientation="vertical"
            android:paddingRight="18dp"
            android:paddingTop="15dp"
            android:paddingBottom="15dp">
            >
            <!--contact name layout-->
            <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:orientation="horizontal">
                <TextView
                    android:id="@+id/tvName"
                    android:layout_width="200dp"
                    android:layout_height="20dp"
                    android:text="Name"
                    android:textColor="@android:color/black"
                    android:textSize="16sp" />
                <TextView
                    android:id="@+id/tvDeliveryStatus"
                    android:layout_width="match_parent"
                    android:layout_height="20dp"
                    android:gravity="right"
                    android:textAlignment="gravity"
                    android:text="Sent"/>
            </LinearLayout>
            <!--message content-->
            <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:orientation="horizontal">
                <TextView
                    android:id="@+id/tvEmailId"
                    android:layout_width="200dp"
                    android:layout_height="20dp"
                    android:layout_below="@+id/tvName"
                    android:text="Email Id"
                    android:textColor="@android:color/black"
                    android:textSize="12sp" />
                <ImageView
                    android:layout_width="match_parent"
                    android:layout_height="match_parent"
                    android:adjustViewBounds="true"
                    android:scaleType="fitEnd"
                    android:src="@drawable/facebook_icon"/>
            </LinearLayout>
        </LinearLayout>


    </LinearLayout>

</com.daimajia.swipe.SwipeLayout>
Bước 3: Tạo lớp Student.
package com.blogspot.simplecodecjava.swiperecycleview;
import java.io.Serializable;
public class Student implements Serializable {
    private static final long serialVersionUID = 1L;
    private String name;
    private String emailId;
    public Student() {
    }
    public Student(String name, String emailId) {
        this.name = name;
        this.emailId = emailId;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getEmailId() {
        return emailId;
    }
    public void setEmailId(String emailId) {
        this.emailId = emailId;
    }
}
Bước 4: Tạo lớp SwipeRecyclerViewAdapter kế thừa từ RecyclerSwipeAdapter.
package com.blogspot.simplecodecjava.swiperecycleview;
import android.content.Context;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageButton;
import android.widget.TextView;
import android.widget.Toast;

import com.daimajia.swipe.SwipeLayout;
import com.daimajia.swipe.adapters.RecyclerSwipeAdapter;
import com.slab.schedulerchat.R;

import java.util.ArrayList;

public class SwipeRecyclerViewAdapter extends RecyclerSwipeAdapter<SwipeRecyclerViewAdapter.SimpleViewHolder> {


    private Context mContext;
    private ArrayList<Student> studentList;

    public SwipeRecyclerViewAdapter(Context context, ArrayList<Student> objects) {
        this.mContext = context;
        this.studentList = objects;
    }

    @Override
    public SimpleViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.swipe_row_item, parent, false);
        return new SimpleViewHolder(view);
    }

    @Override
    public void onBindViewHolder(final SimpleViewHolder viewHolder, final int position) {
        final Student item = studentList.get(position);

        viewHolder.tvName.setText((item.getName()) + "  -  Row Position " + position);
        viewHolder.tvEmailId.setText(item.getEmailId());


        viewHolder.swipeLayout.setShowMode(SwipeLayout.ShowMode.PullOut);

        // Drag From Left
        viewHolder.swipeLayout.addDrag(SwipeLayout.DragEdge.Left, viewHolder.swipeLayout.findViewById(R.id.bottom_wrapper1));

        // Drag From Right
        viewHolder.swipeLayout.addDrag(SwipeLayout.DragEdge.Right, viewHolder.swipeLayout.findViewById(R.id.bottom_wrapper));


        // Handling different events when swiping
        viewHolder.swipeLayout.addSwipeListener(new SwipeLayout.SwipeListener() {
            @Override
            public void onClose(SwipeLayout layout) {
                //when the SurfaceView totally cover the BottomView.
            }

            @Override
            public void onUpdate(SwipeLayout layout, int leftOffset, int topOffset) {
                //you are swiping.
            }

            @Override
            public void onStartOpen(SwipeLayout layout) {

            }

            @Override
            public void onOpen(SwipeLayout layout) {
                //when the BottomView totally show.
            }

            @Override
            public void onStartClose(SwipeLayout layout) {

            }

            @Override
            public void onHandRelease(SwipeLayout layout, float xvel, float yvel) {
                //when user's hand released.
            }
        });

        /*viewHolder.swipeLayout.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {


                if ((((SwipeLayout) v).getOpenStatus() == SwipeLayout.Status.Close)) {
                    //Start your activity

                    Toast.makeText(mContext, " onClick : " + item.getName() + " \n" + item.getEmailId(), Toast.LENGTH_SHORT).show();
                }

            }
        });*/

        viewHolder.swipeLayout.getSurfaceView().setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Toast.makeText(mContext, " onClick : " + item.getName() + " \n" + item.getEmailId(), Toast.LENGTH_SHORT).show();
            }
        });


        viewHolder.btnLocation.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

                Toast.makeText(v.getContext(), "Clicked on Map " + viewHolder.tvName.getText().toString(), Toast.LENGTH_SHORT).show();
            }
        });


        viewHolder.tvShare.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {

                Toast.makeText(view.getContext(), "Clicked on Share " + viewHolder.tvName.getText().toString(), Toast.LENGTH_SHORT).show();
            }
        });

        viewHolder.tvEdit.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {

                Toast.makeText(view.getContext(), "Clicked on Edit  " + viewHolder.tvName.getText().toString(), Toast.LENGTH_SHORT).show();
            }
        });


        viewHolder.tvDelete.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                mItemManger.removeShownLayouts(viewHolder.swipeLayout);
                studentList.remove(position);
                notifyItemRemoved(position);
                notifyItemRangeChanged(position, studentList.size());
                mItemManger.closeAllItems();
                Toast.makeText(view.getContext(), "Deleted " + viewHolder.tvName.getText().toString(), Toast.LENGTH_SHORT).show();
            }
        });


        // mItemManger is member in RecyclerSwipeAdapter Class
        mItemManger.bindView(viewHolder.itemView, position);

    }

    @Override
    public int getItemCount() {
        return studentList.size();
    }

    @Override
    public int getSwipeLayoutResourceId(int position) {
        return R.id.swipe;
    }


    //  ViewHolder Class

    public static class SimpleViewHolder extends RecyclerView.ViewHolder {
        SwipeLayout swipeLayout;
        TextView tvName;
        TextView tvEmailId;
        TextView tvDelete;
        TextView tvEdit;
        TextView tvShare;
        ImageButton btnLocation;

        public SimpleViewHolder(View itemView) {
            super(itemView);
            swipeLayout = (SwipeLayout) itemView.findViewById(R.id.swipe);
            tvName = (TextView) itemView.findViewById(R.id.tvName);
            tvEmailId = (TextView) itemView.findViewById(R.id.tvEmailId);
            tvDelete = (TextView) itemView.findViewById(R.id.tvDelete);
            tvEdit = (TextView) itemView.findViewById(R.id.tvEdit);
            tvShare = (TextView) itemView.findViewById(R.id.tvShare);
            btnLocation = (ImageButton) itemView.findViewById(R.id.btnLocation);


        }
    }
}
Bước 5: Khai báo MainAtivity.
package com.blogspot.simplecodecjava.swiperecycleview;

import android.content.Context;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.Toolbar;
import android.util.Log;
import android.view.View;
import android.widget.TextView;
import java.util.ArrayList;

public class MainActivity extends AppCompatActivity {
    private ArrayList<Student> mDataSet;
    private String TAG = MainActivity.class.getName();
    private Toolbar toolbar;
    private TextView tvEmptyView;
    private RecyclerView mRecyclerView;
    private volatile static MainActivity mInstance;
    public static MainActivity getInstance(Context context){
        if(mInstance == null){
            synchronized (MainActivity.class){
                if(mInstance == null){
                    mInstance = new MainActivity();
                }
            }
        }
        return mInstance;
    }
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        toolbar = (Toolbar) findViewById(R.id.toolbar);
        tvEmptyView = (TextView) findViewById(R.id.empty_view);
        mRecyclerView = (RecyclerView) findViewById(R.id.my_recycler_view);
        mRecyclerView.setLayoutManager(new LinearLayoutManager(this));
        mDataSet = new ArrayList<Student>();
        if (toolbar != null) {
            setSupportActionBar(toolbar);
            getSupportActionBar().setTitle("Android Students");

        }
        loadData();
        if (mDataSet.isEmpty()) {
            mRecyclerView.setVisibility(View.GONE);
            tvEmptyView.setVisibility(View.VISIBLE);

        } else {
            mRecyclerView.setVisibility(View.VISIBLE);
            tvEmptyView.setVisibility(View.GONE);
        }
        SwipeRecyclerViewAdapter mAdapter = new SwipeRecyclerViewAdapter(this, mDataSet);
        mRecyclerView.setAdapter(mAdapter);
        mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
            @Override
            public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
                super.onScrollStateChanged(recyclerView, newState);
                Log.e("RecyclerView", "onScrollStateChanged");
            }

            @Override
            public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
                super.onScrolled(recyclerView, dx, dy);
            }
        });
    }
    public void loadData() {

        for (int i = 0; i <= 20; i++) {
            mDataSet.add(new Student("Student " + i, "androidstudent" + i + "@gmail.com"));
        }
    }
}
Bước 6: Khai báo activity_main layout.
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <android.support.v7.widget.Toolbar
        android:id="@+id/toolbar"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="#FF4081"
        android:elevation="8dp"
        android:minHeight="?attr/actionBarSize">

    </android.support.v7.widget.Toolbar>

    <android.support.v7.widget.RecyclerView
        android:id="@+id/my_recycler_view"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_margin="5dp"
        android:layout_weight="1"
        android:scrollbars="vertical" />
    <TextView
        android:id="@+id/empty_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:gravity="center"
        android:text="No Records"
        android:visibility="gone" />


</LinearLayout>
Bạn có thể tải project mẫu tại đây.
Nguồn: blogger.com

Monday, February 15, 2016

[Android] Thư viện TimePicker & DatePicker đẹp cho android.

Qua một thời gian sử dụng Google calendar mình thấy cách chọn thời gian để đặt sự kiện, ghi nhớ rất dễ hiểu và trực quan. Bạn hãy xem cách Time/Date Picker của Google hoạt động trên Google calendar.
Qua một thời gian search trên Google để tìm thư viện mã nguồn mở về cách lựa chọn thời gian giống như trên mình có tìm thấy android-betterpickers.
Dưới đây là hình ảnh về Time/Date Picker thư viện hỗ trợ.

Sau đây mình sẽ hướng dẫn các bạn thêm thư viện vào trong project bằng Android studio.
Bước 1: Add thư viện vào trong file gradle.
Mở file gradle và thêm dòng sau.
compile 'com.code-troopers.betterpickers:library:2.5.1'

*Trong trường hợp add thư viện vào bạn nhận được thông báo
Error:A problem occurred configuring project ':app'.
> Could not download library.aar (com.code-troopers.betterpickers:library:2.5.1)
   > Could not get resource 'https://jcenter.bintray.com/com/code-troopers/betterpickers/library/2.5.1/library-2.5.1.aar'.
      > Could not GET 'https://jcenter.bintray.com/com/code-troopers/betterpickers/library/2.5.1/library-2.5.1.aar'.
         > peer not authenticated

Lỗi trên có thể được khắc phục bằng cách thực hiện các bước sau:
  1. Download library-2.5.1.aar bằng trình cách paste vào trình duyệt địa chỉ https://jcenter.bintray.com/com/code-troopers/betterpickers/library/2.5.1/library-2.5.1.aar
  2. Copy file library-2.5.1.aar vào thư mục libs
  3. Thêm
    allprojects {
       repositories {
          jcenter()
          flatDir {
            dirs 'libs'
          }
       }
    }
    
    dependencies {
        compile(name:'library-2.5.1', ext:'aar')
    }
    

    vào file build gradle.
Bước 2: Bắt action và hiển thị Time/Date Picker vào main code.
Dưới đây là các ví dụ:
1. Calendar Date Picker.
button.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        CalendarDatePickerDialogFragment cdp = new CalendarDatePickerDialogFragment()
                .setOnDateSetListener(SampleCalendarDateBasicUsage.this)
                .setFirstDayOfWeek(Calendar.SUNDAY)
                .setPreselectedDate(towDaysAgo.getYear(), towDaysAgo.getMonthOfYear() - 1, towDaysAgo.getDayOfMonth())
                .setDateRange(minDate, null)
                .setThemeDark(true);
        cdp.show(getSupportFragmentManager(), FRAG_TAG_DATE_PICKER);
    }
});

2. Redial Time Picker
button.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        RadialTimePickerDialogFragment rtpd = new RadialTimePickerDialogFragment()
                .setOnTimeSetListener(SampleRadialTimeBasicUsage.this)
                .setStartTime(10, 10)
                .setThemeDark(true);
        rtpd.show(getSupportFragmentManager(), FRAG_TAG_TIME_PICKER);
    }
});
3. Recurrence Picker
button.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        FragmentManager fm = getSupportFragmentManager();
        Bundle bundle = new Bundle();
        Time time = new Time();
        time.setToNow();
        bundle.putLong(RecurrencePickerDialogFragment.BUNDLE_START_TIME_MILLIS, time.toMillis(false));
        bundle.putString(RecurrencePickerDialogFragment.BUNDLE_TIME_ZONE, time.timezone);
        bundle.putString(RecurrencePickerDialogFragment.BUNDLE_RRULE, mRrule);
        bundle.putBoolean(RecurrencePickerDialogFragment.BUNDLE_HIDE_SWITCH_BUTTON, true);

        RecurrencePickerDialogFragment rpd = new RecurrencePickerDialogFragment();
        rpd.setArguments(bundle);
        rpd.setOnRecurrenceSetListener(SampleRecurrenceBasicUsage.this);
        rpd.show(fm, FRAG_TAG_RECUR_PICKER);
    }
});
4. Timezone Picker
button.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        FragmentManager fm = getSupportFragmentManager();
        Bundle bundle = new Bundle();
        Time time = new Time();
        time.setToNow();
        bundle.putLong(TimeZonePickerDialogFragment.BUNDLE_START_TIME_MILLIS, time.toMillis(false));
        bundle.putString(TimeZonePickerDialogFragment.BUNDLE_TIME_ZONE, time.timezone);
        bundle.putString(RecurrencePickerDialogFragment.BUNDLE_RRULE, mRrule);

        TimeZonePickerDialogFragment tzpd = new TimeZonePickerDialogFragment();
        tzpd.setArguments(bundle);
        tzpd.setOnTimeZoneSetListener(SampleTimeZoneBasicUsage.this);
        tzpd.show(fm, FRAG_TAG_TIME_ZONE_PICKER);
    }
});
5. Date Picker
button.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        DatePickerBuilder dpb = new DatePickerBuilder()
                .setFragmentManager(getSupportFragmentManager())
                .setStyleResId(R.style.BetterPickersDialogFragment)
                .setYearOptional(true);
        dpb.show();
    }
});
6. Expiration Picker
button.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        ExpirationPickerBuilder epb = new ExpirationPickerBuilder()
                  .setFragmentManager(getSupportFragmentManager())
                  .setStyleResId(R.style.BetterPickersDialogFragment) 
                  .setMinYear(2000);
        epb.show();
    }
});
7. HMS Picker
button.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        HmsPickerBuilder hpb = new HmsPickerBuilder()
                .setFragmentManager(getSupportFragmentManager())
                .setStyleResId(R.style.BetterPickersDialogFragment);
        hpb.show();
    }
});
8. Number Picker
button.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        NumberPickerBuilder npb = new NumberPickerBuilder()
                .setFragmentManager(getSupportFragmentManager())
                .setStyleResId(R.style.BetterPickersDialogFragment)
                .setLabelText("LBS.");
        npb.show();
}
});
9. Time Picker
button.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        TimePickerBuilder tpb = new TimePickerBuilder()
                .setFragmentManager(getSupportFragmentManager())
                .setStyleResId(R.style.BetterPickersDialogFragment);
        tpb.show();
    }
});
Theming.
Đồng thời bạn có thể định nghĩa theme theo phong cách của riêng bạn.
    bpDialogBackground       :: drawable của DialogFragment background.
    bpTextColor              :: màu của text trong DialogFragment.
    bpDeleteIcon             :: drawable của delete button.
    bpCheckIcon              :: drawable của check button trong DateDialogPicker.
    bpKeyBackground          :: drawable của keyboard buttons.
    bpButtonBackground       :: drawable cho các nút Set, Cancel, and Delete buttons.
    bpDividerColor           :: màu của DialogFragment dividers.
    bpKeyboardIndicatorColor :: màu của ViewPagerIndicator trong DateDialogPicker.
  1. Tạo theme cá nhân trong file styles.xml
    <style name="MyCustomBetterPickerTheme">
        <item name="bpDialogBackground">@drawable/custom_dialog_background</item>
        <item name="bpTextColor">@color/custom_text_color</item>
        <item name="bpDeleteIcon">@drawable/ic_backspace_custom</item>
        <item name="bpCheckIcon">@drawable/ic_check_custom</item>
        <item name="bpKeyBackground">@drawable/key_background_custom</item>
        <item name="bpButtonBackground">@drawable/button_background_custom</item>
        <item name="bpDividerColor">@color/custom_divider_color</item>
        <item name="bpKeyboardIndicatorColor">@color/custom_keyboard_indicator_color</item>
    </style>
    
  2. Khởi tạo DialogFragment có sử dụng theme trên.
    DatePickerBuilder dpb = new DatePickerBuilder()
        .setFragmentManager(getSupportFragmentManager())
        .setStyleResId(R.style.MyCustomBetterPickerTheme);
    dpb.show();
    
Source code của chương trình được tải về tại đây.
Theo gitHub.com

Friday, January 15, 2016

[Java] Copy dữ liệu sang file khác trong Java

Bài viết sẽ trình bày cách copy dữ liệu từ một file sang một file khác trong Java. Theo thứ tự để copy dữ liệu sang file khác, ta cần phải đọc dữ liệu (sử dụng FileInputStream) và viết dữ liệu sang file khác (sử dụng FileOutputStream).
Chương trình sau sẽ copy dữ liệu từ file "MyInputFile.txt" sang file "MyOutputFile.txt". Nếu file "MyOutputFile.txt" chưa tồn tại thì chương trình sẽ tạo file và copy dữ liệu sang file đó.
package simplecodecjava.blogspot.com;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;

public class CopyExample {
 public static void main(String[] args) {
  FileInputStream instream = null;
  FileOutputStream outstream = null;

  try {
   File infile = new File("src/simplecodecjava/blogspot/com/MyInputFile.txt");
   File outfile = new File("src/simplecodecjava/blogspot/com/MyOutputFile.txt");

   instream = new FileInputStream(infile);
   outstream = new FileOutputStream(outfile);

   byte[] buffer = new byte[1024];

   int length;
   /*
    * copy dữ liệu từ file đầu vào sang file đầu ra
    *  sử dụng phương thức read và write trong java.
    */
   while ((length = instream.read(buffer)) > 0) {
    outstream.write(buffer, 0, length);
   }
   /*Đóng luồng input/output*/
   instream.close();
   outstream.close();
   System.out.println("Copy thành công!");
  } catch (IOException ioe) {
   ioe.printStackTrace();
  }
 }
}
Output
Copy thành công!
Chương trình trên sử dụng phương thức read để đọc dữ liệu.
public int read(byte[] b) throws IOException
Khi gọi phương thức trên chương trình sẽ đọc vào mảng buffer 1024 (kích thước của mảng đệm buffer) byte từ luồng dữ liệu đầu vào instream . Phương thức này sẽ trả về số tổng số file được đọc vào mảng buffer. Nếu file không chứa dữ hiệu hoặc chương trình đã đọc đến đoạn kết thúc của file phương thức read sẽ trả về -1.

Chương trình trên sử dụng phương thức write để ghi dữ liệu.
public void write(byte[] b,int off, int length) throws IOException
Phương thức trên sẽ viết length byte từ mảng b bắt đầu từ vị trí off ra file đầu ra.

Saturday, January 9, 2016

[Java] Lấy IP trong Java

Bài viết sẽ hướng dẫn bạn lấy địa chỉ IP từ hệ thống. Các bước để lấy địa chỉ IP như sau:
1. Lấy địa chỉ local host bằng phương thức getLocalHost() của class InetAddress.
2. Lấy địa chỉ IP bằng phương thức getHostAddress().
Chương trình cài đặt.
package simplecodecjava.blogspot.com;

import java.net.InetAddress;

public class GetIPAddress {
 public static void main(String[]args) throws Exception{
  /*phhương thức static InetAddress getLocalHost() ném ra UnknownHostException,
  Phương thức này trả về địa chỉ của local host.*/
  InetAddress myIP = InetAddress.getLocalHost();
  System.out.print("Địa chỉ IP của máy tính là: ");
  System.out.print(myIP.getHostAddress());
  
 }
}

Output:
Địa chỉ IP của máy tính là: 107.113.187.26

Thursday, January 7, 2016

[Java] Chuyển từ hệ thập phân sang hệ nhị phân.

Có 3 cách để chuyển một số từ hệ thập phân sang hệ nhị phân.
  1. Sử dụng phương thức toBinaryString() trong class Integer của Java.
  2. Sử dụng phương thức chuyển đổi bằng logic mà không sử dụng phương thức có sẵn của Java.
  3. Sử dụng Stack.
1. Sử dụng phương thức toBinaryString().
package simplecodecjava.blogspot.com;

public class DecimalToBinaryExample {
 public static void main(String[]args){
  int decimalNumber = 123456789;
  System.out.print("Hệ nhị phân của " + decimalNumber +" là :");
  System.out.print(Integer.toBinaryString(decimalNumber));
 }
}
Output:
Hệ nhị phân của 123456789là :111010110111100110100010101
2. Sử dụng chuyển đổi bằng logic.
package simplecodecjava.blogspot.com;

public class DecimalToBinaryExample {
 
 public void convertBinary(int num){
      int binary[] = new int[40];
      int index = 0;
      while(num > 0){
        binary[index++] = num%2;
        num = num/2;
      }
      for(int i = index-1;i >= 0;i--){
        System.out.print(binary[i]);
      }
   }
  
 public static void main(String[]args){
  int decimalNumber = 123456789;
  System.out.print("Hệ nhị phân của " + decimalNumber +" là :");
  new DecimalToBinaryExample().convertBinary(decimalNumber);
 }
}
Output:
Hệ nhị phân của 123456789 là :111010110111100110100010101
3. Sử dụng Stack.
package simplecodecjava.blogspot.com;

import java.util.Stack;

public class DecimalToBinaryExample {
 
 public void convertBinary(int num){
  Stack<Integer> stack = new Stack<Integer>();
     while(num != 0){
      //thực hiện phép chia lấy phần dư cho 2.
      int d = num%2;
      // thêm vào stack.
      stack.push(d);
      num/=2;
     }
     while(!(stack.isEmpty())){
      System.out.print(stack.pop());
     }
     
   }
  
 public static void main(String[]args){
  int decimalNumber = 123456789;
  System.out.print("Hệ nhị phân của " + decimalNumber +" là :");
  new DecimalToBinaryExample().convertBinary(decimalNumber);
 }
}
Output:
Hệ nhị phân của 123456789 là :111010110111100110100010101

Wednesday, January 6, 2016

[Java] Sự khác nhau giữa HashMap và Hashtable

Sự khác nhau giữa HashMap HashTable ? Đây là câu hỏi thường được đưa ra trong các cuộc phỏng vấn chuyên gia Java/J2EE.
HashMapHashTable đều được implements từ java.util.Map interface. Tuy nhiên có một vài sự khác biệt giữa chúng trong cách thức hoạt động và sử dụng.
HashMap vs HashTable.
1. Khả năng đồng bộ.
- HashMap là lớp không đồng bộ (non-synchronized). Điều đó có nghĩa là HashMap có thể cho phép có nhiều hơn một thread cùng truy cập và sử lý dữ liệu và nó chứa đựng một cách đồng thời.
 void clear()
 Object clone()
 boolean containsKey(Object key)
 boolean containsValue(Object value)
 Set<Entry<K, V>> entrySet()
 V get(Object key)
 boolean isEmpty()
 Set<k> keySet()
 V put(K key, V value)
 void putAll(Map map)
 V remove(Object key)
 int size()
 Collection<v> values()

- HashTable là lớp đồng bộ (synchronized). Điều đó có nghĩa là HashTable chỉ cho phép tối đa một thread truy cập và xử lý dữ liệu tại một thời điểm. Thread này chiếm giữ HashTable và các Thread khác phải chờ cho đến khi Thread này truy cập và xử lý  xong.
 synchronized void clear()
 synchronized Object clone()
 boolean contains(Object value)
 synchronized boolean containsKey(Object key)
 synchronized boolean containsValue(Object value)
 synchronized Set<Entry<K, V>> entrySet()
 synchronized boolean equals(Object object)
 synchronized V get(Object key)
 synchronized int hashCode()
 synchronized boolean isEmpty()
 synchronized Set<k> keySet()
 synchronized Enumeration<k> keys()
 synchronized V put(K key, V value)
 synchronized void putAll(Map map)
 synchronized V remove(Object key)
 synchronized int size()
 synchronized String toString()
 synchronized Collection<v> values()


2. Khóa và Giá trị.
- HashMap cho phép lưu khóa và giá trị là NULL.
- HashTable không cho phép lưu khóa và giá trị là NULL.
package simplecodecjava.blogspot.com;

import java.util.HashMap;
import java.util.Hashtable;

public class HashMapvsHashTable {
 private HashMap<String, String> myHashMap = new HashMap<String, String>();
 private Hashtable<String, String> myHashTable = new Hashtable<String, String>();
 public HashMapvsHashTable() {
  try{
  myHashMap.put(null, null);
  myHashTable.put(null, null);
  }catch(Exception e){
   e.printStackTrace();
  }
 }
 public static void main(String[]args){
  new HashMapvsHashTable();
 }
}
Output
java.lang.NullPointerException
 at java.util.Hashtable.put(Unknown Source)
 at simplecodecjava.blogspot.com.HashMapvsHashTable.<init>(HashMapvsHashTable.java:12)
 at simplecodecjava.blogspot.com.HashMapvsHashTable.main(HashMapvsHashTable.java:18)

3. Chèn và ánh xạ.
- HashMap là cài đặt của LinkedHashMap TreeMap. Vì vậy mà khi các phần từ được chèn vào trong HashMap theo một thứ tự và sắp xếp sự ánh xạ theo thứ tự tăng dần của khóa.
- HashTable thì ngược lại. Tức các phần tử được chèn vào trong HashTable không theo một thứ tự và sự ánh xạ cũng không theo thứ tự tăng dần của khóa.
4. Thành phần của Java Collection Framework.
- HashMap là một thành phần của Java Collection Framework.
- HashTable là lớp được dùng lại từ thành phần Java cũ nên không thuộc Java Collection Framework.
//HashTable được định nghĩa như sau
public class Hashtable extends Dictionary implements Map, Cloneable, Serializable {}
//HashMap được định nghĩa như sau
public class HashMap extends AbstractMap implements Map, Cloneable, Serializable {}
5. Cải tiến
 HashMap khắc phục một vài thiếu sót của HashTable. HashTable có phương thức contains(Object value) sẻ trả về true nếu HashTale có chứa đối tượng value. Trong khi đó HashMap có hai phương thức: phương thức containsKey(Object key) trả về true nếu HashMap có chứa đối tượng khóa, phương thức containValue(Object value) trả về true nếu HashMap có chứa đối tượng giá trị.
Sử dụng HashMap và HashTable.
1. Như so sánh ở trên sự khác nhau quan trọng nhất của HashMap HashTable là khả năng đồng bộ. Khi muốn sự thực thi của các luồng diễn ra an toàn thì nên sử dụng HashTable.
2. Sự đồng bộ sẽ làm giảm hiệu năng của chương trình vì vậy việc đồng bộ các luồng (synchromized) nên được tránh trừ trường hợp thực sự cần thiết. Do đó trong trường chương trình có nhiều Thread không đọc và ghi dữ liệu đồng thời thì nên sử dụng HashMap.