Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/android/226.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何保存和恢复AndroidWidgetHostView_Android_Widget_Launcher - Fatal编程技术网

如何保存和恢复AndroidWidgetHostView

如何保存和恢复AndroidWidgetHostView,android,widget,launcher,Android,Widget,Launcher,我正在尝试构建一个定制的启动器应用程序。当活动重新启动时,我一直在恢复小部件 在选择一个小部件后,widgetID被存储到共享的prefs中,在onCreate中,我试图恢复以前设置的小部件。我在学习教程 AppWidgetManager mAppWidgetManager; AppWidgetHost mAppWidgetHost; ViewGroup hostView; int numWidgets = 0; /** * Called on the creation of the

我正在尝试构建一个定制的启动器应用程序。当活动重新启动时,我一直在恢复小部件

在选择一个小部件后,widgetID被存储到共享的prefs中,在onCreate中,我试图恢复以前设置的小部件。我在学习教程

  AppWidgetManager mAppWidgetManager;
AppWidgetHost mAppWidgetHost;
ViewGroup hostView;
int numWidgets = 0;


/**
 * Called on the creation of the activity.
 */
@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_dashboard);

    hostView = (ViewGroup) findViewById(R.id.LAYOUT_DASHBOARD);

    hostView.setOnLongClickListener(new View.OnLongClickListener() {
        @Override
        public boolean onLongClick(View view) {
           if(numWidgets < 4) {
               selectWidget();
           }else {
               removeAllWidgets();
               numWidgets = 0;
           }
            return false;
        }
    });

    mAppWidgetManager = AppWidgetManager.getInstance(this);
    mAppWidgetHost = new AppWidgetHost(this, R.id.APPWIDGET_HOST_ID);



    restoreWidgets();
}

/**
 * Launches the menu to select the widget. The selected widget will be on
 * the result of the activity.
 */
void selectWidget() {
    int appWidgetId = this.mAppWidgetHost.allocateAppWidgetId();
    Intent pickIntent = new Intent(AppWidgetManager.ACTION_APPWIDGET_PICK);
    pickIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
    addEmptyData(pickIntent);
    startActivityForResult(pickIntent, R.id.REQUEST_PICK_APPWIDGET);
}

/**
 * This avoids a bug in the com.android.settings.AppWidgetPickActivity,
 * which is used to select widgets. This just adds empty extras to the
 * intent, avoiding the bug.
 *
 * See more: http://code.google.com/p/android/issues/detail?id=4272
 */
void addEmptyData(Intent pickIntent) {
    ArrayList<AppWidgetProviderInfo> customInfo = new ArrayList<AppWidgetProviderInfo>();
    pickIntent.putParcelableArrayListExtra(AppWidgetManager.EXTRA_CUSTOM_INFO, customInfo);
    ArrayList<Bundle> customExtras = new ArrayList<Bundle>();
    pickIntent.putParcelableArrayListExtra(AppWidgetManager.EXTRA_CUSTOM_EXTRAS, customExtras);
}

/**
 * If the user has selected an widget, the result will be in the 'data' when
 * this function is called.
 */
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    if (resultCode == RESULT_OK) {
        if (requestCode == R.id.REQUEST_PICK_APPWIDGET) {
            configureWidget(data);
        } else if (requestCode == R.id.REQUEST_CREATE_APPWIDGET) {
            createWidget(data);
        }
    } else if (resultCode == RESULT_CANCELED && data != null) {
        int appWidgetId = data.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, -1);
        if (appWidgetId != -1) {
            mAppWidgetHost.deleteAppWidgetId(appWidgetId);
        }
    }
}

/**
 * Checks if the widget needs any configuration. If it needs, launches the
 * configuration activity.
 */
private void configureWidget(Intent data) {
    Bundle extras = data.getExtras();
    int appWidgetId = extras.getInt(AppWidgetManager.EXTRA_APPWIDGET_ID, -1);
    AppWidgetProviderInfo appWidgetInfo = mAppWidgetManager.getAppWidgetInfo(appWidgetId);
    if (appWidgetInfo.configure != null) {
        Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_CONFIGURE);
        intent.setComponent(appWidgetInfo.configure);
        intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
        startActivityForResult(intent, R.id.REQUEST_CREATE_APPWIDGET);
    } else {
        createWidget(data);
    }
}

