2011年10月30日 星期日

Android筆記,控制appwidget














透過按鈕讓桌面的小時鐘,暫停或顯示時間,上面是模擬器出現的畫面

原理用一個Thread讓service每秒啓動一次,更新view寫在onStart(service啓動時執行一次),當按下按鈕決定view是否要更新,這個Thread只在widget初始化時才newㄧ次


1.Clock_widget.java



package test.Clock_widget1;

import java.util.Calendar;
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;

import android.app.PendingIntent;
import android.app.Service;
import android.appwidget.AppWidgetManager;
import android.appwidget.AppWidgetProvider;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.util.Log;
import android.widget.RemoteViews;
import android.widget.Toast;

//自定義clock_thread class 繼承Thread,s毫秒送出sendMessage
class clock_Thread extends Thread{
  //變數宣告
  Handler thandler;
  private int sc;
  private Message m;
  boolean paused;
  //建構子,初始化
  public clock_Thread(Handler h,int s){
  sc=s;//毫秒
  thandler =h;
  }

public void run(){
super.run();
try{
 while(true){
     Thread.sleep(sc);
   
   m=new Message();
     thandler.sendMessage(m);
   
      }//while
 }catch (Exception e) {
    Log.d("tag", "error");
    //  handle exception
   }//cttch
}//run
//set handler_

public void set_handler(Handler h){
this.thandler=h;
}
//set second
public void set_second(int s){
this.sc=s;
}

}//thread




public class Clock_widget extends AppWidgetProvider {



//變數宣告
//public Handler c_Handler;
public  static Handler w_handler;
private int[] sappWidgetIds;
    private AppWidgetManager sappWidgetManager;
    private static Context scontext;
    private clock_Thread cthread;
public static String CLICK_ACTION1 ;
public static String CLICK_ACTION2 ;
    static private boolean START_TIME;//是否顯示時間


   // 建構子初始化Clock_widget,能初始化盡量初始化
 
public  Clock_widget() {
//按鈕1字串
CLICK_ACTION1 = "test.widget_clock.CLICK1";
//按鈕2字串
CLICK_ACTION2 = "test.widget_clock.CLICK2";

START_TIME=true;
w_handler=null;
  //一開始handler null,1秒送出message
cthread=new clock_Thread(w_handler,1000);
//start thread
cthread.start();

}
@Override
public void onReceive(Context context, Intent intent) {
 super.onReceive(context, intent);
 final String action = intent.getAction();
 if(action.equals(CLICK_ACTION1)){
     
      //context.startService(intent1);
 START_TIME=true;
     
      Toast.makeText(context, "開時時間", Toast.LENGTH_LONG).show();
      }
 if(action.equals(CLICK_ACTION2)){
 START_TIME=false;
 Toast.makeText(context, "停止時間", Toast.LENGTH_LONG).show();
 }



}

   @Override
 
   public void onUpdate(final Context context,AppWidgetManager appWidgetManager, int[] appWidgetIds) {
 
    //onUpdate時放到全域變數
    sappWidgetManager = appWidgetManager;
    sappWidgetIds = appWidgetIds;
    scontext = context;
   
    //綁定Clock_widget注意androidmanifest receiver需註冊action
       final Intent refreshIntent1 = new Intent(scontext, Clock_widget.class);
       //set action字串
   refreshIntent1.setAction(Clock_widget.CLICK_ACTION1);
    PendingIntent refreshPendingIntent1 = PendingIntent.getBroadcast(scontext, 0,refreshIntent1, PendingIntent.FLAG_UPDATE_CURRENT);
   //final PendingIntent refreshPendingIntent = PendingIntent.getService(cc, 0,refreshIntent, 0);
   RemoteViews updateViews1 = new RemoteViews( scontext.getPackageName(), R.layout.main);
       //設定button
   updateViews1.setOnClickPendingIntent(R.id.button1, refreshPendingIntent1);
       //update view
       sappWidgetManager.updateAppWidget(sappWidgetIds, updateViews1);
   
   
   
    //綁定Clock_widget注意androidmanifest receiver需註冊action
       final Intent refreshIntent2 = new Intent(scontext, Clock_widget.class);
       //set action字串
   refreshIntent2.setAction(Clock_widget.CLICK_ACTION2);
    PendingIntent refreshPendingIntent2 = PendingIntent.getBroadcast(scontext, 0,refreshIntent2, PendingIntent.FLAG_UPDATE_CURRENT);
   //final PendingIntent refreshPendingIntent = PendingIntent.getService(cc, 0,refreshIntent, 0);
   RemoteViews updateViews2 = new RemoteViews( scontext.getPackageName(), R.layout.main);
       //設定button
   updateViews2.setOnClickPendingIntent(R.id.button2, refreshPendingIntent2);
       //update view
       sappWidgetManager.updateAppWidget(sappWidgetIds, updateViews2);
   
       //new handler
 
   w_handler =new Handler(){
          public void handleMessage(Message msg) {
Intent intent = new Intent(scontext, MyService.class);
  //start service
   scontext.startService(intent);
}
};//Hamdler
//重設handler
cthread.set_handler(w_handler);
   
   }//onupdate
 
