Android小部件上的线程

Posted

技术标签:

【中文标题】Android小部件上的线程【英文标题】:Threads on Android widget 【发布时间】:2018-09-06 04:55:57 【问题描述】:

我正在尝试制作一个小部件时钟。

在我的 MainActivity 上,时钟使用 runOnUiThread 完美显示。 由于小部件不扩展“活动”,我无法运行 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();

这会产生一个空白小部件。

我不是要代码,只是帮我找出我在这里的错误以及我应该如何处理?

【问题讨论】:

【参考方案1】:

您的Thread 方法不起作用,因为android 不允许未创建View 层次结构的Threads 接触那些Views。与大多数情况一样,您尝试从工作人员 Thread 更新的 View 很可能在 Android 的 Activity 创建过程中在 UI 线程上被夸大和实例化。

我认为你有两个选择:

    始终将Activity 作为Context 参数传递给NewAppWidget 构造函数。

    然后您可以安全地将Context 对象转换为Activity 并调用Activity.runOnUiThread(Runnable),或者将Context 字段更改为Activity,以避免每次都进行转换。

    使用Handler

    如下实例化您的Handler。这将创建一个链接到 UI 线程(也称为“主”线程)的 Handler 对象。

    Handler handler = new Handler(Looper.getMainLooper());

    然后,您可以使用 Handler 发布 Runnables,然后您的工作人员 Thread 在 UI Thread 上运行。您可以通过这种方式从您的工作人员Thread 更新Views:

    handler.post(new Runnable() ... );

我推荐第二种方法,因为它更简洁,而且您不需要通过这种方式引用 Activity

请记住第二种方法,在您的Runnable 中,您需要将WeakReference 用于您想要更新的ActivityView,以防止内存泄漏。即使您的ActivityView 被(应该)垃圾收集,您的工作人员Thread 可能仍在运行。使用WeakReference 允许垃圾收集器收集您的Activity / View,即使您的工作人员Thread 仍在运行。

【讨论】:

这有帮助。谢谢!

以上是关于Android小部件上的线程的主要内容,如果未能解决你的问题,请参考以下文章

点击事件上的android小部件

Qt5:Android 上的原生外观小部件

单击android小部件按钮上的侦听器

Android 小部件:RemoteViews 上的动画? [复制]

使用 Android 小部件

如何在android编程中获取放置在小部件上的textview文本