/**
 * Creates the widget and adds to our view layout.
 */
public void createWidget(Intent data) {
    if(numWidgets<4) {
        Bundle extras = data.getExtras();
        int appWidgetId = extras.getInt(AppWidgetManager.EXTRA_APPWIDGET_ID, -1);

        AppWidgetProviderInfo appWidgetInfo = mAppWidgetManager.getAppWidgetInfo(appWidgetId);
        AppWidgetHostView widHostView = mAppWidgetHost.createView(this, appWidgetId, appWidgetInfo);
        widHostView.setAppWidget(appWidgetId, appWidgetInfo);

        SharedPreferences sharedPref = this.getPreferences(Context.MODE_PRIVATE);
        SharedPreferences.Editor editor = sharedPref.edit();
        editor.putInt("ID"+numWidgets, appWidgetId);

        editor.commit();
        attachWidget(widHostView);

    }
}

/**
 * Attaches a new widget at the right position on hostView
 * @param widHostView   widget to attach
 */
public void attachWidget(AppWidgetHostView widHostView){
    RelativeLayout.LayoutParams lp = new RelativeLayout.LayoutParams(hostView.getWidth() / 2, hostView.getHeight() / 2);
    if (numWidgets < 2) {
        lp.leftMargin = numWidgets * (hostView.getWidth() / 2);
        lp.topMargin = 0;
    } else {
        lp.leftMargin = (numWidgets - 2) * (hostView.getWidth() / 2);
        lp.topMargin = hostView.getHeight() / 2;
    }

    this.hostView.addView(widHostView, lp);
    numWidgets++;
}

/**
 * Restores all widgets from shared preferences
 */
public void restoreWidgets()
{
    SharedPreferences sharedPref = this.getPreferences(Context.MODE_PRIVATE);
    restoreWidget(sharedPref.getInt("ID0", -1));
    restoreWidget(sharedPref.getInt("ID1", -1));
    restoreWidget(sharedPref.getInt("ID2", -1));
    restoreWidget(sharedPref.getInt("ID3", -1));
}

/**
 * Restores a single widget
 */
public void restoreWidget(int _widgetId){
    if(_widgetId < 0){
        return;
    }
    AppWidgetProviderInfo appWidgetInfo = mAppWidgetManager.getAppWidgetInfo(_widgetId);
    AppWidgetHostView hostView = mAppWidgetHost.createView(this, _widgetId, appWidgetInfo);
    hostView.setAppWidget(_widgetId, appWidgetInfo);
    attachWidget(hostView);
}

/**
 * Registers the AppWidgetHost to listen for updates to any widgets this app
 * has.
 */
@Override
protected void onStart() {
    super.onStart();
    mAppWidgetHost.startListening();
}

/**
 * Stop listen for updates for our widgets (saving battery).
 */
@Override
protected void onStop() {
    super.onStop();
    mAppWidgetHost.stopListening();
}

/**
 * Removes the widget displayed by this AppWidgetHostView.
 */
public void removeWidget(AppWidgetHostView hostView) {
    mAppWidgetHost.deleteAppWidgetId(hostView.getAppWidgetId());
    this.hostView.removeView(hostView);
}

/**
 * Removes all widgets displayed on screen.
 */
