2011年11月10日 星期四

Android透過activity來設定appwidget

啟動












滑鼠點擊時間,跳到設定畫面














點擊按鈕,時間變綠色



重點XML,不要設CONFIGURE(這裡是要使用者點擊appwidget來設定),xml設錯,不是桌面加不上appwidget,不然就是程式繞半天繞不出來,試很久才試出我想要的
AndroidManifest.xml中指定activity既可(如下)
<activity android:name=".clockConfigure"/>
再來建立Intent指定activity,然後綁定textview,重點就這樣

1.Clock_widget.java,注意紅色部份getActivity,setOnClickPendingIntent來綁定

 package test.Clock_widget1;

import java.util.Calendar;

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.graphics.Color;
import android.os.Bundle;
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 static int[] sappWidgetIds;
    private static AppWidgetManager sappWidgetManager;
    private static Context scontext;
    private clock_Thread cthread;
    public static String CLICK_ACTION1 ;
    public static String CLICK_ACTION2 ;
    public static String CLICK_ACTION3 ;
    static private boolean START_TIME;//是否顯示時間
    private static final int SHOW_EDITOR = 0;
    public static String ACTION_WIDGET_CONFIGURE = "ConfigureWidget";
    private PendingIntent refreshPendingIntent;
   // 建構子初始化Clock_widget,能初始化盡量初始化
 
    public  Clock_widget() {
      
        //按鈕1字串
        CLICK_ACTION1 = "test.widget_clock.CLICK1";
        //按鈕2字串
        CLICK_ACTION2 = "test.widget_clock.CLICK2";
        //按鈕2字串
                CLICK_ACTION3 = "test.widget_clock.CLICK3";
        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) {
            super.onUpdate(context, appWidgetManager, appWidgetIds);
            //onUpdate時放到全域變數
            sappWidgetManager = appWidgetManager;
            sappWidgetIds = appWidgetIds;
            scontext = context;
          
            //設定button1狀態
            this.self_update_views(scontext,sappWidgetManager,sappWidgetIds,Clock_widget.CLICK_ACTION1,R.layout.main,R.id.button1,Clock_widget.class,false);
          
            //設定button2狀態
            this.self_update_views(scontext,sappWidgetManager,sappWidgetIds,Clock_widget.CLICK_ACTION2,R.layout.main,R.id.button2,Clock_widget.class,false);
          
            //設定textview狀態
            this.self_update_views(scontext,sappWidgetManager,sappWidgetIds,"ACTION_WIDGET_CONFIGURE",R.layout.main,R.id.textView1,clockConfigure.class,true);
          
     
     
        
            //new handler,啟動service
          
            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
      
        //因為太多updateAppWidget,寫成method來處理,xid是xml的id,lid是layout中id(ex:button),as是ACTION STRING
        private void self_update_views(final Context ct,AppWidgetManager aw, int[] aids,String as,int xid,int lid,Class ac,boolean at){
          
            final Intent refreshIntent = new Intent(ct, ac);
            //set action字串
            RemoteViews updateViews = new RemoteViews( ct.getPackageName(), xid);
            refreshIntent.setAction(as);
            if(at){
                //因為要切換到Activity,PendingIntent呼叫getActivity,這裡是重點!!
                refreshPendingIntent = PendingIntent.getActivity(ct, 0,refreshIntent, PendingIntent.FLAG_UPDATE_CURRENT);
              
            }else{
                // 因為要Broadcast廣播,PendingIntent呼叫getBroadcast
                refreshPendingIntent = PendingIntent.getBroadcast(ct, 0,refreshIntent, PendingIntent.FLAG_UPDATE_CURRENT);
            }
            //final PendingIntent refreshPendingIntent = PendingIntent.getService(cc, 0,refreshIntent, 0);
          
            //設定button當使用者點擊button,然後onReceive接收作判斷,或綁定textview1,當使用者點擊textview啟動activity來改變appwidget
            updateViews.setOnClickPendingIntent(lid, refreshPendingIntent);
            //update view
            aw.updateAppWidget(aids, updateViews);
          
          
        }
      
      
      
        //取得時間,宣告成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.setTextColor(R.id.textView1, -1);
            
                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.clockConfigure.java,這裡activity只是作text顏色變換沒甚重點,要注意是clockConfigure.this.finish();讓activity還回appwidget



package test.Clock_widget1;






import android.app.Activity;
import android.appwidget.AppWidgetManager;
import android.content.ComponentName;
import android.graphics.Color;
import android.os.Bundle;
import android.view.View;
import android.widget.RemoteViews;

/**
 * @author yplin66
 *
 */
/**
 * @author yplin66
 *
 */
public class clockConfigure extends Activity {
    public static String ACTION_WIDGET_CONFIGURE = "ConfigureWidget";
     private int mAppWidgetId;
     

   @Override
        public void onCreate(Bundle savedInstanceState) {
           
       
            super.onCreate(savedInstanceState);
            setContentView(R.layout.conf);
            
           
           
           
                }
   
       
        //botton
        public void set_ok(View cv) {
           
       
    //RemoteViews views = new RemoteViews(clockConfigure.this, R.layout.main);
    RemoteViews views = new RemoteViews(getPackageName(), R.layout.main);
    ComponentName widget = new ComponentName(clockConfigure.this,Clock_widget.class);
    //Updates AppWidget state; gets information about
    //installed AppWidget providers and other AppWidget related state.
    AppWidgetManager manager = AppWidgetManager.getInstance(clockConfigure.this);
   
   
    views.setTextColor(R.id.textView1, Color.GREEN);

    manager.updateAppWidget(widget, views);
    clockConfigure.this.finish();
           
                 

        }//start_clock

}

3.AndroidManifest.xml多一行<activity android:name=".clockConfigure"/>不需要(
<action android:name="android.appwidget.action.APPWIDGET_CONFIGURE"/>)

如下

<?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>
       
          <activity android:name=".clockConfigure"/>
       
       
    </application>
</manifest>

4.clockprovider.xml(appwidget設定檔xml,並指定initialLayout)
也不需註明conigure來源
(android:configure="test.widget_clock.colockConfigure")

<?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>


5.conf.xml 設定appwidget的activity的LAYOUT(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="match_parent"
    android:orientation="vertical" >

    <Button
        android:id="@+id/button3"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:onClick="set_ok" android:text="設定綠色"/>

</LinearLayout>


6.main.xml主要viewer(讓appwidget來顯示)

<?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年11月1日 星期二

Android的thread與handler


想好幾天,想不出個所以然,今天總算試出來了

看下面程式,一直會認為當run_clock=true,Log會顯示true,當我設run_clock=false,Log應該顯示出false才對,結果Log是true,false 交互出現,在設一次run_clock=false變成true false false百思不解,亂try一通還真try出來了


 class clock_Thread extends Thread{
    public void run(){
    super.run();
    try{
    do{
    Thread.sleep(1000);

    Message m=new Message();
   
    if(run_clock){
    w_handler.sendMessage(m);
    
    Log.d("tag", "true");
    }else{
    w_handler.removeCallbacks(this);
    Log.d("tag", "false");
    }
    }while(true);

    }catch (Exception e) {
    Log.d("tag", "error");
    // TODO: handle exception
    }//cttch
    }//run
    }//thread


正確程式碼如下,當設run_clock=false在else應多寫w_handler.removeCallbacks(this),這樣才是正確讓Handler不送出message

 class clock_Thread extends Thread{
    public void run(){
    super.run();
    try{
    do{
    Thread.sleep(1000);

    Message m=new Message();
   
    if(run_clock){
    w_handler.sendMessage(m);
    
    Log.d("tag""true");
    }else{
    w_handler.removeCallbacks(this);
    Log.d("tag""false");
    }
    }while(true);

    }catch (Exception e) {
    Log.d("tag""error");
    // TODO: handle exception
    }//cttch
    }//run
    }//thread

還是不對,上面是出現error而產生的thread異常終止,不是我想要的,似乎是app widget不能讓thread改變,若是把thread在Activity則正常工作,看下面程式,當對clock_Thread使用set_start(false)是可讓時間停止,set_start(true)是可讓時間再次顯示的





package test.clock1;
import java.util.Calendar;

import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.view.View;
import android.widget.TextView;
public class Clock1Activity 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 clock_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=true;
run_clock=false;
//產執行續物件
c_Thread = new clock_Thread();
//啟動執行續
c_Thread.start();
}
//button事件,啟動時間
public void clock_start(View cv) {
c_Thread.set_start(true);

}//start_clock
//button事件,停止時間
public void clock_stop(View cv) {
c_Thread.set_start(false);
}//stop_clock
//執行續
class clock_Thread extends Thread{
boolean START=true;
public void run(){
super.run();
try{
do{
Thread.sleep(1000);
if(START){
Message m=new Message();

// 將Message物件送入MessageQueue裡
Log.d("TAG", "OK");
c_Handler.sendMessage(m);
}else{
Log.d("TAG", "NO");
}
}while(true);

}catch (Exception e) {
// TODO: handle exception
}//cttch
}//run
public void set_start(boolean b){
this.START=b;
}

}//thread
}






read more...

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...