2012年2月18日 星期六

Android - AIDL

在Android中,每個應用程式都可以有自己的進程,在相同的進程中彼此可以共用記憶體資訊,但在不同的進程中,Java中不允許跨進程記憶體共用。

在Linux中是以處理程序為單元來進行資料的配置與管理,但是基於保護目的,一個處理程序不能直接存取另一個處理程序資源。

解決方法 :透過 IPC(Inter-Prcess Communication) 來溝通。

為了完成處理程序之間的通訊,Binder採用了AIDL來描述處理程序間的介面,讓Android得以實踐跨界傳值的目的。(跨界存取)


AIDL(Androoid Interface Definition Language)是一種介面描述語言,編譯器可以通過 .aidl 檔生成一段程式代碼,通過預先定義的介面達到兩個進程內部通訊的目的。


實作方法
IAddService.aidl

package com.aidl;


interface IAddService
{
int add(in int x, in int y);
}


AddService.java

package com.service;


import com.aidl.IAddService;


import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.RemoteException;


public class AddService extends Service
{
@Override
public IBinder onBind(Intent arg0) 
{
IAddService.Stub stub = new IAddService.Stub()
{
@Override
public int add(int x, int y) throws RemoteException
{
return x+y;
}
};

return stub;
}
}


AddServiceConnection.java
package com.service;

import com.aidl.IAddService;

import android.content.ComponentName;
import android.content.ServiceConnection;
import android.os.IBinder;

public class AddServiceConnection implements ServiceConnection
{
private IAddService service; 
@Override
public void onServiceConnected(ComponentName name, IBinder service)
{
this.service = IAddService.Stub.asInterface(service);
}

@Override
public void onServiceDisconnected(ComponentName name)
{
this.service =  null;
}
public IAddService getService()
{
return this.service;
}
}

AIDL_Add.java
package com.test;

import com.aidl.IAddService;
import com.service.AddServiceConnection;

import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;

public class AIDL_Add extends Activity
{
private AddServiceConnection connection;
    private EditText editText01, editText02;
    private TextView textView01;
    private Button button01;
    
    @Override
    public void onCreate(Bundle savedInstanceState) 
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        
        initService();
        
        editText01 = (EditText)findViewById(R.id.editText1);
        editText02 = (EditText)findViewById(R.id.editText2);
        
        textView01 = (TextView)findViewById(R.id.textView2);
        
        button01 = (Button)findViewById(R.id.button1);
        
        button01.setOnClickListener(new Button01OnClickListener());
    }
    
    private void initService()
    {
     connection = new AddServiceConnection();
     Intent intent = new Intent("com.service.REMOTE_SERVICE");
     bindService(intent, connection, Context.BIND_AUTO_CREATE);
    }
    
    class Button01OnClickListener implements OnClickListener
    {
@Override
public void onClick(View view) 
{
int xValue = Integer.parseInt(editText01.getText().toString());
int yValue = Integer.parseInt(editText02.getText().toString());
IAddService service = connection.getService();
try
{
if(service==null)
{
Toast.makeText(AIDL_Add.this, "Service is null", Toast.LENGTH_SHORT).show();
}
else
{
Toast.makeText(AIDL_Add.this, String.valueOf(service.add(xValue, yValue)), Toast.LENGTH_SHORT).show();
textView01.setText(String.valueOf(service.add(xValue, yValue)));
}
}
catch(Exception e)
{
e.printStackTrace();
}
}
    }
}

執行結果如下









2012年2月7日 星期二

Android - AsyncTask

在處理秏時的Android程序時,User可能感覺到系統畫面停頓,感到不協調,甚至發生ANR的錯誤。因此,該耗時程序應另指派一執行緒負責維護運作進行。
PS. UI Thread 若執行5秒以上的工作會拋出ANR的錯誤     
     