   //取得時間,宣告成static可值接用,不須new
   public static String get_date(){
   int c_Minutes; //分
   int c_Hour; //時
   int c_Second;
   int c_year; //時
   int c_month;
   final String str;
   long time=System.currentTimeMillis();
final Calendar c_Calendar = Calendar.getInstance();
c_Calendar.setTimeInMillis(time);
c_Hour=c_Calendar.get(Calendar.HOUR);
c_Minutes=c_Calendar.get(Calendar.MINUTE);
c_Second=c_Calendar.get(Calendar.SECOND);
c_month=c_Calendar.get(Calendar.MONTH);
c_year=c_Calendar.get(Calendar.YEAR);
 str="西元"+c_year+"年"+c_month+"月"+c_Hour+"時"+c_Minutes+"分"+c_Second+"秒";
   return str;
   }
 
 


//MyService服務程式 ,背景運作
 
 
   public static class MyService extends Service {
 
    //onStart階段service啓動只執行一次
       @Override
       public void onStart(Intent intent, int startId) {
        if(START_TIME){
           ComponentName thisWidget = new ComponentName(this, Clock_widget.class);
           AppWidgetManager manager = AppWidgetManager.getInstance(this);
           RemoteViews remoteViews = new RemoteViews(getPackageName(), R.layout.main);
            //Toast.makeText(this, "開時時間", Toast.LENGTH_LONG).show();
           remoteViews.setTextViewText(R.id.textView1, get_date());
         
           manager.updateAppWidget(thisWidget, remoteViews);
        Log.d("TAG","true") ;
}else{
Log.d("TAG","false") ;
}//if
       }
       @Override
       public IBinder onBind(Intent intent) {
           return null;
       }
   } //service

}//app class


2.AndroidManifest.xml


<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
      package="test.Clock_widget1"
      android:versionCode="1"
      android:versionName="1.0">
    <uses-sdk android:minSdkVersion="11" />

    <application android:icon="@drawable/icon" android:label="@string/app_name">
            <receiver android:name=".Clock_widget" >
            <intent-filter>
                <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />

                <!--receiver註冊action-->
                <action android:name="test.widget_clock.CLICK1" />
                <action android:name="test.widget_clock.CLICK2" />

            </intent-filter>
            <meta-data android:name="android.appwidget.provider"
                android:resource="@xml/clockprovider" />
           </receiver>
           <service android:enabled="true" android:name=".Clock_widget$MyService">

            <intent-filter>
                <!--service註冊action,mark掉>
                                <action android:name="test.widget_clock.CLICK3" />
                                </-->
                        </intent-filter>

                </service>

    </application>
</manifest>


3.clockprovider.xml

<?xml version="1.0" encoding="utf-8"?>
<appwidget-provider
  xmlns:android="http://schemas.android.com/apk/res/android"

    android:minWidth="100dp"
    android:minHeight="50dp"
    android:updatePeriodMillis="0"
    android:initialLayout="@layout/main"
  >

</appwidget-provider>

4.main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"

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

    <TextView
        android:id="@+id/textView1"
        android:layout_width="843dp"
        android:layout_height="wrap_content"
        android:text="TextView"
        android:textSize="18dp" >
</TextView>
    <LinearLayout android:id="@+id/linearLayout1" android:layout_height="wrap_content" android:layout_width="match_parent" android:layout_weight="0.13" android:weightSum="1">

    <LinearLayout
        android:id="@+id/linearLayout2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" >

            <Button android:id="@+id/button1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="顯示時間"></Button>
            <Button android:id="@+id/button2" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="暫停時間"></Button>
        </LinearLayout>
    </LinearLayout>