public void removeAllWidgets(){
   boolean stop = false;
    do{
        int childCount = hostView.getChildCount();
        if (childCount >= 1) {
            View view = hostView.getChildAt(childCount - 1);
            if (view instanceof AppWidgetHostView) {
                removeWidget((AppWidgetHostView) view);
            }
        }else{
            stop = true;
        }
    }while (!stop);
}

}
AppWidgetManager-mAppWidgetManager;
AppWidgetHost mAppWidgetHost;
视图组主机视图;
int numWidgets=0;
/**
*在创建活动时调用。
*/
@凌驾
创建时的公共void(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_仪表板);
主机视图=(视图组)findViewById(R.id.LAYOUT_仪表板);
hostView.setOnLongClickListener(新视图.OnLongClickListener(){
@凌驾
仅长按公共布尔值(视图){
if(numWidgets<4){
选择Widget();
}否则{
removeAllWidgets();
numWidgets=0;
}
返回false;
}
});
mAppWidgetManager=AppWidgetManager.getInstance(此);
mAppWidgetHost=新的AppWidgetHost(这个,R.id.APPWIDGET\u HOST\u id);
恢复边缘();
}
/**
*启动菜单以选择小部件。选定的小部件将打开
*活动的结果。
*/
void selectWidget(){
int-appWidgetId=this.mAppWidgetHost.allocateAppWidgetId();
Intent pickIntent=新意图(AppWidgetManager.ACTION\u APPWIDGET\u PICK);
pickIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID,appWidgetId);
addEmptyData(pickIntent);
startActivityForResult(pickIntent,R.id.REQUEST\u PICK\u APPWIDGET);
}
/**
*这避免了com.android.settings.AppWidgetPickActivity中的错误,
*它用于选择小部件。这只会将空的附加内容添加到
*意图,避免错误。
*
*请参阅更多:http://code.google.com/p/android/issues/detail?id=4272
*/
void addEmptyData(Intent pickIntent){
ArrayList customInfo=新的ArrayList();
pickIntent.putParcelableArrayListExtra(AppWidgetManager.EXTRA\u CUSTOM\u INFO,customInfo);
ArrayList customExtras=新的ArrayList();
pickIntent.putParcelableArrayListExtra(AppWidgetManager.EXTRA\u CUSTOM\u EXTRAS,customExtras);
}
/**
*如果用户选择了一个小部件,当
*此函数被调用。
*/
@凌驾
受保护的void onActivityResult(int请求代码、int结果代码、意图数据){
if(resultCode==RESULT\u OK){
if(requestCode==R.id.REQUEST\u PICK\u APPWIDGET){
配置小部件(数据);
}else if(requestCode==R.id.REQUEST\u CREATE\u APPWIDGET){
createWidget(数据);
}
}else if(resultCode==RESULT\u cancelled&&data!=null){
int appWidgetId=data.getIntExtra(AppWidgetManager.EXTRA\u APPWIDGET\u ID,-1);
如果(appWidgetId!=-1){
mAppWidgetHost.deleteAppWidgetId(appWidgetId);
}
}
}
/**
*检查小部件是否需要任何配置。如果需要,启动
*配置活动。
*/
专用void配置小部件(意图数据){
Bundle extras=data.getExtras();
int appWidgetId=extras.getInt(AppWidgetManager.EXTRA\u APPWIDGET\u ID,-1);
AppWidgetProviderInfo appWidgetInfo=mAppWidgetManager.getAppWidgetInfo(appWidgetId);
if(appWidgetInfo.configure!=null){
意向意向=新意向(AppWidgetManager.ACTION\u APPWIDGET\u CONFIGURE);
setComponent(appWidgetInfo.configure);
intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID,appWidgetId);
startActivityForResult(意图、R.id.REQUEST\u CREATE\u APPWIDGET);
}否则{
createWidget(数据);
}
}
/**
*创建小部件并添加到视图布局中。
*/
公共void createWidget(意图数据){
if(numWidgets=1){
View=hostView.getChildAt(childCount-1);
if(查看AppWidgetHostView的实例){
removeWidget((AppWidgetHostView)视图);
}
}否则{
停止=真;
}
}而(!停止);
}
}

我对此进行了一些调试,并意识到您需要为添加的每个小部件存储AppWidgetId。当我存储AppWidgetId并尝试从中获取AppWidgetProviderInfo时,宽度和高度始终为0,但mAppWidgetHost.createView将返回有效视图。因此,要修复此存储,请将最后一个宽度和高度、id以及您希望保存到WidgetHolder的任何其他数据。然后,如果愿意,您可以将这些值存储到SharedReference中

这是我写的一个工作的WidgetHolder类

import android.util.Base64;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;

public class WidgetHolder implements Serializable {

    // any other data you want
    public int id;

    public int width, height;

    public WidgetHolder() {}