AsyncTask執行上的重要方法
(1) onPreExecute( )                               =>    任務執行前呼叫此方法      
(2) doInBackground(Params... )           =>    執行任務工作
(3) onProgressUpdate(Progress... )      =>    顯示任務執行進度
(4) onPostExecute(Result)                    =>    任務執行完成會呼叫此方法        

AsyncTask定義了三種泛型
AsyncTask<Params, Progress, Result>
(1) Params:啟動任務執行的輸入參數,設定於 execute() 的參數型別
(2) Progress:幕後工作執行的百分比
(3) Result:後台執行任務最終返回的結果,設定於 onPostExecute() 的參數型別

    實作方法
    package com.test;

    import java.io.ByteArrayOutputStream;
    import java.io.InputStream;

    import org.apache.http.HttpEntity;
    import org.apache.http.HttpResponse;
    import org.apache.http.client.HttpClient;
    import org.apache.http.client.methods.HttpGet;
    import org.apache.http.impl.client.DefaultHttpClient;

    import android.app.Activity;
    import android.app.ProgressDialog;
    import android.graphics.Bitmap;
    import android.graphics.BitmapFactory;
    import android.graphics.drawable.BitmapDrawable;
    import android.graphics.drawable.Drawable;
    import android.os.AsyncTask;
    import android.os.Bundle;
    import android.view.View;
    import android.view.View.OnClickListener;
    import android.widget.Button;
    import android.widget.ImageView;

    public class AsyncTeskProgress extends Activity
    {
    private Button Button01;
    private ImageView imageView01;
    private String imgURL = "http://vincentjava.skyhostsite.0lx.net/img/white.png";

        @Override
        public void onCreate(Bundle savedInstanceState)
        {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.main);
         
            Button01 = (Button) findViewById(R.id.Button01);
            imageView01 = (ImageView) findViewById(R.id.imageView01);
    Button01.setOnClickListener(new AsyncBtnOnClickListener());
        }
     
        private class AsyncBtnOnClickListener implements OnClickListener
    {
    @Override
    public void onClick(View view)
    {
    imageView01.setVisibility(View.VISIBLE);
    new AsyncTaskLoadImageProgress().execute(imgURL);
    }

    private class AsyncTaskLoadImageProgress extends AsyncTask<String,IntegerDrawable>
    {
    ProgressDialog progressDialog;

    @Override
    protected void onPreExecute()
    {
    progressDialog = new ProgressDialog(AsyncTeskProgress.this);
    progressDialog.setTitle("ProgressDialog");
    progressDialog.setMessage("Wait!");
    progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
    progressDialog.setCancelable(false);
    progressDialog.show();
    }

    @Override
    protected Drawable doInBackground(String... args)
    {
    try
    {
    // 1.取得 HttpEntity 實體
    HttpEntity entity = getHttpEntityByURL(args[0]);
    long length = entity.getContentLength();
    InputStream is = entity.getContent();

    // 2.資料讀取與接收
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    byte[] buf = new byte[128];
    int ch = -1;
    int count = 0;

    while ((ch = is.read(buf)) != -1)
    {
    baos.write(buf, 0, ch);
    count += ch;

    if (length > 0)
    {
    publishProgress((int) ((count / (float) length) * 100));
    }
    }

    // 3.資料轉換 byte[]  -->  Bitmap  -->  Drawable
    byte[] b = baos.toByteArray();
    Bitmap bmp = BitmapFactory.decodeByteArray(b, 0, b.length);
    Drawable drawable = new BitmapDrawable(bmp);

    return drawable;

    }

    catch (Exception e)
    {
    e.printStackTrace();
    }

    return null;
    }

    @Override
    protected void onProgressUpdate(Integer... values)
    {
    // 更新進度
    progressDialog.setProgress(values[0]);
    }

    @Override
    protected void onPostExecute(Drawable resultImage)
    {
    progressDialog.dismiss();

    if (resultImage != null)
    {
    imageView01.setImageDrawable(resultImage);
    imageView01.setVisibility(View.VISIBLE);
    }
    }
    }
    }

    private HttpEntity getHttpEntityByURL(String url) throws Exception
    {
    HttpClient client = new DefaultHttpClient();
    HttpGet get = new HttpGet(url);
    HttpResponse response = client.execute(get);
    HttpEntity entity = response.getEntity();
    return entity;
    }
    }


    執行結果如下

    2012年1月26日 星期四

    Android - TabActivity

    TabHost是Android負責產生Tab Layout的類別,它包含了兩個children,分別為TabWidget與TabContent。

    TabWidget負責處理與User進行互動的Tab,TabContent是根據所選的Tab來顯示相對應的內容。

    實作方法如下:
    main.xml
    <?xml version="1.0" encoding="utf-8"?>
    <TabHost xmlns:android="http://schemas.android.com/apk/res/android"
        android:id="@android:id/tabhost"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent" >

        <LinearLayout
            android:layout_width="fill_parent"
            android:layout_height="fill_parent"
            android:orientation="vertical" >

            <RelativeLayout
                android:layout_width="fill_parent"
                android:layout_height="wrap_content" >

                <HorizontalScrollView
                    android:layout_width="fill_parent"
                    android:layout_height="wrap_content"
                    android:layout_toLeftOf="@+id/next_button"
                    android:layout_toRightOf="@+id/up_button"
                    android:fillViewport="true"
                    android:scrollbars="none" >

                    <TabWidget
                        android:id="@android:id/tabs"
                        android:layout_width="fill_parent"
                        android:layout_height="wrap_content" />
                </HorizontalScrollView>

            </RelativeLayout>

            <FrameLayout
                android:id="@android:id/tabcontent"
                android:layout_width="fill_parent"
                android:layout_height="fill_parent" >

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

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

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

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

                <TextView
                    android:id="@+id/textview05"
                    android:layout_width="fill_parent"
                    android:layout_height="wrap_content" />
            </FrameLayout>

        </LinearLayout>

    </TabHost>

    Tab.java
    public class Tab extends TabActivity
    {
     TabHost tabhost;

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

          //.xml有使用TabHost時才要寫
        setContentView(R.layout.main);     

          //.xml沒有使用TabHost時才要寫
        //LayoutInflater.from(Tab.this).inflate(R.layout.main, tabhost.getTabContentView(), true);
     
     tabhost = getTabHost();

        tabhost.addTab(tabhost.newTabSpec("tab1").setIndicator("Tab1", getResources().getDrawable(android.R.drawable.ic_btn_speak_now)).setContent(R.id.textview01));

        tabhost.addTab(tabhost.newTabSpec("tab2").setIndicator("Tab2").setContent(R.id.textview02));
    tabhost.addTab(tabhost.newTabSpec("tab3").setIndicator("Tab3").setContent(R.id.textview03));
    tabhost.addTab(tabhost.newTabSpec("tab4").setIndicator("Tab4").setContent(R.id.textview04));
        tabhost.addTab(tabhost.newTabSpec("tab5").setIndicator("Tab5").setContent(R.id.textview05));
     
        TabWidget tabWidget = tabhost.getTabWidget();


          //取得Tab的數量
        int count = tabWidget.getChildCount();

          //取得手機的螢幕尺寸
        DisplayMetrics displayMetrics = new DisplayMetrics();
        getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);
        int screenWidth = displayMetrics.widthPixels;
     int screenheight = displayMetrics.heightPixels;

        if (count >= 3)
        {
           for (int i = 0; i < count; i++)
         {
             tabWidget.getChildTabViewAt(i).setMinimumWidth((screenWidth) / 3);
         }
       }

          //設置TabHost點選後的監聽器
        tabhost.setOnClickListener(new TabHostOnClickListener());

          //設置TabHost的Tab切換後的監聽器
        tabhost.setOnTabChangedListener(new TabHostOnTabChangedListener());
     }

      class TabHostOnClickListener implements OnClickListener
     {
    @Override
    public void onClick(View v)
    {
    Toast.makeText(Tab.this, "OnClick~", Toast.LENGTH_SHORT).show();
    }
     }

     class TabHostOnTabChangedListener implements OnTabChangeListener
     {
    @Override
    public void onTabChanged(String tab)
    {
                //必須要與當初設置Tab的Space名稱相同
    if(tab.equals("tab1"))
    {
    Toast.makeText(Tab.this, "Tab1~", Toast.LENGTH_SHORT).show();
    }

    if(tab.equals("tab2"))
    {
    Toast.makeText(Tab.this, "Tab2~", Toast.LENGTH_SHORT).show();
    }

    if(tab.equals("tab3"))
    {
    Toast.makeText(Tab.this, "Tab3~", Toast.LENGTH_SHORT).show();
    }

    if(tab.equals("tab4"))
    {
    Toast.makeText(Tab.this, "Tab4~", Toast.LENGTH_SHORT).show();
    }

    if(tab.equals("tab5"))
    {
    Toast.makeText(Tab.this, "Tab5~", Toast.LENGTH_SHORT).show();
    }
    }
    }
    }

    執行結果如下:

    地心冒險2:神秘島

    今天去中壢威尼斯影城看 "地心冒險2:神秘島",帶著3D眼鏡看電影,感覺真的很棒。

    以下是地心冒險2:神秘島的介紹
    《地心冒險2:神秘島》敘述17歲的少年尚恩(喬許哈契遜飾),無預警收到一連串編碼求救訊號,但是遍尋航海地圖,在發出訊息的座標的方位上卻找不到任何島嶼的痕跡,然而他深信這個訊息是千真萬確,認定他那愛冒險的爺爺發出來的。
    尚恩決定啟程尋覓他那個身在太平洋中某處的爺爺,看到尚恩一副勢在必行的樣子,繼父漢克(巨石強森飾)也只好加入這趟探險,而同行的還有見錢眼開的直昇機飛行員(路易古茲曼)及其美麗的女兒(凡妮莎哈金斯),在艱辛的乘風破浪後,出現在他們的眼前的竟是一座完全超乎人類感官經驗的奇異島嶼,諸如巨大如恐龍般的蜥蜴、小到可以抱在胸前當寵物的大象等,許多不可思議的生物、火山、黃金礦山和若干驚人的祕密,及更多意想不到的驚奇旅程正在前方等著他們。他們將要在大地震造成島嶼下沉、寶藏不見天日前拯救落單居民與平安逃離,如此艱鉅的任務有可能成功達成嗎?
    這部由巨石強森、喬許哈契遜與凡妮莎哈金斯所主演的動作家庭冒險動作續集電影結合了最新的3D拍攝技術,除了古文明的建築與怪異比例的野生動物看起來栩栩如生外,也讓巨石強森的胸肌與手臂的肌肉線條在3D的效果下表露無遺,在拍攝過程中,身兼製片的巨石強森有不少無厘頭的鬼點子出現,甚至拿出看家絕活「抖胸示愛」來娛樂大家,胸部肌肉可以分開或同時作出跳動的高難度動作,還能夠配合講話的速度,不只讓工作人員笑翻和紓壓,最後更被導演設計出現在電影橋段中。

    2011年12月30日 星期五

    Android - Coffee點餐系統

    大學四年級已經過一半了,這個學期我感覺我的Android技術又提昇了,把之前段老師教的內容做個整理,寫出了一個85度C的點餐系統。


    系統流程如下 








    實作結果如下


    系統圖片取自於 85度C 與 其他網站,請不要見諒!!!




    2011年9月12日 星期一

    工讀學習結束(Android)

    好快喔,在華亞科技股份有限公司(Inotera memories)工讀一年的時間就要劃下句點了!


    這一年,雖然沒學到專業技術,只是做物料管理、搬貨等打雜的工作,但是自己也去外面學了我欠缺的技能。


    雖然目前尚未學的很深入,可是學習的過程中,非常很快樂,完全不會覺得很無聊。


    Android ,讚!!! ~~~~~~