</LinearLayout>





read more...

2011年10月29日 星期六

Android appwidget service筆記













一開始service未啟動















按按鈕啟動service














再按按鈕顯示時間











android appwidget透過一個按鈕來啟動背景servicey,在透過另一按鈕更新時間(appwidget的建立可參考上一篇)











1. 
reciver註冊action (給按鈕1)Clock_widget
  <action android:name="test.widget_clock.CLICK1" />
service註冊action(給按鈕2)Myservice

  <action android:name="test.widget_clock.CLICK1" />

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
      package="test.Clock_widget1"
      android:versionCode="1"
      android:versionName="1.0">
    <uses-sdk android:minSdkVersion="11" />

    <application android:icon="@drawable/icon" android:label="@string/app_name">
            <receiver android:name=".Clock_widget" >
            <intent-filter>
                <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
              
                <action android:name="test.widget_clock.CLICK2" />
           
            </intent-filter>
            <meta-data android:name="android.appwidget.provider"
                android:resource="@xml/clockprovider" />
           </receiver>
           <service android:enabled="true" android:name=".Clock_widget$MyService">
      
           <intent-filter>
                <action android:name="test.widget_clock.CLICK1" />
            </intent-filter>
        </service>

    </application>
</manifest>

2.
//綁定service,注意androidmanifest receiver需註冊action
               Intent intent1 = new Intent(context, MyService.class);
              //啟動服務 
              context.startService(intent1);


 action動作的溝通需建立Intent


Clock_widget.java



package test.Clock_widget1;

import java.util.Calendar;
import java.util.Date;

import android.app.PendingIntent;
import android.app.Service;
import android.appwidget.AppWidgetManager;
import android.appwidget.AppWidgetProvider;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.os.Handler;
import android.os.IBinder;
import android.widget.RemoteViews;
import android.widget.Toast;




public class Clock_widget extends AppWidgetProvider {
  
  
  
    //變數宣告
    public Handler c_Handler;
    public Handler r_Handler;
 
  
  
    public Calendar c_Calendar; //日曆
  
    public static String CLICK_ACTION1 ;
    public static String CLICK_ACTION2 ;
  

 
    public  Clock_widget() {
        //按鈕1字串
        CLICK_ACTION1 = "test.widget_clock.CLICK1";
        //按鈕2字串
        CLICK_ACTION2 = "test.widget_clock.CLICK2";
        c_Handler=new Handler();
      
      
     
      
      
    }
    @Override
     public void onReceive(Context context, Intent intent) {
          super.onReceive(context, intent);
          final String action = intent.getAction();
          if(action.equals(CLICK_ACTION2)){
              //if(c_Thread.isInterrupted())c_Thread.resume();
          
              //綁定service
               Intent intent1 = new Intent(context, MyService.class);
              //啟動服務  
              context.startService(intent1);
              
            
              Toast.makeText(context, "開時service", Toast.LENGTH_LONG).show();
          }
        
     }

        @Override
      
        public void onUpdate(Context context,AppWidgetManager appWidgetManager, int[] appWidgetIds) {
      
      
        
            //綁定Clock_widget注意androidmanifest receiver需註冊action
            final Intent refreshIntent1 = new Intent(context, Clock_widget.class);
            //set action字串
            refreshIntent1.setAction(Clock_widget.CLICK_ACTION2);
            final PendingIntent refreshPendingIntent1 = PendingIntent.getBroadcast(context, 0,refreshIntent1, PendingIntent.FLAG_UPDATE_CURRENT);
            //final PendingIntent refreshPendingIntent = PendingIntent.getService(cc, 0,refreshIntent, 0);
            RemoteViews updateViews1 = new RemoteViews( context.getPackageName(), R.layout.main);
            //設定button
            updateViews1.setOnClickPendingIntent(R.id.button2, refreshPendingIntent1);
            //update view
            appWidgetManager.updateAppWidget(appWidgetIds, updateViews1);
        
        
      
    
        }//onupdate
  
     
      
        public static class MyService extends Service {
          

          
          
