昨日、スマートフォンのデスクトップにカルマを表示するウィジェットであるCarmaWidgetを更新しました。 今日は、ウィジェットの作成方法について説明します。

原則は次のとおりです。
- クラス-後者がデスクトップに追加されたときに起動するウィジェットの設定。
- クラスは、すべてのタイマーが存在するウィジェットの情報プロバイダーです。
- データベース-ユーザー情報を保存します。
- ウィジェットとカスタマイザーの2つのレイアウト。
実際に行きましょう!
データベースを操作するためのクラス。
このクラスでは、列、テーブル、ベース自体のすべての名前を取得します。 テーブルを作成、削除、必要に応じてアップグレードするメソッド。 また、1つのレシーバーを実装しています。 AndroidのベースはSQLiteであるため、複数のスレッドから同じデータベースに同時に書き込むことはできません。 私はこれを回避しましたが、すべての記録呼び出しのコストがインターフェイススレッドの外部から開始されるようになりました。
クラスはDatabasHelperと呼ばれ、SQLiteOpenHelperを継承します。
すべての定数を設定します。
public static String DATABASE_NAME = "carmawidget.db"
private static int DATABASE_VERSION = 1;
public static String TABLE_NAME = "users";
public static String USERS_ID = "_id";
public static String USERS_NAME = "name";
public static String USERS_KARMA = "karma";
public static String USERS_RATE = "rate";
public static String USERS_UPDATE = "_update";
public static String USERS_ICON = "icon";
public static String USERS_ICON_URL = "icon_url";
- DATABASE_NAME-データベース名
- DATABASE_VERSION-データベースのバージョン。 この値が変更されると、onUpdate()メソッドが呼び出されます。
- TABLE_NAME-テーブル名
- USERS_ID-テーブルの最初の列。 これには、ユーザーの一意の識別子が含まれ、これは本質的にウィジェットの識別子でもあります。
- USERS_KARMA-カルマ。
- USERS_RATE-評価。
- USERS_UPDATE-更新レート。
- USERS_ICON_URL-ユーザーアイコンへのリンク。 更新時に変更される場合は、アイコン自体を更新します。
- USERS_ICON-アイコン。
伝統的に、私はかむ)
USERS_ID-ユーザーがウィジェットを追加すると、識別子がユーザーに割り当てられ、同じタイプの別のウィジェットが追加された場合、この識別子を使用して特定のウィジェットにアクセスできます。 おそらく今はまだあまり明確ではなく、もう少し詳細になります。USERS_ICONおよびUSERS_ICON_URL-カスタマイザーにチェックボックスがあります。 チェックされている場合、アイコンをロードし、ロードされていない場合は、両方の列のデータベースにNULLを入れます。 次に、更新時にデータベースUSERS_ICON_URLから読み取り、それがNULLでない場合、ユーザーは設定でそれをダウンロードすることを示し、サーバーから受信したことを確認し、一致しないかUSERS_ICONにNULLが含まれている場合、実際にアイコンを更新します。コンストラクターを定義します。
public DatabaseHelper(コンテキストコンテキスト){
super(コンテキスト、DATABASE_NAME、null、DATABASE_VERSION);
}
ベースは1つしかないので、少し簡略化しました。
テーブルを作成するSQLクエリを生成するメソッドを作成しています。
プライベート文字列usersCreate()
{
StringBuilder result = new StringBuilder( "CREATE TABLE");
result.append(TABLE_NAME);
result.append( "(");
result.append(USERS_ID);
result.append( "INTEGER PRIMARY KEY、");
result.append(USERS_NAME);
result.append( "TEXT NOT NULL、");
result.append(USERS_KARMA);
result.append( "TEXT DEFAULT '0,00'、");
result.append(USERS_RATE);
result.append( "TEXT DEFAULT '0,00'、");
result.append(USERS_ICON_URL);
result.append( "TEXT、");
result.append(USERS_UPDATE);
result.append( "INTEGER DEFAULT '0'、");
result.append(USERS_ICON);
result.append( "BLOB);");
return result.toString();
}
ベースを作成するメソッド。
@Override
public void onCreate(SQLiteDatabase db){
db.execSQL(usersCreate());
}
テーブルのバージョンが変更されたときに呼び出されるonUpgradeメソッド。
@Override
public void onUpgrade(SQLiteDatabase db、int oldVersion、int newVersion){
db.execSQL( "DROP TABLE IF EXISTS" + TABLE_NAME);
onCreate(db);
}
たとえば、開発プロセス中に、列を追加する必要がありました。 リクエストジェネレータを修正し、バージョンを増やします。 ベースが新たに作成されます。 しかし、これが最も簡単な方法です。良い方法では、削除せずに追加する必要があります。書き込むベースを返すメソッド。
@Override
パブリックSQLiteDatabase getWritableDatabase()
{
SQLiteDatabase db = null;
while(db == null)
{
試してみる
{
db = super.getWritableDatabase();
}
catch(SQLiteException e)
{
{
Thread.sleep(500);
} catch(InterruptedException e1){
}
}
}
return db;
すぐに予約しますが、解決策は正しくないかもしれませんが、うまくいくようです。 記録にアクセスする方法がない場合は、0.5秒待ってから再試行します。Habraサーバーを操作するためのクラスを作成します。
定数を設定します
private static String USER_URL = "http:// <ユーザー名> .habrahabr.ru /";
private static String API_URL = "http://habrahabr.ru/api/profile/";
public static String RESULT_OK = "ok";
public static String RESULT_SERVER = "server";
public static String RESULT_USER_NOT_FOUND = "not_found";
public static String RESULT_NETWORK = "network";
public static String RESULT_NO_USERPIC = "http://habrahabr.ru/i/avatars/stub-user-middle.gif";
RESULT_NO_USERPIC-これは、ハブの「アバターなし」アイコンへのリンクです。カルマと評価を取得する方法。
public String [] getStats(String username)
{
String [] result = new String [] {"0.00"、 "0.00"、RESULT_OK};
文字列url = API_URL + Uri.encode(ユーザー名);
文字列proxyHost = android.net.Proxy.getDefaultHost();
int proxyPort = android.net.Proxy.getDefaultPort();
HttpClient httpClient = new DefaultHttpClient();
if(proxyPort> 0)
{
HttpHost proxy = new HttpHost(proxyHost、proxyPort);
httpClient.getParams()。setParameter(ConnRoutePNames.DEFAULT_PROXY、プロキシ);
}
HttpGet httpGet = new HttpGet(url);
{
HttpResponse response = httpClient.execute(httpGet);
if(response.getStatusLine()。getStatusCode()== HttpStatus.SC_OK)
{
BufferedReader reader =新しいBufferedReader(新しいInputStreamReader(response.getEntity()。GetContent()));
StringBuilder sb = new StringBuilder();
文字列line = null;
while((line = reader.readLine())!= null){
sb.append(line + System.getProperty( "line.separator"));
}
文字列answerInputString = sb.toString();
if(answerInputString.contains( "<habrauser>"))
{
if(answerInputString.contains( "<error> 404 </ error>"))
{
結果[2] = RESULT_USER_NOT_FOUND;
}
他に
{
result [0] = answerInputString.substring(answerInputString.indexOf( "<karma>")+ "<karma>" .length()、answerInputString.indexOf( "</ karma>"));
result [1] = answerInputString.substring(answerInputString.indexOf( "<rating>")+ "<rating>" .length()、answerInputString.indexOf( "</ rating>"));
結果[0] =フォーマッタ(結果[0]);
結果[1] =フォーマッタ(結果[1]);
}
}
他に
{
結果[2] = RESULT_SERVER;
}
}
他に
{
結果[2] = RESULT_SERVER;
}
} catch(例外e){
結果[2] = RESULT_NETWORK;
}
結果を返す;
}
result-メソッドの出力値、3行の配列。1行目はカルマ、2行目は評価、3行目はエラーメッセージです。Habraのapiはカルマと評価、たとえば12を返すことができるので、フォーム12.00に持ってくる必要があります。
プライベート文字列フォーマッタ(文字列文字列)
{
string = string.replace( "。"、 "、");
if(!string.contains( "、"))
{
string = string + "、00";
}
for(int i = 0; i <2-string.split( "、")[1] .length(); i ++)
{
string = string + "0";
}
戻り文字列。
}
リンクアイコンを取得します。 APIにはこれがありません。ユーザープロファイルを解析する必要があります。
public String getUserpicUrl(ストリングユーザー名)
{
文字列の結果= "";
結果= RESULT_NO_USERPIC;
文字列url = USER_URL.replace( "<ユーザー名>"、ユーザー名);
文字列proxyHost = android.net.Proxy.getDefaultHost();
int proxyPort = android.net.Proxy.getDefaultPort();
HttpClient httpClient = new DefaultHttpClient();
if(proxyPort> 0)
{
HttpHost proxy = new HttpHost(proxyHost、proxyPort);
httpClient.getParams()。setParameter(ConnRoutePNames.DEFAULT_PROXY、プロキシ);
}
HttpGet httpGet = new HttpGet(url);
{
HttpResponse response = httpClient.execute(httpGet);
if(response.getStatusLine()。getStatusCode()== HttpStatus.SC_OK)
{
BufferedReader reader =新しいBufferedReader(新しいInputStreamReader(response.getEntity()。GetContent()));
StringBuilder sb = new StringBuilder();
文字列line = null;
while((line = reader.readLine())!= null){
sb.append(line + System.getProperty( "line.separator"));
}
文字列の答え= sb.toString();
結果= RESULT_NO_USERPIC;
answer = answer.substring(answer.indexOf( "<h1 class = \" habrauserava \ ">"));
answer = answer.substring(answer.indexOf( "<img src = \" ")+" <img src = \ ""。length()、answer.indexOf( "\" alt "));
結果=回答;
}
} catch(例外e)
{
}
結果を返す;
}
そして実際にアイコンをロードします。
パブリックビットマップimageDownloader(文字列url)
{
ビットマップ結果= null;
文字列proxyHost = android.net.Proxy.getDefaultHost();
int proxyPort = android.net.Proxy.getDefaultPort();
{
URL bitmapUrl =新しいURL(url);
HttpURLConnection接続。
if(proxyPort> 0)
{
InetSocketAddress proxyAddr =新しいInetSocketAddress(proxyHost、proxyPort);
プロキシproxy = new Proxy(Proxy.Type.HTTP、proxyAddr);
connection =(HttpURLConnection)bitmapUrl.openConnection(プロキシ);
}
他に
{
connection =(HttpURLConnection)bitmapUrl.openConnection();
}
connection.setDoInput(true);
connection.connect();
InputStream inputStream = connection.getInputStream();
result = BitmapFactory.decodeStream(inputStream);
}
catch(例外e)
{
}
結果を返す;
}
ウィジェットカスタマイザー

Configクラスは通常のアクティビティですが、作業の結果をウィジェットに返す必要があります。 つまり、ウィジェットを追加するためにクリックすると、このカスタマイザーが表示され、正しく機能した場合、結果を肯定として設定し、たとえば、ユーザーが見つかった場合、これについて通知し、ユーザーは再試行または閉じる。 したがって、データ入力が成功せずに終了すると、結果がキャンセルされたと設定されます。 実際には少し低くなります。
パブリッククラスConfigはActivity {を拡張します
/ **アクティビティが最初に作成されたときに呼び出されます。 * /
コンテキストコンテキスト。
Thread updaterThread = new Thread();
ProgressDialog progressDialog;
@Override
public void onCreate(バンドルsavedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
コンテキスト=これ;
setResult(RESULT_CANCELED);
progressDialog = new ProgressDialog(this);
progressDialog.setMessage(getApplicationContext()。getResources()。getString(R.string.loading));
ボタン準備完了=(ボタン)findViewById(R.id.submit);
ready.setOnClickListener(新しいOnClickListener(){
@Override
public void onClick(View v){
// TODO自動生成メソッドスタブ
if(updaterThread.getState()== State.NEW || updaterThread.getState()== State.TERMINATED)
{
updaterThread = new Thread(アップデーター);
updaterThread.start();
progressDialog.show();
}
}
});
}
}
インターフェイスを公開し、[完了]ボタンをクリックするためのハンドラーを記述します。 setResult(RESULT_CANCELLED)-アクションの結果をキャンセル済みとして最初に設定するだけです。 すべてがうまくいけば、それを変更します。ここにRunnable updaterを追加します-初期データのロードが行われる別のストリーム。
Runnable updater = new Runnable(){@Override public void run(){// TODO Auto-generated method stub String username =((EditText)findViewById(R.id.username))。GetText().ToString(); int update =((Spinner)findViewById(R.id.update_value))。getSelectedItemPosition(); boolean picupdate =((CheckBox)findViewById(R.id.load_pic))。isChecked(); 文字列[]値=新しいHabrahabrAPI()。GetStats(ユーザー名); if(値[2] .equals(HabrahabrAPI.RESULT_OK)){Intent intent = getIntent(); if(intent.getExtras()!= null){int appWidgetId = intent.getExtras()。getInt(AppWidgetManager.EXTRA_APPWIDGET_ID、AppWidgetManager.INVALID_APPWIDGET_ID); if(appWidgetId!= AppWidgetManager.INVALID_APPWIDGET_ID){ContentValues contentValues = new ContentValues(); contentValues.put(DatabaseHelper.USERS_ID、appWidgetId); contentValues.put(DatabaseHelper.USERS_NAME、ユーザー名); contentValues.put(DatabaseHelper.USERS_KARMA、値[0]); contentValues.put(DatabaseHelper.USERS_RATE、値[1]); contentValues.put(DatabaseHelper.USERS_UPDATE、更新); AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(getApplicationContext()); RemoteViewsビュー=新しいRemoteViews(getApplicationContext()。GetPackageName()、R.layout.widget); if(picupdate == true){String icon = new HabrahabrAPI()。getUserpicUrl(username); contentValues.put(DatabaseHelper.USERS_ICON_URL、アイコン); if(!icon.equals(HabrahabrAPI.RESULT_NO_USERPIC)){Bitmap userpic = new HabrahabrAPI()。imageDownloader(icon); if(userpic!= null){ByteArrayOutputStream baos = new ByteArrayOutputStream(); userpic.compress(Bitmap.CompressFormat.PNG、100、baos); contentValues.put(DatabaseHelper.USERS_ICON、baos.toByteArray()); views.setBitmap(R.id.icon、 "setImageBitmap"、userpic); }} else {views.setBitmap(R.id.icon、 "setImageBitmap"、BitmapFactory.decodeResource(getApplicationContext()。getResources()、R.drawable.userpic)); ByteArrayOutputStream baos = new ByteArrayOutputStream(); BitmapFactory.decodeResource(getApplicationContext()。GetResources()、R.drawable.userpic).compress(Bitmap.CompressFormat.PNG、100、baos); contentValues.put(DatabaseHelper.USERS_ICON、baos.toByteArray()); }} else {contentValues.putNull(DatabaseHelper.USERS_ICON); contentValues.putNull(DatabaseHelper.USERS_ICON_URL); } SQLiteDatabase db = new DatabaseHelper(getApplicationContext())。GetWritableDatabase(); db.insert(DatabaseHelper.TABLE_NAME、null、contentValues); db.close(); contentValues.clear(); views.setTextViewText(R.id.karma、値[0]); views.setTextViewText(R.id.rating、値[1]); appWidgetManager.updateAppWidget(appWidgetId、ビュー); Intent resultValue = new Intent(); resultValue.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID、appWidgetId); setResult(RESULT_OK、resultValue); インテントupdaterIntent = new Intent(); updaterIntent.setAction(AppWidgetManager.ACTION_APPWIDGET_UPDATE); updaterIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS、新しいint [] {appWidgetId}); updaterIntent.setData(Uri.withAppendedPath(Uri.parse(Widget.URI_SCHEME + ":// widget / id /")、String.valueOf(appWidgetId))); PendingIntent pendingIntent = PendingIntent.getBroadcast(getApplicationContext()、0、updaterIntent、PendingIntent.FLAG_UPDATE_CURRENT); AlarmManager alarmManager =(AlarmManager)getApplicationContext()。GetSystemService(Context.ALARM_SERVICE); alarmManager.setRepeating(AlarmManager.ELAPSED_REALTIME、SystemClock.elapsedRealtime()+(Widget.updatePeriodsMinutes [更新] * 60000)、Widget.updatePeriodsMinutes [更新] * 60000、pendingIntent); }}} Bundle data = new Bundle(); data.putString( "RESULT"、値[2]); メッセージmessage = new Message(); message.setData(データ); handler.sendMessage(メッセージ); }};
まず、インターフェイス要素から入力を取得します。 そして、%username%のカルマをロードします。 次に、インテントからウィジェット識別子を取得します。 結果をデータベースに入れるために、ContentValuesクラスの変数を作成します。 次に、RemoteViewsを使用して、ウィジェットビューを更新します。ウィジェットビューの構成を行い、この内容をデータベースに配置します。 最後に、更新を行うIntent updaterIntentを作成します。 Androidは、setData(Uri)データをこのインテントに追加しなかった場合、そのようなインテントが既に存在していると見なし、それを再び使用するように機能します。 setDataは一意になるようにのみ作成されます。
AlarmManagerを使用して、次の更新の時間を設定します。 一般に、devGuideは、ウィジェットプロバイダーの説明を通じて更新時間を使用するように指示します。詳細については、以下を参照してください。 ただし、これにより、異なる更新時間を設定することはできません。 TimerTaskを使用できますが、画面をオンにすると、デバイスの電源がオフになっている間にすぐに更新が開始されます。 この点で、AlarmManagerは非常に便利です。デバイスが停止している間は更新されませんが、この間に少なくとも1つの更新が行われた場合、起動後に1回呼び出されます。
この実行可能ファイルの最後に、結果を処理するハンドラーを呼び出して、エラーメッセージを含むgetStats(username)メソッドから3行目を渡します。結果ハンドラ。
Handler handler = new Handler(){
@Override
public void handleMessage(メッセージメッセージ)
{
progressDialog.dismiss();
AlertDialog.Builder builder = new AlertDialog.Builder(コンテキスト);
builder.setIcon(android.R.drawable.ic_dialog_alert);
builder.setPositiveButton(R.string.ok、新しいDialogInterface.OnClickListener(){
@Override
public void onClick(DialogInterfaceダイアログ、int which){
// TODO自動生成メソッドスタブ
dialog.dismiss();
}
});
String result = message.getData()。GetString( "RESULT");
if(result.equals(HabrahabrAPI.RESULT_NETWORK))
{
builder.setTitle(R.string.error_network);
builder.setMessage(R.string.try_later);
}
if(result.equals(HabrahabrAPI.RESULT_USER_NOT_FOUND))
{
builder.setTitle(R.string.error_user);
builder.setMessage(R.string.try_user);
}
if(result.equals(HabrahabrAPI.RESULT_SERVER))
{
builder.setTitle(R.string.error_server);
builder.setMessage(R.string.try_later);
}
if(result.equals(HabrahabrAPI.RESULT_OK))
{
終了();
}
他に
{
builder.show();
}
}
};
この結果に応じて、対応するメッセージを発行しますが、結果がRESULT_OKの場合、API habrを使用してクラスに設定し、このアクティビティのみを閉じます。AppWidgetProvider
ウィジェットが更新されるメインクラス。
定数を設定します:
public static int [] updatePeriodsMinutes = new int [] {30、60、180、360、720};
public static String URI_SCHEME = "karma_widget";
この場合の配列には、ConfigクラスのSpinnerViewの分が含まれています。 AlarmManagerのスピナーのテキスト値をミリ秒に変換するために必要です。 Configでは、選択したアイテムのインデックスを取得し、データベースに配置します。 プロバイダーでは、ベースからのインデックスを持つ配列から要素を取得し、それを60,000倍します。ミリ秒を取得します。OnEnabled()メソッド
@Override
public void onEnabled(コンテキストコンテキスト)
{
SQLiteDatabase db = new DatabaseHelper(コンテキスト).getReadableDatabase();
Cursor cursor = db.query(DatabaseHelper.TABLE_NAME、new String [] {DatabaseHelper.USERS_ID、DatabaseHelper.USERS_KARMA、DatabaseHelper.USERS_RATE、DatabaseHelper.USERS_UPDATE、DatabaseHelper.USERS_ICON}、null、null、null、null、null、null、null、null、null、null、null、null
while(cursor.moveToNext())
{
RemoteViewsビュー=新しいRemoteViews(context.getPackageName()、R.layout.widget);
int id = cursor.getInt(cursor.getColumnIndex(DatabaseHelper.USERS_ID));
文字列karma = cursor.getString(cursor.getColumnIndex(DatabaseHelper.USERS_KARMA));
文字列率= cursor.getString(cursor.getColumnIndex(DatabaseHelper.USERS_RATE));
バイト[]アイコン= cursor.getBlob(cursor.getColumnIndex(DatabaseHelper.USERS_ICON));
int update = cursor.getInt(cursor.getColumnIndex(DatabaseHelper.USERS_UPDATE));
views.setTextViewText(R.id.karma、karma);
views.setTextViewText(R.id.rating、rate);
if(アイコン== null)
{
views.setBitmap(R.id.icon、 "setImageBitmap"、BitmapFactory.decodeResource(context.getResources()、R.drawable.userpic));
}
他に
{
views.setBitmap(R.id.icon、 "setImageBitmap"、BitmapFactory.decodeByteArray(icon、0、icon.length));
}
AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(コンテキスト);
appWidgetManager.updateAppWidget(id、views);
インテントupdaterIntent = new Intent();
updaterIntent.setAction(AppWidgetManager.ACTION_APPWIDGET_UPDATE);
updaterIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS、新しいint [] {id});
updaterIntent.setData(Uri.withAppendedPath(Uri.parse(URI_SCHEME + ":// widget / id /")、String.valueOf(id)));
PendingIntent pendingIntent = PendingIntent.getBroadcast(context、0、updaterIntent、PendingIntent.FLAG_UPDATE_CURRENT);
AlarmManager alarmManager =(AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
alarmManager.setRepeating(AlarmManager.ELAPSED_REALTIME、SystemClock.elapsedRealtime()、updatePeriodsMinutes [update] * 60000、pendingIntent);
}
cursor.close();
db.close();
super.onEnabled(コンテキスト);
}
一般に、このプロバイダーの開始時に一度呼び出されます。 既存の要素のすべてのタイマーはここで設定されます。 たとえば、ウィジェットをインストールしたばかりです。 メソッドは呼び出されますが、データベースが空なので、何も開始されません。 しかし、電話を再起動するときに、彼はこのメソッドを呼び出し、要素があれば、更新のためのタイマーを開始し、データベースの過去の値に設定します。OnDeleted()メソッド
@Override
public void onDeleted(Context ctxt、int [] id)
{
final int [] appWidgetIds = ids;
最終コンテキストcontext = ctxt;
新しいスレッド(新しいRunnable(){
@Override
public void run(){
for(int i = 0; i <appWidgetIds.length; i ++)
{
意図の意図=新しい意図();
intent.setAction(AppWidgetManager.ACTION_APPWIDGET_UPDATE);
intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS、新しいint [] {appWidgetIds [i]});
intent.setData(Uri.withAppendedPath(Uri.parse(URI_SCHEME + ":// widget / id /")、String.valueOf(appWidgetIds [i])));
PendingIntent pendingIntent = PendingIntent.getBroadcast(context、0、intent、PendingIntent.FLAG_UPDATE_CURRENT);
AlarmManager alarmManager =(AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
alarmManager.cancel(pendingIntent);
SQLiteDatabase db = new DatabaseHelper(コンテキスト).getWritableDatabase();
db.delete(DatabaseHelper.TABLE_NAME、DatabaseHelper.USERS_ID + "=" + appWidgetIds [i]、null);
db.close();
}
}
})。start();
super.onDeleted(ctxt、ids);
}
デスクトップからウィジェットを削除するときに呼び出されます。 さて、ここでタイマーを停止し、データベースから削除します。OnUpdate()メソッド
@Override
public void onUpdate(コンテキストctxt、AppWidgetManager mgr、int [] appWidgetIds)
{
最終コンテキストcontext = ctxt;
最終AppWidgetManager appWidgetManager = mgr;
final int [] ids = appWidgetIds;
新しいスレッド(新しいRunnable(){
@Override
public void run(){
// TODO自動生成メソッドスタブ
for(int i = 0; i <ids.length; i ++)
{
appWidgetManager.updateAppWidget(ids [i]、buildUpdate(context、ids [i]));
}
}
})。start();
super.onUpdate(ctxt、mgr、appWidgetIds);
}
AlarmManagerは、更新が必要なときにこのメソッドを呼び出します。BuildUpdate()メソッド
パブリックRemoteViews buildUpdate(コンテキストコンテキスト、int id)
{
RemoteViewsビュー=新しいRemoteViews(context.getPackageName()、R.layout.widget);
SQLiteDatabase db = new DatabaseHelper(コンテキスト).getReadableDatabase();
カーソルcursor = db.query(DatabaseHelper.TABLE_NAME、新しい文字列[] {DatabaseHelper.USERS_ID、DatabaseHelper.USERS_KARMA、DatabaseHelper.USERS_RATE、DatabaseHelper.USERS_ICON、DatabaseHelper.USERS_ICON_URL、DatabaseHelper.USERS_NAME_ + +}} .valueOf(id)、null、null、null、null);
if(cursor.getCount()!= 0)
{
ContentValues contentValues =新しいContentValues();
cursor.moveToFirst();
String username = cursor.getString(cursor.getColumnIndex(DatabaseHelper.USERS_NAME));
文字列karma = cursor.getString(cursor.getColumnIndex(DatabaseHelper.USERS_KARMA));
文字列率= cursor.getString(cursor.getColumnIndex(DatabaseHelper.USERS_RATE));
文字列icon_url = cursor.getString(cursor.getColumnIndex(DatabaseHelper.USERS_ICON_URL));
バイト[]アイコン= cursor.getBlob(cursor.getColumnIndex(DatabaseHelper.USERS_ICON));
文字列[]更新=新しいHabrahabrAPI()。GetStats(ユーザー名);
if([2] .equals(HabrahabrAPI.RESULT_OK)を更新)
{
if(!更新[0] .equals(karma)||!更新[1] .equals(rate))
{
karma =更新[0];
レート=更新[1];
contentValues.put(DatabaseHelper.USERS_KARMA、karma);
contentValues.put(DatabaseHelper.USERS_RATE、率);
}
}
views.setTextViewText(R.id.karma、karma);
views.setTextViewText(R.id.rating、rate);
if(icon_url!= null)
{
文字列updatedIconUrl = new HabrahabrAPI()。GetUserpicUrl(ユーザー名);
if((icon == null ||!icon_url.equals(updatedIconUrl))&&!updatedIconUrl.equals(HabrahabrAPI.RESULT_NO_USERPIC))
{
icon_url = updatedIconUrl;
Log.d(「CarmaWidget」、「Downloaded new userpic」);
ビットマップiconBitmap =新しいHabrahabrAPI()。ImageDownloader(icon_url);
if(iconBitmap!= null)
{
ByteArrayOutputStream baos = new ByteArrayOutputStream();
iconBitmap.compress(CompressFormat.PNG、100、baos);
icon = baos.toByteArray();
contentValues.put(DatabaseHelper.USERS_ICON_URL、icon_url);
contentValues.put(DatabaseHelper.USERS_ICON、アイコン);
views.setBitmap(R.id.icon、 "setImageBitmap"、iconBitmap);
}
}
}
他に
{
if(アイコン== null)
{
views.setBitmap(R.id.icon、 "setImageBitmap"、BitmapFactory.decodeResource(context.getResources()、R.drawable.userpic));
}
他に
{
views.setBitmap(R.id.icon、 "setImageBitmap"、BitmapFactory.decodeByteArray(icon、0、icon.length));
}
}
cursor.close();
db.close();
if(contentValues.size()!= 0)
{
db = new DatabaseHelper(context).getWritableDatabase();
db.update(DatabaseHelper.TABLE_NAME、contentValues、DatabaseHelper.USERS_ID + "=" + String.valueOf(id)、null);
db.close();
}
}
他に
{
cursor.close();
db.close();
}
ビューを返す;
}
更新が行われる場所であり、Configクラスの更新に非常に似ています次に、ウィジェットのカスタマイザー、幅、高さ、レイアウトを設定する必要があります。 これを行うには、res / xmlフォルダーで、次の形式のxmlファイルを作成します。
<?xml version = "1.0" encoding = "utf-8"?>
<appwidget-provider xmlns:android = "http://schemas.android.com/apk/res/android"
android:initialLayout = "@ layout / widget"
android:minHeight = "72dp"
android:minWidth = "146dp"
android:configure = "com.nixan.carmawidget.Config" />
これに更新時間を追加できますが、繰り返しますが、すべてのウィジェットで同じになります。最後に-AndroidManifest.xmlを編集します
<?xml version = "1.0" encoding = "utf-8"?>
<マニフェストxmlns:android = "http://schemas.android.com/apk/res/android"
パッケージ= "com.nixan.carmawidget"
android:versionCode = "3"
android:versionName = "1.2">
<application android:icon = "@ drawable / icon" android:label = "@ string / app_name" android:theme = "@ android:style / Theme.Light">
<アクティビティandroid:name = "。Config" android:screenOrientation = "portrait">
<intent-filter>
<action android:name = "android.appwidget.action.APPWIDGET_CONFIGURE" />
</ intent-filter>
</アクティビティ>
<receiver android:name = "。Widget"
android:label = "@ string / app_name">
<intent-filter>
<action android:name = "android.appwidget.action.APPWIDGET_UPDATE" />
</ intent-filter>
<meta-data android:name = "android.appwidget.provider" android:resource = "@ xml / carmawidget_provider" />
</ receiver>
<receiver android:name = "。Widget"
android:label = "@ string / app_name">
<intent-filter>
<action android:name = "android.appwidget.action.APPWIDGET_UPDATE" />
<data android:scheme = "karma_widget" />
</ intent-filter>
<meta-data android:name = "android.appwidget.provider" android:resource = "@ xml / carmawidget_provider" />
</ receiver>
</ application>
<uses-sdk android:minSdkVersion = "3" />
<uses-permission android:name = "android.permission.INTERNET" />
</ manifest>
インターフェースの設計はソースにあります。何か明確でない場合は、
ここと
ここを読むことができ
ますソースのダウンロード(172 Kb)アプリケーションのダウンロード(51 Kb)またはパブ市場:nixan
ご清聴ありがとうございました)