Android 小部件上的主题
Threads on Android widget
我正在尝试制作一个小部件时钟。
在我的 MainActivity 上,使用 runOnUiThread 可以完美显示时钟。
由于小部件不扩展 "activity" 我无法运行 OnUiThread。
但是,当我尝试将 Thread 与小部件一起使用时,出现错误(或)一个空白小部件。
public class NewAppWidget extends AppWidgetProvider {
static Context cont;
static AppWidgetManager awm;
static int awid;
static Thread t;
static RemoteViews views;
static String timeText;
static String dateText;
public static Bitmap BuildUpdate(String txttime, int size,Context context){
Paint paint= new Paint();
paint.setTextSize(size);
Typeface
custTface=Typeface.createFromAsset(context.getAssets(),"fonts/Lato-Regular.ttf");
paint.setTypeface(custTface);
paint.setColor(Color.WHITE);
paint.setTextAlign(Paint.Align.LEFT);
paint.setSubpixelText(true);
paint.setAntiAlias(true);
// - in the next line is highly important.
float baseline = -paint.ascent();
int width =(int) paint.measureText(txttime+0.5f);
int height= (int) (baseline+paint.descent()+0.5f);
Bitmap image = Bitmap.createBitmap(width,height, Bitmap.Config.ARGB_8888);
Canvas canvas=new Canvas(image);
canvas.drawText(txttime,0,baseline,paint);
return image;
}
static void updateAppWidget(Context context, AppWidgetManager appWidgetManager,
int appWidgetId) {
views = new RemoteViews(context.getPackageName(), R.layout.new_app_widget);
cont=context;
awm=appWidgetManager;
awid=appWidgetId;
t = new Thread() {
@Override
public void run() {
while (!isInterrupted()){
try {
t.sleep(1000);
new Thread(new Runnable(){
@Override
public void run() {
long date = System.currentTimeMillis();
SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy");
SimpleDateFormat sdf2 = new SimpleDateFormat("hh-mm-ss a");
timeText = sdf2.format(date);
dateText = sdf.format(date);
views.setImageViewBitmap(R.id.txtTime, BuildUpdate(timeText, 100, cont));
views.setImageViewBitmap(R.id.txtDate, BuildUpdate(dateText, 25, cont));
awm.updateAppWidget(awid, views);
}
});
}catch (InterruptedException e) {
}
}
}
};
t.start();
}
这会生成一个空白小部件。
我不是要代码,只是帮我找出我的错误是什么以及我应该如何处理它?
您的 Thread
方法不起作用,因为 Android 不允许未创建 View
层次结构的 Thread
接触那些 View
。与大多数情况一样,您尝试从您的工作人员 Thread
更新的 View
很可能在 UI 线程上膨胀并实例化为您的 Activity
的一部分Android.
的创作过程
我想你有两个选择:
始终在 NewAppWidget
构造函数中传递 Activity
作为 Context
参数。
然后您可以安全地将 Context
对象转换为 Activity
并调用 Activity.runOnUiThread(Runnable)
,或者将 Context
字段更改为 Activity
以避免每次都必须投射。
使用一个Handler
。
实例化你的 Handler
如下。这将创建一个链接到 UI 线程(也称为 "main" 线程)的 Handler
对象。
Handler handler = new Handler(Looper.getMainLooper());
然后您可以使用 Handler
到 post Runnable
s,它们将在您的 UI Thread
上成为 运行工人 Thread
。您将能够通过您的工作人员 Thread
以这种方式更新 View
s:
handler.post(new Runnable() { ... });
我推荐第二种方法,因为它更简洁,而且您不会总是需要这样引用 Activity
。
请记住第二种方法,在您的 Runnable
中,您需要对要更新的 Activity
或 View
使用 WeakReference
以防止内存泄漏。即使您的 Activity
或 View
被(应该)垃圾回收了,您的工作人员 Thread
可能仍处于 运行ning 状态。使用 WeakReference
允许垃圾收集器收集你的 Activity
/ View
即使你的工人 Thread
仍然是 运行ning.
我正在尝试制作一个小部件时钟。
在我的 MainActivity 上,使用 runOnUiThread 可以完美显示时钟。
由于小部件不扩展 "activity" 我无法运行 OnUiThread。
但是,当我尝试将 Thread 与小部件一起使用时,出现错误(或)一个空白小部件。
public class NewAppWidget extends AppWidgetProvider {
static Context cont;
static AppWidgetManager awm;
static int awid;
static Thread t;
static RemoteViews views;
static String timeText;
static String dateText;
public static Bitmap BuildUpdate(String txttime, int size,Context context){
Paint paint= new Paint();
paint.setTextSize(size);
Typeface
custTface=Typeface.createFromAsset(context.getAssets(),"fonts/Lato-Regular.ttf");
paint.setTypeface(custTface);
paint.setColor(Color.WHITE);
paint.setTextAlign(Paint.Align.LEFT);
paint.setSubpixelText(true);
paint.setAntiAlias(true);
// - in the next line is highly important.
float baseline = -paint.ascent();
int width =(int) paint.measureText(txttime+0.5f);
int height= (int) (baseline+paint.descent()+0.5f);
Bitmap image = Bitmap.createBitmap(width,height, Bitmap.Config.ARGB_8888);
Canvas canvas=new Canvas(image);
canvas.drawText(txttime,0,baseline,paint);
return image;
}
static void updateAppWidget(Context context, AppWidgetManager appWidgetManager,
int appWidgetId) {
views = new RemoteViews(context.getPackageName(), R.layout.new_app_widget);
cont=context;
awm=appWidgetManager;
awid=appWidgetId;
t = new Thread() {
@Override
public void run() {
while (!isInterrupted()){
try {
t.sleep(1000);
new Thread(new Runnable(){
@Override
public void run() {
long date = System.currentTimeMillis();
SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy");
SimpleDateFormat sdf2 = new SimpleDateFormat("hh-mm-ss a");
timeText = sdf2.format(date);
dateText = sdf.format(date);
views.setImageViewBitmap(R.id.txtTime, BuildUpdate(timeText, 100, cont));
views.setImageViewBitmap(R.id.txtDate, BuildUpdate(dateText, 25, cont));
awm.updateAppWidget(awid, views);
}
});
}catch (InterruptedException e) {
}
}
}
};
t.start();
}
这会生成一个空白小部件。
我不是要代码,只是帮我找出我的错误是什么以及我应该如何处理它?
您的 Thread
方法不起作用,因为 Android 不允许未创建 View
层次结构的 Thread
接触那些 View
。与大多数情况一样,您尝试从您的工作人员 Thread
更新的 View
很可能在 UI 线程上膨胀并实例化为您的 Activity
的一部分Android.
我想你有两个选择:
始终在
NewAppWidget
构造函数中传递Activity
作为Context
参数。然后您可以安全地将
Context
对象转换为Activity
并调用Activity.runOnUiThread(Runnable)
,或者将Context
字段更改为Activity
以避免每次都必须投射。使用一个
Handler
。实例化你的
Handler
如下。这将创建一个链接到 UI 线程(也称为 "main" 线程)的Handler
对象。Handler handler = new Handler(Looper.getMainLooper());
然后您可以使用
Handler
到 postRunnable
s,它们将在您的 UIThread
上成为 运行工人Thread
。您将能够通过您的工作人员Thread
以这种方式更新View
s:handler.post(new Runnable() { ... });
我推荐第二种方法,因为它更简洁,而且您不会总是需要这样引用 Activity
。
请记住第二种方法,在您的 Runnable
中,您需要对要更新的 Activity
或 View
使用 WeakReference
以防止内存泄漏。即使您的 Activity
或 View
被(应该)垃圾回收了,您的工作人员 Thread
可能仍处于 运行ning 状态。使用 WeakReference
允许垃圾收集器收集你的 Activity
/ View
即使你的工人 Thread
仍然是 运行ning.