            @Override
            public void onStart(Intent intent, int startId) {
                ComponentName thisWidget = new ComponentName(this, Clock_widget.class);
                AppWidgetManager manager = AppWidgetManager.getInstance(this);
                RemoteViews remoteViews = new RemoteViews(getPackageName(), R.layout.main);
              
                //intent.getAction()取得action字串
                if (CLICK_ACTION1.equals(intent.getAction())) {
                  
                    Toast.makeText(this, "開時時間", Toast.LENGTH_LONG).show();
                    remoteViews.setTextViewText(R.id.textView1, new Date().toLocaleString());
                }else{
                    remoteViews.setTextViewText(R.id.textView1, "時間顯示器");  
                }
                //綁定Clock_widget注意androidmanifest receiver需註冊action
                Intent clickIntent = new Intent();
                clickIntent.setAction(CLICK_ACTION1);
                PendingIntent pendingIntent = PendingIntent.getService(this, 0, clickIntent, 0);
               
                remoteViews.setOnClickPendingIntent(R.id.button1, pendingIntent);
                manager.updateAppWidget(thisWidget, remoteViews);
              
            }
            @Override
            public IBinder onBind(Intent intent) {
                return null;
            }
        }

}









read more...

2011年10月21日 星期五

Android筆記 - 設計appwidget


























設計一個在平板桌面上跑的小時鐘,用thread每秒更新一次時間 據上一次程式,這小工具是在桌面上來顯示因此,新增Project時不選Create Activity,此次轉換到MacBook Air機器上開發(因為模擬器比較正常一些)