    public WidgetHolder(int id, int width, int height) {
        this.id = id;
        this.width = width;
        this.height = height;
    }

    public static WidgetHolder deserialize( String data ) {
        try {
            byte [] bites = Base64.decode( data.getBytes(), 0);
            ByteArrayInputStream bis = new ByteArrayInputStream( bites );
            ObjectInputStream ois = new ObjectInputStream( bis );
            WidgetHolder holder = (WidgetHolder) ois.readObject();
            ois.close();
            return holder;
        } catch (IOException e ) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        return new WidgetHolder();
    }

    public String serialize() {
        try {
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            ObjectOutputStream oos = new ObjectOutputStream( baos );
            oos.writeObject(this);
            oos.flush();
            return new String(Base64.encode(baos.toByteArray(), 0));
        } catch( IOException e ) {
            return "";
        }
    }
}
然后,无论何时向AppWidgetHost添加新的AppWidget,都将WidgetHolder数据存储到SharedReferences或缓存文件中

private void handleAddNewAppWidget( int appWidgetId, AppWidgetProviderInfo info ) {
    // use application context, for issues with support v7 libs causing AppCompatImage exceptions
    AppWidgetHostView hostView = mAppWidgetHost
            .createView(context.getApplicationContext(), appWidgetId, info);   
    hostView.setAppWidget(appWidgetId, info);

    // calculate width and height for hostView from info.minHeight and info.minWidth
    RelativeLayout.LayoutParams rlp = new RelativeLayout.LayoutParams( width, height );
    hostView.setLayoutParams(rlp);

    // add hostView to widgetContainer (RelativeLayout)
    widgetContainer.addView(hostView);

    // create widgetHolder
    WidgetHolder holder = new WidgetHolder( appWidgetId, width, height );

    String serialized = holder.serialize();

    // storage is a wrapper for SharedPreferences, the key is the appWidgetId, and the value is the serialized content
    storage.store(appWidgetId + "", serialized);
}

private void handleRestoreWidgets(ArrayList<String> widgets) {
    // Retrieve all saved widgets from Storage
    for( int i = 0; i < widgets.size(); i++ ) {
        String widgetString = widgets.get(i);
        WidgetHolder holder = WidgetHolder.deserialize(widgetString);
        AppWidgetProviderInfo info = AppWidgetManager
                .getInstance(getContext().getApplicationContext() )
                .getAppWidgetInfo(holder.id);

        AppWidgetHostView hostView = mAppWidgetHost
                .createView(context.getApplicationContext(), holder.id, info);
        hostView.setAppWidget(holder.id, info);

        RelativeLayout.LayoutParams rlp = new RelativeLayout.LayoutParams( holder.width,
                holder.height );
        hostView.setLayoutParams(rlp);

        // restore app widget from holder
        widgetContainer.addView(hostView);
    }
}
private void HandLeadNewAppWidget(int-appWidgetId,AppWidgetProviderInfo信息){
//使用应用程序上下文,解决支持v7 LIB导致AppCompatImage异常的问题
AppWidgetHostView主机视图=mAppWidgetHost
.createView(context.getApplicationContext(),appWidgetId,info);
setAppWidget(appWidgetId,info);
//从info.minHeight和info.minWidth计算hostView的宽度和高度
RelativeLayout.LayoutParams rlp=新的RelativeLayout.LayoutParams(宽度、高度);
设置布局参数(rlp);
//将主机视图添加到widgetContainer(RelativeLayout)
addView(主机视图);
//创建widgetHolder
WidgetHolder=新的WidgetHolder(appWidgetId、宽度、高度);
String serialized=holder.serialize();
//存储是SharedReference的包装,键是appWidgetId,值是序列化内容
store.store(appWidgetId+“”,序列化);
}
私有void handleRestoreWidgets(ArrayList小部件){
//从存储器中检索所有保存的小部件
对于(inti=0;iMap<String, String> allKeyValues = getContext().getSharedPreferences("WidgetHolders", Context.MODE_PRIVATE).getAll();

// then to get all stored String do 
ArrayList<String> serializedWidgetHolders = new ArrayList<String>( allKeyValues.values() );