1.新增Project名稱叫widget_clock(File->New->Project->Android Project->Next->Project Name->Next->Android 3.0->
不選Create Activity
Pockage Name :test.clock_widget

2.新增appwidget-provider(File->New->Other->Android XML File->Next->Resource Type選 AppWidget Provider)(如下圖)



























產生好xml filfe(clock_widge.xml)後,修改下面紅色字體部份(亮藍色背景)
說明:

android:updatePeriodMillis="0"代表只讓appwidget更新一次,我要自行用thread來更新

android:initialLayout="@layout/main" 是指initialLayout指定你layout佈局的xml(main)


clock_widge.xml File:

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

<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"

    android:minWidth="294dp"

    android:minHeight="150dp"

    android:updatePeriodMillis="0"

    android:initialLayout="@layout/main" 

     >

</appwidget-provider>

3.修改main.xml的內容加入下面紅色字體部份(亮藍色背景)
說明:

android:id="@+id/now設定view id


main.xml File:

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

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

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

    <TextView
    android:id="@+id/now"
    android:gravity="center"
    android:textColor="@android:color/white"
    android:textSize="32sp"
    android:layout_width="fill_parent" 
    android:layout_height="fill_parent" 
    android:text="@string/hello"
    />

LinearLayout>
4.修改AndroidManifest.xml加入下面紅色字體部份(亮藍色背景)

說明:
<receiver android:name=".Clock_widget" >
<service android:enabled="true" android:name=".Clock_widget" />
同時指定receiver,service.Clock_widget(java class,這是要新增class更新appwidget)


<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
指定動作方式APPWIDGET_UPDATE

android:resource="@xml/clock_widge" />
指定resource="@xml/clock_widge" (步驟1新增的xml)

AndroidManifest.xml File:

<xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="test.widget_clock"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk android:minSdkVersion="10" />

    <application
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name" >

         <receiver android:name=".Clock_widget" >
            <intent-filter>
                <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
            </intent-filter>
            <meta-data android:name="android.appwidget.provider"
                android:resource="@xml/clock_widge" />
        </receiver>
         <service android:enabled="true" android:name=".Clock_widget" />
        
            
            
    application>

manifest>
5.新增class(Clock_widget)File->New->Class


說明:
Clock_widget.java內容如下
class繼承了AppWidgetProvider並覆寫更新onUpdate程序,Handler是要工作的內容,thread來時時送出handler訊息
updateViews.setTextViewText(R.id.now, str ); 
updateViews.setTextColor(R.id.now, -1);
這兩行now對應到main.xml所設的id

Clock_widget.java File:

package test.widget_clock;



import java.util.Calendar;


import android.appwidget.AppWidgetManager;
import android.appwidget.AppWidgetProvider;
import android.content.Context;
import android.os.Handler;
import android.os.Message;
import android.widget.RemoteViews;

public class Clock_widget extends AppWidgetProvider{
public Handler c_Handler;
public Context cc;
public int[] aapid;
public AppWidgetManager appw;
private Thread c_Thread;
public Calendar c_Calendar; //日曆
private int c_Minutes; //
private int c_Hour; //
private int c_Second; //
private String str;
@Override
public void onUpdate(Context context,AppWidgetManager appWidgetManager, int[] appWidgetIds) {
cc=context;
aapid=appWidgetIds;
appw=appWidgetManager;
c_Handler =new Handler(){
public void handleMessage(Message msg){
long time=System.currentTimeMillis();
final Calendar c_Calendar = Calendar.getInstance();
c_Calendar.setTimeInMillis(time);
c_Hour=c_Calendar.get(Calendar.HOUR);
c_Minutes=c_Calendar.get(Calendar.MINUTE);
c_Second=c_Calendar.get(Calendar.SECOND);
str="現在時間 "+c_Hour+":"+c_Minutes+":"+c_Second;
RemoteViews updateViews = new RemoteViews( cc.getPackageName(), R.layout.main);
updateViews.setTextViewText(R.id.now, str );
updateViews.setTextColor(R.id.now, -1);

appw.updateAppWidget(aapid, updateViews);
}
};
//產執行續物件
c_Thread = new clock_Thread();
//啟動執行續
c_Thread.start();

}//onupdate

//thread class
class clock_Thread extends Thread{
public void run(){
super.run();
try{
do{
Thread.sleep(1000);
Message m=new Message();
// Message物件送入MessageQueue
c_Handler.sendMessage(m);
}while(true);
}catch (Exception e) {
// handle exception
}//cttch
}//run
}//thread


}//Clock_widget class

5.模擬器上跑的結果




read more...

2011年10月15日 星期六

Android筆記

UBUNTU1004下使用ECLIPSE,撰寫Android,Java安裝使用Synaptic安裝OpenJdk,其他設定google找一下

1.Ctrl+Shift+o自動import
2.連點res->layout->gt;main.xml啟動Layout(UI設計)
3.事件處理:Layout中選取元件->Properties->On click填入處理method name(如下圖右側)














4.Java程式主體
連點SRC下的Activity(下圖左側),利用thread,來改變textview的text,顯示當前時間,按下按鈕1
送出c_Handler.sendMessage(m),啟動時間,按下另一按鈕則不送出c_Handler.sendMessage(m),時間停止












package t.u;

import java.util.Calendar;
public class Clock2Activity extends Activity {
private TextView mTextView;
public Calendar c_Calendar; //日曆
public int c_Minutes; //分
public int c_Hour; //時
public int c_Second; //秒
private boolean run_clock;
public Handler c_Handler;
private Thread c_Thread;
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);

mTextView=(TextView)findViewById(R.id.textView1);
mTextView.setTextSize(30);

//hander指派工作
c_Handler =new Handler(){
public void handleMessage(Message msg){
long time=System.currentTimeMillis();
final Calendar c_Calendar = Calendar.getInstance();
c_Calendar.setTimeInMillis(time);
c_Hour=c_Calendar.get(Calendar.HOUR);
c_Minutes=c_Calendar.get(Calendar.MINUTE);
c_Second=c_Calendar.get(Calendar.SECOND);
mTextView.setText(c_Hour+":"+c_Minutes+":"+c_Second);
}
};

run_clock=false;
//產執行續物件
c_Thread = new clock_Thread();
//啟動執行續
c_Thread.start();
}
//button事件,啟動時間
public void clock(View cv) {
run_clock=true;
}//start_clock
//button事件,停止時間
public void clock_stop(View cv) {
run_clock=false;
}//stop_clock
//執行續
class clock_Thread extends Thread{
public void run(){
super.run();
try{
do{
Thread.sleep(1000);

Message m=new Message();
// 將Message物件送入MessageQueue裡
if(run_clock){
c_Handler.sendMessage(m);
}
}while(true);

}catch (Exception e) {
// TODO: handle exception
}//cttch
}//run
}//thread
}


5.main.xml

使用ECLIPSE來設計,這部份都可自動加上,上面3.事件處理有填入clock,下面xml程式會自動加入,就不用自己加

















6平板模擬器上的結果





















7.實際裝到eeepad

在project名字目錄下bin目錄,ECLIPSE已經打包好apk,只要拿到平板安裝,實際執行如下圖


read more...