程序入口点
类似于win32程序里的WinMain函数,Android自然也有它的程序入口点。它通过在AndroidManifest.xml文件中配置来指明,可以看到名为NotesList的activity节点下有这样一个intent-filter,其action为android.intent.action.MAIN,
Category指定为 android.intent.category.LAUNCHER,这就指明了这个activity是作为入口activity,系统查找到它后,就会创建这个activity实例来运行,若未发现就不启动(你可以把MAIN改名字试试)。

<intent-filter>
<action android:name="android.intent.action.MAIN"
/>
<category android:name="android.intent.category.LAUNCHER"
/>
</intent-filter>

NotesList详解
就从入口点所在的activity(见图1)开始,可以看到这个activity最重要的功能就是显示日志列表。这个程序的日志都存放在Sqlite数据库中,因此需要读取出所有的日志记录并显示。

先来看两个重要的私有数据,第一个PROJECTION字段指明了“日志列表“所关注的数据库中的字段(即只需要ID和Title就可以了)。

private
static
final String[] PROJECTION =
new String[] {
            Notes._ID, // 0
            Notes.TITLE, // 1
    };


第二个字段COLUMN_INDEX_TITLE指明title字段在数据表中的索引。
private
static
final
int COLUMN_INDEX_TITLE =
1;
然后就进入第一个调用的函数onCreate。
        Intent intent = getIntent();
        if (intent.getData() ==
null)
        {
            intent.setData(Notes.CONTENT_URI);
        }

      因为NotesList这个activity是系统调用的,此时的intent是不带数据和操作类型的,系统只是在其中指明了目标组件是Notelist,所以这里把”content:// com.google.provider.NotePad/notes”保存到intent里面,这个URI地址指明了数据库中的数据表名(参见以后的NotePadProvider类),也就是保存日志的数据表notes。
        Cursor cursor = managedQuery(getIntent().getData(), PROJECTION, null, null, Notes.DEFAULT_SORT_ORDER);
      然后调用managedQuery函数查询出所有的日志信息,这里第一个参数就是上面设置的” content:// com.google.provider.NotePad/notes”这个URI,即notes数据表。PROJECTION 字段指明了结果中所需要的字段,Notes.DEFAULT_SORT_ORDER 指明了结果的排序规则。实际上managedQuery并没有直接去查询数据库,而是通过Content Provider来完成实际的数据库操作,这样就实现了逻辑层和数据库层的分离。
SimpleCursorAdapter adapter =
new SimpleCursorAdapter(this, R.layout.noteslist_item, cursor,
                new String[] { Notes.TITLE }, new
int[] { android.R.id.text1 });
        setListAdapter(adapter);

      查询出日志列表后,构造一个CursorAdapter,并将其作为List View的数据源,从而在界面上显示出日志列表。可以看到,第二个参数是R.layout.noteslist_item,打开对应的noteslist_item.xml文件,
<TextView xmlns:android="
http://schemas.android.com/apk/res/android"
    android:id="@android:id/text1"
    android:layout_width="fill_parent"
    android:layout_height="?android:attr/listPreferredItemHeight"
    android:textAppearance="?android:attr/textAppearanceLarge"
    android:gravity="center_vertical"
    android:paddingLeft="5dip"
    android:singleLine="true"
/>

      就是用来显示一条日志记录的TextView,最后两个字段指明了实际的字段映射关系,通过这个TextView来显示一条日志记录的title字段。

处理“选择日志”事件

既然有了“日志列表”,就自然要考虑如何处理某一条日志的单击事件,这通过重载onListItemClick方法来完成,
    @Override
    protected
void onListItemClick(ListView l, View v, int position, long id) {
        Uri uri = ContentUris.withAppendedId(getIntent().getData(), id);
       
        String action = getIntent().getAction();
        if (Intent.ACTION_PICK.equals(action) || Intent.ACTION_GET_CONTENT.equals(action)) {
            // The caller is waiting for us to return a note selected by
            // the user.  The have clicked on one, so return it now.
            setResult(RESULT_OK, new Intent().setData(uri));
        } else {
            // Launch activity to view/edit the currently selected item
            startActivity(new Intent(Intent.ACTION_EDIT, uri));
        }
    }

      首先通过”content:// com.google.provider.NotePad/notes”和日志的id 号拼接得到选中日志的真正URI,然后创建一个新的Intent,其操作类型为Intent.ACTION_EDIT,数据域指出待编辑的日志URI(这里只分析else块)。

Intent深度剖析
那么,上面这句startActivity(new Intent(Intent.ACTION_EDIT, uri))执行后会发生什么事情呢?这时候Android系统就跳出来接管了,它会根据intent中的信息找到对应的activity,在这里找到的是NoteEditor这个activity,然后创建这个activity的实例并运行。

那么,Android又是如何找到NoteEditor这个对应的activity的呢?这就是intent发挥作用的时刻了。
new Intent(Intent.ACTION_EDIT, uri)

这里的Intent.ACTION_EDIT=” android.intent.action.EDIT”,另外通过设置断点,我们看下这里的uri值:
 

      可以看到选中的日志条目的URI是:content://com.google.provider.NotePad/notes/1

然后我们再来看下Androidmanfest.xml,其中有这个provider
<provider android:name="NotePadProvider"
            android:authorities="com.google.provider.NotePad"
/>

      发现没有?它也有com.google.provider.NotePad,这个是content://com.google.provider.NotePad/notes/1的一部分,同时

<activity android:name="NoteEditor"
            android:theme="@android:style/Theme.Light"
            android:label="@string/title_note"
            android:screenOrientation="sensor"
            android:configChanges="keyboardHidden|orientation"
>
<!-- This filter says that we can view or edit the data of
                 a single note -->
<intent-filter android:label="@string/resolve_edit">
<action android:name="android.intent.action.VIEW"
/>
<action android:name="android.intent.action.EDIT"
/>
<action android:name="com.android.notepad.action.EDIT_NOTE"
/>
<category android:name="android.intent.category.DEFAULT"
/>
<data android:mimeType="vnd.android.cursor.item/vnd.google.note"
/>
</intent-filter>
<!-- This filter says that we can create a new note inside
                 of a directory of notes. -->
<intent-filter>
<action android:name="android.intent.action.INSERT"
/>
<category android:name="android.intent.category.DEFAULT"
/>
<data android:mimeType="vnd.android.cursor.dir/vnd.google.note"
/>
</intent-filter>
</activity>

      上面第一个intent-filter中有一个action 名为android.intent.action.EDIT,而前面我们创建的Intent也正好是

Intent.ACTION_EDIT=” android.intent.action.EDIT”,想必大家已经明白是怎么回事了吧。

下面就进入activity选择机制了:
系统从intent中获取道uri,得到了content://com.google.provider.NotePad/notes/1,去掉开始的content:标识,得到com.google.provider.NotePad/notes/1,然后获取前面的com.google.provider.NotePad,然后就到Androidmanfest.xml中找到authorities为com.google.provider.NotePad的provider,这个就是后面要讲的contentprovider,然后就加载这个content provider。

<provider android:name="NotePadProvider"
            android:authorities="com.google.provider.NotePad"
/>

在这里是NotePadProvider,然后调用NotePadProvider的gettype函数,并把上述URI传给这个函数,函数返回URI所对应的类型(这里返回Notes.CONTENT_ITEM_TYPE,代表一条日志记录,而CONTENT_ITEM_TYPE = " vnd.android.cursor.item/vnd.google.note ")。
   @Override
    public String getType(Uri uri) {
        switch (sUriMatcher.match(uri)) {
        case NOTES:
            return Notes.CONTENT_TYPE;
        case NOTE_ID:
            return Notes.CONTENT_ITEM_TYPE;
        default:
            throw
new IllegalArgumentException("Unknown URI "
+ uri);
        }
}

      上面的sUriMatcher.match是用来检测uri是否能够被处理,而sUriMatcher.match(uri)返回值其实是由
        sUriMatcher =
new UriMatcher(UriMatcher.NO_MATCH);
        sUriMatcher.addURI(NotePad.AUTHORITY, "notes", NOTES);
        sUriMatcher.addURI(NotePad.AUTHORITY, "notes/#", NOTE_ID);

决定的。


然后系统使用获得的" vnd.android.cursor.item/vnd.google.note "和”android.intent.action.EDIT”到androidmanfest.xml中去找匹配的activity.


<intent-filter android:label="@string/resolve_edit">
<action android:name="android.intent.action.VIEW"
/>
<action android:name="android.intent.action.EDIT"
/>
<action android:name="com.android.notepad.action.EDIT_NOTE"
/>
<category android:name="android.intent.category.DEFAULT"
/>
<data android:mimeType="vnd.android.cursor.item/vnd.google.note"
/>
</intent-filter>

正好NoteEditor这个activity的intent-filter满足上述条件,这样就找到了NoteEditor。于是系统加载这个类并实例化,运行,然后就到了NoteEditor的OnCreate函数中(见后续文章)。

小技巧
1,在命令行中使用”adb shell”命令进入系统中,然后”cd app”进入应用程序所在目录,”rm XXX”就可以删除你指定的apk,从而去掉其在系统顶层界面占据的图标,若两次”cd data”则可以进入应用程序使用的数据目录,你的数据可以保存在这里,例如Notepad就是把其数据库放在它的databases目录下,名为note_pad.db.
2,第一次启动模拟器会比较慢,但以后就别关闭模拟器了,修改代码,调试都不需要再次启动的,直接修改后run或debug就是。
2.在测试时,如何实现一个提示
可以使用
1. Toast.makeText(this, "这是一个提示", Toast.LENGTH_SHORT).show();
2. //从资源文件string.xml 里面取提示信息
3.   Toast.makeText(this, getString(R.string.welcome), Toast.LENGTH_SHORT).show();
这个提示会几秒钟后消失
3.可以使用AlertDialog.Builder 才产生一个提示框.
   例如像messagebox那样的
1.    new AlertDialog.Builder(this)
2.     .setTitle("Android 提示")
3.     .setMessage("这是一个提示,请确定")
4.     .show();
带一个确定的对话框
1. new AlertDialog.Builder(this)
2.          .setMessage("这是第二个提示")
3.          .setPositiveButton("确定",
4.                          new DialogInterface.OnClickListener(){
5.                                  public void onClick(DialogInterface dialoginterface, int i){
6.                                      //按钮事件
7.                                  }
8.                          })
9.          .show();
AlertDialog.Builder 还有很多复杂的用法,有确定和取消的对话框
1. new AlertDialog.Builder(this)
2.         .setTitle("提示")
3.         .setMessage("确定退出?")
4.         .setIcon(R.drawable.quit)
5.         .setPositiveButton("确定", new DialogInterface.OnClickListener() {
6.         public void onClick(DialogInterface dialog, int whichButton) {
7.         setResult(RESULT_OK);//确定按钮事件
8.         finish();
9.         }
10.         })
11.         .setNegativeButton("取消", new DialogInterface.OnClickListener() {
12.         public void onClick(DialogInterface dialog, int whichButton) {
13.          //取消按钮事件
14.         }
15.         })
16.         .show();
4. menu 的用法.
1. 简单的代码
1. public static final int ITEM_1_ID = Menu.FIRST;
2. public static final int ITEM_2_ID = Menu.FIRST + 1;
3. public static final int ITEM_3_ID = Menu.FIRST + 2;
4.    
5. public boolean onCreateOptionsMenu(Menu menu) {
6.         super.onCreateOptionsMenu(menu);
7. //不带图标的menu
8.         menu.add(0, ITEM_1_ID, 0, "item-1");      
9. //带图标的menu
10.         menu.add(0, ITEM_2_ID, 1, "item-2").setIcon(R.drawable.editbills2);
11.         menu.add(0, ITEM_3_ID, 2, "item-3").setIcon(R.drawable.billsum1);
12.         return true;
13. }
14. 
15. public boolean onOptionsItemSelected(MenuItem item){
16.        switch (item.getItemId()) {
17.        case 1:
18.            Toast.makeText(this, "menu1",Toast.LENGTH_SHORT).show();           
19.            return true;
20.        case 2:
21.        
22.            return true;
23.        case 3:
24.         
25.            return true;
26.        }
27.        return false;
28.     }
2. menu实现的两种方法
大部分的应用程序都包括两种人机互动方式,一种是直接通过GUI的 Views,其可以满足大部分的交互操作。另外一种是应用Menu,当按下Menu按钮后,会弹出与当前活动状态下的应用程序相匹配的菜单。

这两种方式相比较都有各自的优势,而且可以很好的相辅相成,即便用户可以由主界面完成大部分操作,但是适当的拓展Menu功能可以更加完善应用程序,至少用户可以通过排列整齐的 按钮清晰的了解当前模式下可以使用的功能。
有两种方法可以为Android APPs添加菜单功能,下边将对设置过程给出详细的介绍:
第一种方法,通过Layout来添加静态菜单元素。
一般情况下,开发者在res/Layout路径下来定义应用程序的GUI。应用Eclipse创建一个新项目后,可以看到res/layout中存在一个 预置的main.xml文件,其作为程序默认启动界面。同样,可以通过这种方式 创建一个静态的Menu,创建方法参阅下边的源代码:
?View Code XML
<?xml version="1.0" encoding="utf-8"?> 
<menu xmlns:android="
http://schemas.android.com/apk/res/android"> 
    <item  
        android:id="@+id/previous"  
        android:title="@string/previous"  
        android:enabled="false" 
        android:icon="@android:drawable/ic_media_previous"/> 
        <!--these may not be available in next api (level > 3), so be carefull--> 
    <item  
        android:id="@+id/play_pause"  
        android:title="@string/play"  
        android:icon="@android:drawable/ic_media_play"/> 
    <item  
        android:id="@+id/next"  
        android:title="@string/next"  
        android:icon="@android:drawable/ic_menu_next"/> 
</menu>

在Activity类中调用刚刚创建的Menu,首先将当前的Activity与指定的Menu XML相关联:
 @Override
 public boolean onCreateOptionsMenu(Menu menu) {
     super.onCreateOptionsMenu(menu);
     getMenuInflater().inflate(R.layout.menu_mainactivity, menu);
     return true;
 }

实现onOptionsItemSelected方法: (其目的是捕捉到菜单触发事件后,对具体触发的选项作出响应,实际调用的函数包含在各自的case中)
01.@Override
02.public boolean onOptionsItemSelected(MenuItem item) {
03.    switch (item.getItemId()) {
04.    case R.id.previous:
05.        previous(); //go to previous song in the playlist
06.        return true;
07.    case R.id.play_pause:
08.        isPlaying() ? pause() : play(); //toggle play/pause
09.        return true;
10.    case R.id.next:
11.        next(); //go to next song in the playlist
12.        return true;
13.    }
14.    return false; //should never happen
15.}


最后可以通过onPrepareOptionMenu方法初始化Menu Items的属性:
01.@Override
02.public boolean onPrepareOptionsMenu(Menu menu) {
03.    //set play_pause menu item look
04.    if(isPlaying()) {
05.        menu
06.            .findItem(R.id.play_pause)
07.            .setTitle(R.string.pause)
08.            .setIcon(android.R.drawable.ic_media_pause);
09.    } else {
10.        menu
11.            .findItem(R.id.play_pause)
12.            .setTitle(R.string.play)
13.            .setIcon(android.R.drawable.ic_media_play);
14.    }
15.    return true;
16.}


大部分程序都通过这种方式添加Menu菜单功能,而且通过以上的步骤来看,其实现方法非常简单。
第二种方法,在Activity类中动态创建Menu。
首先需要定义Menu Item识别序号:
1.public static final MENU_PREVIOUS = 0; //no more R.ids
2.public static final MENU_PLAY_PAUSE = 1;
3.public static final MENU_NEXT = 2;


实现onCreateOptionMenu()方法:(第一种方法中已经通过xml定义了现成的Menu结构,所以不需要应用这个方法)
01.@Override
02.public boolean onCreateOptionsMenu(Menu menu) {
03.    menu
04.        .add(0, MENU_PREVIOUS, 0, R.string.previous)
05.        .setIcon(android.R.drawable.ic_media_previous);
06.    menu
07.        .add(0, MENU_PLAY_PAUSE, 0, R.string.play)
08.        .setIcon (android.R.drawable.ic_media_play);
09.    menu
10.        .add(0, MENU_NEXT, 0, R.string.next)
11.        .setIcon(android.R.drawable.ic_media_next);
12.    return true;
13.}


引用与第一种方法相同的方式来捕捉菜单的行为:
01.@Override
02.public boolean onOptionsItemSelected(MenuItem item) {
03.    switch (item.getItemId()) {
04.    case MENU_PREVIOUS:
05.        previous(); //go to previous song in the playlist
06.        return true;
07.    case MENU_PLAY_PAUSE:
08.        isPlaying() ? pause() : play(); //toggle play/pause
09.        return true;
10.    case MENU_NEXT:
11.        next(); //go to next song in the playlist
12.        return true;
13.    }
14.    return false; //should never happen
15.}


————
对以上两种方法的补充:
根据需要设置不同Menu Item的属性:
1.menu.findItem(R.id.next).setEnabled(false);


设置Menu Item从属关系(添加子父级别):
直接写在方法中:
1.menu
2.        .addSubMenu(R.id.repeat)
3.        .add(R.id.one)
4.        .add(R.id.all)
5.        .add(R.id.none);


直接定义在XML Layout中:
?View Code XML
<item android:id="@+id/repeat" android:title="@string/repeat"> 
<menu> 
    <item android:id="@+id/one" android:title="@string/repeat_one"></item> 
    <item android:id="@+id/all" android:title="@string/repeat_all"></item> 
    <item android:id="@+id/none" android:title="@string/repeat_none"></item> 
</menu>

————
这两种不同的方法实现的目的是一样的,而且不存在本质上的却别,具体根据实际情况(根据项目的结构需要或者团队开发标准)选择合适的方法来创建Menu。
5.Activity 的切换(含Bundle传值)
1. 代码   
1、 2个Activity 的切换,没有数据传递
1. //从A到B
2. Intent intent = new Intent();
3. intent.setClass(A.this, B.class);
4. startActivity(intent);
5. A.this.finish();

2、 2个Activity 之间传递数据(简单)
//A数据传给B
//A中代码:”passData” 是自定义的识别标志,可以随便命名~ 还可以添加多个

Intent intent = new Intent();
  intent.setClass(A.this, B.class);
  Bundle mBundle = new Bundle();
  mBundle.putString("passData", "ray'blog");//压入数据
  intent.putExtras(mBundle);
  startActivity(intent);
A.this.finish();

//B中接受数据的代码:

//读出数据, 则data的值为 ray‘blog
        Bundle bundle = getIntent().getExtras(); 
String data = bundle.getString( "passData" );


 3、 2个Activity 之间传递数据(复杂方法我没看懂)
    相关的几个函数
    startActivityForResult
    public final void setResult(int resultCode, String data)
    回调函数
    protected void onActivityResult(int requestCode, int resultCode, Intent data)
 
   例如A到B, 从B得到A的数据 
1. //A到B
2. static final int RG_REQUEST = 0;
3. Intent intent = new Intent();
4. intent.setClass(A.this, B.class);
5. startActivityForResult(intent,RG_REQUEST);
6.                                  
7. //在B中处理
8. Bundle bundle = new Bundle();
bundle.putString("DataKey", edittext.getText().toString());//给bundle 写入数据
Intent mIntent = new Intent();
mIntent.putExtras(bundle);
setResult(RESULT_OK, mIntent);
finish();
9. 
10. //最后在A的回调函数里面接收数据
11. if (requestCode == RG_REQUEST) {
      if (resultCode == RESULT_CANCELED)
           setTitle("Canceled...");
      else if(resultCode == RESULT_OK) {
          setTitle((String)data.getCharSequenceExtra("DataKey"));
       }
 }
2. 详解:
一个Android应用程序很少会只有一个Activity对象,如何在多个Activity之间进行跳转,而且能够互相传值是一个很基本的要求。

  在前面创建的MyApp中,我们通过点击按钮可以更新当前界面上的文本内容。现在我们想换种方式,在点击按钮后,显示一个新的屏幕,在这个屏幕上输入一段话,然后再返回到原先的界面显示刚才输入的那句话。

  首先我们新建这个新屏幕的布局文件input.xml,并添加一个文本输入框和一个按钮(注意,xml元素的命名不要和其他布局文件中的定义重名,因为所有的资源都在R中进行索引,比如id,如果重名了在使用R.id.*的时候就会有问题了)。这个布局文件对应的是一个Activity,因此我们再新建一个Input类(继承自Activity)用于显示这个布局并响应事件。

 

  然后,还有一个重要的工作,那就是在清单文件AndroidManifest.xml中告诉程序,我定义了一个新的Activity,你可以去调用它。

 

  我们希望在以前的那个主界面上点击按钮以后可以跳转到文本输入界面,所以我们需要对按钮的onClick事件进行定义:

 

  在这段代码里出现了一些新东西。首先是Intent,它是Android一个很重要的类.Intent直译是“意图”,什么是意图呢?比如你想从这个Activity跳转到另外一个Activity,这就是一个意图。它不但可以连接多个Activity,还可以在它们之间传递数据。在这里,我们就是用Intent从MyApp对象跳转到了Input对象。
再看紧跟着的startActivityForResult()方法,顾名思义,它可以从一个定义好的Intent对象启动一个新的Activity,并且,这个Activity会返回执行的结果,这些内容下面马上就会提到。
好,这里我们已经可以调出新Activity了,我们看一下执行的结果:
你马上可以想到,现在需要对新的Activity(Input)进行处理了。我们在点击“确定”按钮的时候,需要获得上面EditText对象中的文本,然后返回到前一个Activity(MyApp)中去。看我们的按钮事件处理:

 
这里的关键是SharedPreferences对象,这是在多个Activity(同一包中)共享数据的方式,本质上它就是一个可以在包的范围内进行数据共享的文件。
我们通过一个标签“Text”获得了和文本相关的那个SharedPreferences对象(“Text”仅仅是自己定义的一个标签),然后给它赋予一个“text”对象值为当前文本框中输入的文本。设置完成以后,设置当前Activity的执行结果为RESULT_OK,再关闭当前的Activity,剩下的事情就可以回到MyApp这个主界面中去执行了。
其实剩下的事情也很简单,在MyApp这个Activity中,我们需要重写一个函数,onActivityResult()。因为我们启动Input这个Activity的时候使用的是startActivityForResult()方法,这个方法会使Input执行完以后返回给MyApp一个结果,MyApp接收到返回结果的时候会触发onActivityResult事件,对于结果的处理就在onActivityResult()中进行。同样,我们通过“Text”这个标签获得SharedPreferences对象,再把字符串从“text”对象中取出来并显示到当前屏幕上。
另外说明一下,requestCode是用来标识请求对象,我们刚才在启动Activity的时候使用的是“startActivityForResult(intent, 0)”,这里的0就是requestCode,当然,你可以设置成任何你喜欢的值。
 
我们看一下执行结果:
 
 
 
6.Android UI Layout
1. AbsoluteLayout
在 Android UI 中,最基本的构建单位(building block)是 android.view.View。一个 View 占据屏幕上的一个矩形区域,并负责该区域的绘画和事件处理。View 有一些子类,比如 ImageView、TextView 等可分别用来显示图像、文字…… View 还有一个特殊的子类 ViewGroup,ViewGroup 在 UI layout 中充当“容器”的角色,用以“包含”其他 View 以及 ViewGroup:
viewgroup.png

  由于 ViewGroup 是一个 abstract class 无法直接实例化,所以在 layout 中真正充当“容器”角色的应该是 ViewGroup 的子类 :AbsoluteLayout、 FrameLayout、 LinearLayout、 RelativeLayout 等。在实际的 UI 编程中,使用不同的 Layout 类作为容器,对该容器中的各个子 View 的排列方式有很大影响。比如,LinearLayout 中的各个子 View 按照横向或者纵向线性排列;而 AbsoluteLayout 中各个子 View 可以指定以像素为单位的“绝对”位置。AbsoluteLayout 的这种“绝对”定位的布局方式和我们非常熟悉的 Windows 编程中的 SetWindowPos() 或 Form1.Left = 10 的布局方式是一样的,比较简单:

  现在我们新建一个 Android 工程中,在其主 Activity 类中添加如下三个成员:
private AbsoluteLayout al;
private TextView tv;
private View v;

改写这个类的 onCreate 方法如下:
public void onCreate(Bundle icicle) {
        super.onCreate(icicle);

  构造一个 AbsoluteLayout,设置其背景色
        al = new AbsoluteLayout(this);
        al.setBackgroundColor(Color.YELLOW);
构造一个 TextView 并设置其 text 和 背景色
        tv = new TextView(this);
        tv.setText("Android is a software stack for mobile devices that includes an operating system, middleware and key applications. ");
        tv.setBackgroundColor(Color.BLUE);
用该 View 在父 View 中的 width,height,x,y 作为参数构造一个 AbsoluteLayout.LayoutParams
        AbsoluteLayout.LayoutParams tvLP = new AbsoluteLayout.LayoutParams(70, 50, 10, 20);
把这个 TextView 加入到 AbsoluteLayout 中,并应用上一步创建的 LayoutParams。这样 TextView 就会显示在我们指定的位置上了。
        al.addView(tv, tvLP);
      
        v = new View(this);
        v.setBackgroundColor(Color.RED);
        AbsoluteLayout.LayoutParams vLP = new AbsoluteLayout.LayoutParams(70, 50, 90, 70);
也可以先为子 View 设置 LayoutParams,然后再调用一个参数的 ViewGroup.addView(View) 来添加。效果是一样的。
        v.setLayoutParams(vLP);
        al.addView(v);
      
设置 al 为本 Activity 的 content
这样,在该 Activity 被调用时,就会显示该 AbsoluteLayout 和其子 View
        this.setContentView(al);
}

7. Tab以及 HostTab操作
Tab与TabHost
 
这就是Tab,而盛放Tab的容器就是TabHost
如何实现??
每一个Tab还对应了一个布局,这个就有点好玩了。一个Activity,对应了多个功能布局。
①新建一个Tab项目,注意,不要生成main Activity
这里不要选
②在包里面新建一个类MyTab,继承于TabActivity
其实,TabActivity是Activity的子类
package zyf.tab.test;
import android.app.TabActivity;
public class MyTab extends TabActivity {
}
③从父类继承OnCreate()入口方法
package zyf.tab.test;
import android.app.TabActivity;
import android.os.Bundle;
public class MyTab extends TabActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
}
}
④在Manifest.xml文件中注册一下MyTab类(Activity)
⑤这时候,需要设计一下标签页对应的布局,一般采用FrameLayout作为根布局,每个标签页面对应一个子节点的Layout
android:layout_width=”fill_parent” android:layout_height=”fill_parent”>
android:layout_width=”fill_parent” android:layout_height=”fill_parent”
androidrientation=”vertical” >
android:layout_height=”wrap_content” android:text=”EditText”
android:textSize=”18sp”>
android:layout_height=”wrap_content” android:text=”Button”>
android:layout_width=”fill_parent” android:layout_height=”fill_parent”
androidrientation=”vertical” >
android:layout_width=”wrap_content” android:layout_height=”wrap_content”>
android:layout_width=”fill_parent” android:layout_height=”fill_parent”
androidrientation=”vertical”>
android:layout_width=”166px” android:layout_height=”98px”
androidrientation=”vertical”>
android:layout_width=”wrap_content” android:layout_height=”wrap_content”
android:text=”RadioButton”>
android:layout_width=”wrap_content” android:layout_height=”wrap_content”
android:text=”RadioButton”>
⑥首先,应该声明TabHost,然后用LayoutInflater过滤出布局来,给TabHost加上含有Tab页面的FrameLayout
private TabHost myTabhost;
myTabhost=this.getTabHost();//从TabActivity上面获取放置Tab的TabHost
LayoutInflater.from(this).inflate(R.layout.main, myTabhost.getTabContentView(), true);
//from(this)从这个TabActivity获取LayoutInflater
//R.layout.main 存放Tab布局
//通过TabHost获得存放Tab标签页内容的FrameLayout
//是否将inflate 拴系到根布局元素上
myTabhost.setBackgroundColor(Color.argb(150, 22, 70, 150));
//设置一下TabHost的颜色
⑦接着,在TabHost创建一个标签,然后设置一下标题/图标/标签页布局
myTabhost
.addTab(myTabhost.newTabSpec(“TT”)// 制造一个新的标签TT
.setIndicator(“KK”,
getResources().getDrawable(R.drawable.ajjc))
// 设置一下显示的标题为KK,设置一下标签图标为ajjc
.setContent(R.id.widget_layout_red));
//设置一下该标签页的布局内容为R.id.widget_layout_red,这是FrameLayout中的一个子Layout

⑧标签切换事件处理,setOnTabChangedListener
myTabhost.setOnTabChangedListener(new OnTabChangeListener(){
@Override
public void onTabChanged(String tabId) {
// TODO Auto-generated method stub
}
});
⑨各个标签页的动态MENU
先把在XML中设计好的MENU放到一个int数组里
private static final int myMenuResources[] = { R.menu.phonebook_menu,
R.menu.addphone_menu, R.menu.chatting_menu, R.menu.userapp_menu };

在setOnTabChangedListener()方法中根据标签的切换情况来设置myMenuSettingTag
@Override
public void onTabChanged(String tagString) {
// TODO Auto-generated method stub
if (tagString.equals(“One”)) {
myMenuSettingTag = 1;
}
if (tagString.equals(“Two”)) {
myMenuSettingTag = 2;
}
if (tagString.equals(“Three”)) {
myMenuSettingTag = 3;
}
if (tagString.equals(“Four”)) {
myMenuSettingTag = 4;
}
if (myMenu != null) {
onCreateOptionsMenu(myMenu);
}
}
然后onCreateOptionsMenu(Menu menu) 方法中通过MenuInflater过滤器动态加入MENU
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// TODO Auto-generated method stub
// Hold on to this
myMenu = menu;
myMenu.clear();//清空MENU菜单
// Inflate the currently selected menu XML resource.
MenuInflater inflater = getMenuInflater();
//从TabActivity这里获取一个MENU过滤器
switch (myMenuSettingTag) {
case 1:
inflater.inflate(myMenuResources[0], menu);
//动态加入数组中对应的XML MENU菜单
break;
case 2:
inflater.inflate(myMenuResources[1], menu);
break;
case 3:
inflater.inflate(myMenuResources[2], menu);
break;
case 4:
inflater.inflate(myMenuResources[3], menu);
break;
default:
break;
}
return super.onCreateOptionsMenu(menu);
}
⑩运行效果

  
8. List  (图片/按钮/标题/文本)

LIST例一
在android开发中ListView是比较常用的组件,它以列表的形式展示具体内容,并且能够根据数据的长度自适应显示。抽空把对ListView的使用做了整理,并写了个小例子,如下图。
  

列表的显示需要三个元素:
1.ListVeiw 用来展示列表的View。
2.适配器 用来把数据映射到ListView上的中介。
3.数据    具体的将被映射的字符串,图片,或者基本组件。
     根据列表的适配器类型,列表分为三种,ArrayAdapter,SimpleAdapter和SimpleCursorAdapter
其中以ArrayAdapter最为简单,只能展示一行字。SimpleAdapter有最好的扩充性,可以自定义出各种效果。SimpleCursorAdapter可以认为是SimpleAdapter对数据库的简单结合,可以方面的把数据库的内容以列表的形式展示出来。
我们从最简单的ListView开始:
/**
* @author allin
*
*/
public class MyListView extends Activity {
private ListView listView;
//private List<String> data = new ArrayList<String>();
@Override
public void onCreate(Bundle savedInstanceState){
  super.onCreate(savedInstanceState);
  listView = new ListView(this);
  listView.setAdapter(new ArrayAdapter<String>(this, android.R.layout.simple_expandable_list_item_1,getData()));
  setContentView(listView);
}
private List<String> getData(){
  List<String> data = new ArrayList<String>();
  data.add("测试数据1");
  data.add("测试数据2");
  data.add("测试数据3");
  data.add("测试数据4");
  return data;
}
}
复制代码
上面代码使用了ArrayAdapter(Context context, int textViewResourceId, List<T> objects)来装配数据,要装配这些数据就需要一个连接ListView视图对象和数组数据的适配器来两者的适配工作,ArrayAdapter的构造需要三个参数,依次为this,布局文件(注意这里的布局文件描述的是列表的每一行的布局,android.R.layout.simple_list_item_1是系统定义好的布局文件只显示一行文字,数据源(一个List集合)。同时用setAdapter()完成适配的最后工作。运行后的现实结构如下图:
 
 
SimpleCursorAdapter
sdk的解释是这样的:An easy adapter to map columns from a cursor to TextViews or ImageViews defined in an XML file. You can specify which columns you want, which views you want to display the columns, and the XML file that defines the appearance of these views。简单的说就是方便把从游标得到的数据进行列表显示,并可以把指定的列映射到对应的TextView中。
下面的程序是从电话簿中把联系人显示到类表中。先在通讯录中添加一个联系人作为数据库的数据。然后获得一个指向数据库的Cursor并且定义一个布局文件(当然也可以使用系统自带的)。
/**
* @author allin
*
*/
public class MyListView2 extends Activity {
private ListView listView;
//private List<String> data = new ArrayList<String>();
@Override
public void onCreate(Bundle savedInstanceState){
  super.onCreate(savedInstanceState);
  listView = new ListView(this);
  Cursor cursor = getContentResolver().query(People.CONTENT_URI, null, null, null, null);
  startManagingCursor(cursor);
  ListAdapter listAdapter = new SimpleCursorAdapter(this, android.R.layout.simple_expandable_list_item_1,
    cursor,
    new String[]{People.NAME},
    new int[]{android.R.id.text1});
  listView.setAdapter(listAdapter);
  setContentView(listView);
}
}
复制代码
Cursor cursor = getContentResolver().query(People.CONTENT_URI, null, null, null, null);先获得一个指向系统通讯录数据库的Cursor对象获得数据来源。
startManagingCursor(cursor);我们将获得的Cursor对象交由Activity管理,这样Cursor的生命周期和Activity便能够自动同步,省去自己手动管理Cursor。
SimpleCursorAdapter 构造函数前面3个参数和ArrayAdapter是一样的,最后两个参数:一个包含数据库的列的String型数组,一个包含布局文件中对应组件id的int型数组。其作用是自动的将String型数组所表示的每一列数据映射到布局文件对应id的组件上。上面的代码,将NAME列的数据一次映射到布局文件的id为text1的组件上。
注意:需要在AndroidManifest.xml中如权限:<uses-permission android:name="android.permission.READ_CONTACTS"></uses-permission>
运行后效果如下图:
 
 
SimpleAdapter
simpleAdapter的扩展性最好,可以定义各种各样的布局出来,可以放上ImageView(图片),还可以放上Button(按钮),CheckBox(复选框)等等。下面的代码都直接继承了ListActivity,ListActivity和普通的Activity没有太大的差别,不同就是对显示ListView做了许多优化,方面显示而已。
下面的程序是实现一个带有图片的类表。
首先需要定义好一个用来显示每一个列内容的xml
vlist.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="
http://schemas.android.com/apk/res/android"
android:orientation="horizontal" android:layout_width="fill_parent"
android:layout_height="fill_parent">
<ImageView android:id="@+id/img"
  android:layout_width="wrap_content"
  android:layout_height="wrap_content"
  android:layout_margin="5px"/>
<LinearLayout android:orientation="vertical"
  android:layout_width="wrap_content"
  android:layout_height="wrap_content">
  <TextView android:id="@+id/title"
   android:layout_width="wrap_content"
   android:layout_height="wrap_content"
   android:textColor="#FFFFFFFF"
   android:textSize="22px" />
  <TextView android:id="@+id/info"
   android:layout_width="wrap_content"
   android:layout_height="wrap_content"
   android:textColor="#FFFFFFFF"
   android:textSize="13px" />
</LinearLayout>
</LinearLayout>
复制代码
下面是实现代码:
/**
* @author allin
*
*/
public class MyListView3 extends ListActivity {
// private List<String> data = new ArrayList<String>();
@Override
public void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  SimpleAdapter adapter = new SimpleAdapter(this,getData(),R.layout.vlist,
    new String[]{"title","info","img"},
    new int[]{R.id.title,R.id.info,R.id.img});
  setListAdapter(adapter);
}
private List<Map<String, Object>> getData() {
  List<Map<String, Object>> list = new ArrayList<Map<String, Object>>();
  Map<String, Object> map = new HashMap<String, Object>();
  map.put("title", "G1");
  map.put("info", "google 1");
  map.put("img", R.drawable.i1);
  list.add(map);
  map = new HashMap<String, Object>();
  map.put("title", "G2");
  map.put("info", "google 2");
  map.put("img", R.drawable.i2);
  list.add(map);
  map = new HashMap<String, Object>();
  map.put("title", "G3");
  map.put("info", "google 3");
  map.put("img", R.drawable.i3);
  list.add(map);
  return list;
}
}
复制代码
使用simpleAdapter的数据用一般都是HashMap构成的List,list的每一节对应ListView的每一行。HashMap的每个键值数据映射到布局文件中对应id的组件上。因为系统没有对应的布局文件可用,我们可以自己定义一个布局vlist.xml。下面做适配,new一个SimpleAdapter参数一次是:this,布局文件(vlist.xml),HashMap的 title 和 info,img。布局文件的组件id,title,info,img。布局文件的各组件分别映射到HashMap的各元素上,完成适配。
运行效果如下图:
 
 

有按钮的ListView
      但是有时候,列表不光会用来做显示用,我们同样可以在在上面添加按钮。添加按钮首先要写一个有按钮的xml文件,然后自然会想到用上面的方法定义一个适配器,然后将数据映射到布局文件上。但是事实并非这样,因为按钮是无法映射的,即使你成功的用布局文件显示出了按钮也无法添加按钮的响应,这时就要研究一下ListView是如何现实的了,而且必须要重写一个类继承BaseAdapter。下面的示例将显示一个按钮和一个图片,两行字如果单击按钮将删除此按钮的所在行。并告诉你ListView究竟是如何工作的。效果如下:
 
 
vlist2.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="
http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<ImageView android:id="@+id/img"
  android:layout_width="wrap_content"
  android:layout_height="wrap_content"
  android:layout_margin="5px"/>
<LinearLayout android:orientation="vertical"
  android:layout_width="wrap_content"
  android:layout_height="wrap_content">
  <TextView android:id="@+id/title"
   android:layout_width="wrap_content"
   android:layout_height="wrap_content"
   android:textColor="#FFFFFFFF"
   android:textSize="22px" />
  <TextView android:id="@+id/info"
   android:layout_width="wrap_content"
   android:layout_height="wrap_content"
   android:textColor="#FFFFFFFF"
   android:textSize="13px" />
</LinearLayout>
<Button android:id="@+id/view_btn"
  android:layout_width="wrap_content"
  android:layout_height="wrap_content"
  android:text="@string/s_view_btn"
  android:layout_gravity="bottom|right" />
</LinearLayout>
复制代码
程序代码:
/**
* @author allin
*
*/
public class MyListView4 extends ListActivity {
private List<Map<String, Object>> mData;
@Override
public void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  mData = getData();
  MyAdapter adapter = new MyAdapter(this);
  setListAdapter(adapter);
}
private List<Map<String, Object>> getData() {
  List<Map<String, Object>> list = new ArrayList<Map<String, Object>>();
  Map<String, Object> map = new HashMap<String, Object>();
  map.put("title", "G1");
  map.put("info", "google 1");
  map.put("img", R.drawable.i1);
  list.add(map);
  map = new HashMap<String, Object>();
  map.put("title", "G2");
  map.put("info", "google 2");
  map.put("img", R.drawable.i2);
  list.add(map);
  map = new HashMap<String, Object>();
  map.put("title", "G3");
  map.put("info", "google 3");
  map.put("img", R.drawable.i3);
  list.add(map);
  return list;
}
// ListView 中某项被选中后的逻辑
@Override
protected void onListItemClick(ListView l, View v, int position, long id) {
  Log.v("MyListView4-click", (String)mData.get(position).get("title"));
}
/**
  * listview中点击按键弹出对话框
  */
public void showInfo(){
  new AlertDialog.Builder(this)
  .setTitle("我的listview")
  .setMessage("介绍...")
  .setPositiveButton("确定", new DialogInterface.OnClickListener() {
   @Override
   public void onClick(DialogInterface dialog, int which) {
   }
  })
  .show();
}
public final class ViewHolder{
  public ImageView img;
  public TextView title;
  public TextView info;
  public Button viewBtn;
}
public class MyAdapter extends BaseAdapter{
  private LayoutInflater mInflater;
  public MyAdapter(Context context){
   this.mInflater = LayoutInflater.from(context);
  }
  @Override
  public int getCount() {
   // TODO Auto-generated method stub
   return mData.size();
  }
  @Override
  public Object getItem(int arg0) {
   // TODO Auto-generated method stub
   return null;
  }
  @Override
  public long getItemId(int arg0) {
   // TODO Auto-generated method stub
   return 0;
  }
  @Override
  public View getView(int position, View convertView, ViewGroup parent) {
   ViewHolder holder = null;
   if (convertView == null) {
    holder=new ViewHolder();
    convertView = mInflater.inflate(R.layout.vlist2, null);
    holder.img = (ImageView)convertView.findViewById(R.id.img);
    holder.title = (TextView)convertView.findViewById(R.id.title);
    holder.info = (TextView)convertView.findViewById(R.id.info);
    holder.viewBtn = (Button)convertView.findViewById(R.id.view_btn);
    convertView.setTag(holder);
   }else {
    holder = (ViewHolder)convertView.getTag();
   }
   holder.img.setBackgroundResource((Integer)mData.get(position).get("img"));
   holder.title.setText((String)mData.get(position).get("title"));
   holder.info.setText((String)mData.get(position).get("info"));
   holder.viewBtn.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
     showInfo();    
    }
   });
   return convertView;
  }
}
}

复制代码

     下面将对上述代码,做详细的解释,listView在开始绘制的时候,系统首先调用getCount()函数,根据他的返回值得到listView的长度(这也是为什么在开始的第一张图特别的标出列表长度),然后根据这个长度,调用getView()逐一绘制每一行。如果你的getCount()返回值是0的话,列表将不显示同样return 1,就只显示一行。
系统显示列表时,首先实例化一个适配器(这里将实例化自定义的适配器)。当手动完成适配时,必须手动映射数据,这需要重写getView()方法。系统在绘制列表的每一行的时候将调用此方法。getView()有三个参数,position表示将显示的是第几行,covertView是从布局文件中inflate来的布局。我们用LayoutInflater的方法将定义好的vlist2.xml文件提取成View实例用来显示。然后将xml文件中的各个组件实例化(简单的findViewById()方法)。这样便可以将数据对应到各个组件上了。但是按钮为了响应点击事件,需要为它添加点击监听器,这样就能捕获点击事件。至此一个自定义的listView就完成了,现在让我们回过头从新审视这个过程。系统要绘制ListView了,他首先获得要绘制的这个列表的长度,然后开始绘制第一行,怎么绘制呢?调用getView()函数。在这个函数里面首先获得一个View(实际上是一个ViewGroup),然后再实例并设置各个组件,显示之。好了,绘制完这一行了。那 再绘制下一行,直到绘完为止。在实际的运行过程中会发现listView的每一行没有焦点了,这是因为Button抢夺了listView的焦点,只要布局文件中将Button设置为没有焦点就OK了。
运行效果如下图:
 
 
LIST例二
ListView 是android开发中最常用的组件之一,它通过一个adapter来构建显示通常有三种adapter可以使用ArrayAdapter ,SimpleAdapter,CursorAdapter。CursorAdapter主要正对数据库使用,下面通过例子介绍ArrayAdapter ,SimpleAdapter的简单使用:
   1:ArrayAdapter 它接受一个数组或者List作为参数来构建。
      一下通过简单例子说明:
  创建Test 继承ListActivity 这里我们传入一个string数组

public class ListTest extends ListActivity {
    /** *//** Called when the activity is first created. */

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        String[] sw = new String[100];
        for (int i = 0; i < 100; i++) {
            sw[i] = "listtest_" + i;
        }
        ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,android.R.layout.simple_list_item_1,sw);//使用系统已经实现好的xml文件simple_list_item_1
        setListAdapter(adapter);
    }
}
运行如图:
 

 从以上代码可以看不我们不需要加载我们自己的layout 而是用系统已经实现的layout很快速的实现了listview

第二种SimpleAdapter:
 先看下我们例子的最终截图:
 
 

通过上图可以看出listview每行不仅仅是一个string 包括了很多项,图片,多项文字
我们通过构建list,并设置每项为一个map来实现:
代码:创建TestList类继承Activity


super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        ArrayList<HashMap<String, Object>> users = new ArrayList<HashMap<String, Object>>();
        for (int i = 0; i < 10; i++) {
            HashMap<String, Object> user = new HashMap<String, Object>();
            user.put("img", R.drawable.user);
            user.put("username", "姓名(" + i+")");
            user.put("age", (20 + i) + "");
            users.add(user);
        }
        SimpleAdapter saImageItems = new SimpleAdapter(this,
                users,// 数据来源
                R.layout.user,//每一个user xml 相当ListView的一个组件
                new String[] { "img", "username", "age" },
                // 分别对应view 的id
                new int[] { R.id.img, R.id.name, R.id.age });
        // 获取listview
        ((ListView) findViewById(R.id.users)).setAdapter(saImageItems);
下面是main.xml的内容:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="
http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="fill_parent"
    android:layout_height="fill_parent">
    <TextView android:text="用户列表" android:gravity="center"
        android:layout_height="wrap_content"
        android:layout_width="fill_parent" android:background="#DAA520"
        android:textColor="#000000">
    </TextView>
    <LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content">
        <TextView android:text="姓名"
            android:gravity="center" android:layout_width="160px"
            android:layout_height="wrap_content" android:textStyle="bold"
            android:background="#7CFC00">
        </TextView>
        <TextView android:text="年龄"
            android:layout_width="170px" android:gravity="center"
            android:layout_height="wrap_content" android:textStyle="bold"
            android:background="#F0E68C">
        </TextView>
    </LinearLayout>
<ListView android:layout_width="wrap_content"
        android:layout_height="wrap_content" android:id="@+id/users">
    </ListView>
</LinearLayout>

之中listView前面的可以说是标题行,listview相当于用来显示数据的容器,里面每行是一个用户信息,而用户信息是样子呢?

 看看use.xml

<?xml version="1.0" encoding="utf-8"?> 
<TableLayout   
         android:layout_width="fill_parent"   
         xmlns:android="
http://schemas.android.com/apk/res/android"   
         android:layout_height="wrap_content"   
         >
         <TableRow >
         <ImageView   
               android:layout_width="wrap_content"   
               android:layout_height="wrap_content"  
               android:id="@+id/img">   
         </ImageView> 
         <TextView   
               android:layout_height="wrap_content"   
               android:layout_width="150px"   
               android:id="@+id/name"> 
         </TextView> 
         <TextView   
               android:layout_height="wrap_content"  
               android:layout_width="170px"   
               android:id="@+id/age"> 
         </TextView>
         </TableRow>
</TableLayout> 
也就是说每行包含了一个img 和2个文字信息
这个文件以参数的形式通过adapter在listview中显示。
也就是:
SimpleAdapter saImageItems = new SimpleAdapter(this,
                users,// 数据来源
                R.layout.user,//每一个user xml 相当ListView的一个组件
                new String[] { "img", "username", "age" },

                // 分别对应view 的id
                new int[] { R.id.img, R.id.name, R.id.age });
LIST例三
简约而不简单——Android SimpleAdapter
列表(ListView)、表格(GridView),这在手机应用上面肯定是少不了的,怎样实现比较复杂一点的界面呢,先看一下我的效果图。

             

这样布局的情况是最基本的,也是最常用的,网上关于这样的布局有多种版本的实现方法,但是有很多需要自己实现Adapter,那样子是比较复杂而且没有必要的,因为我们有简约而不简单的SimpleAdapter。

1. ListView

SimpleAdapter的核心代码:

  for (int i = 0; i < 10; i++) {
   Map<String, Object> map = new HashMap<String, Object>();
   map.put("PIC", R.drawable.pic);
   map.put("TITLE", "Test Title");
   map.put("CONTENT", "Test Content");
   contents.add(map);
  }
  SimpleAdapter adapter = new SimpleAdapter(this,
    (List<Map<String, Object>>) contents, R.layout.listitem,
    new String[] { "PIC", "TITLE", "CONTENT" }, new int[] {
      R.id.listitem_pic, R.id.listitem_title,
      R.id.listitem_content });

  listView.setAdapter(adapter);
 

listitem的Layout:

<?xml version="1.0" encoding="utf-8"?>

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
 android:layout_width="fill_parent" android:layout_height="?android:attr/listPreferredItemHeight">
 <ImageView android:id="@+id/listitem_pic"
  android:layout_width="wrap_content" android:layout_height="fill_parent"
  android:layout_alignParentTop="true" android:layout_alignParentBottom="true"
  android:src="@drawable/pic" android:adjustViewBounds="true"
  android:padding="2dip" />
 <TextView android:id="@+id/listitem_title"
  android:layout_width="wrap_content" android:layout_height="wrap_content"
  android:layout_toRightOf="@+id/listitem_pic"
  android:layout_alignParentRight="true" android:layout_alignParentTop="true"
  android:layout_above="@+id/listitem_content"
  android:layout_alignWithParentIfMissing="true" android:gravity="center_vertical"
  android:text="@+id/listitem_title" android:textSize="22px" />
 <TextView android:id="@+id/listitem_content"
  android:layout_width="fill_parent" android:layout_height="wrap_content"
  android:layout_toRightOf="@+id/listitem_pic"
  android:layout_alignParentBottom="true"
  android:layout_alignParentRight="true" android:singleLine="true"
  android:ellipsize="marquee" android:text="@+id/item_content"
  android:textSize="14px" />
</RelativeLayout>
 

2. GridView

SimpleAdapter的核心代码:

  for (int i = 0; i < 10; i++) {
   Map<String, Object> map = new HashMap<String, Object>();
   map.put("PIC", R.drawable.pic);
   map.put("TITLE", "Test Title");
   contents.add(map);
  }
  SimpleAdapter adapter = new SimpleAdapter(this,
    (List<Map<String, Object>>) contents, R.layout.griditem,
    new String[] { "PIC", "TITLE" }, new int[] { R.id.griditem_pic,
      R.id.griditem_title, });

  gridView.setAdapter(adapter);

griditem的Layout:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="
http://schemas.android.com/apk/res/android"
 android:layout_height="fill_parent" android:layout_width="fill_parent"
 android:orientation="vertical">
 <ImageView android:id="@+id/griditem_pic"
  android:layout_width="wrap_content" android:layout_height="wrap_content"
  android:layout_gravity="center_horizontal">
 </ImageView>
 <TextView android:id="@+id/griditem_title"
  android:layout_width="wrap_content" android:layout_height="wrap_content"
  android:layout_gravity="center_horizontal" android:text="test">
 </TextView>
</LinearLayout>

 

9. 调用浏览器 载入某网址
view plaincopy to clipboardprint?
Uri uri = Uri.parse("
http://www.baidu.com");          
Intent it = new Intent(Intent.ACTION_VIEW, uri);          
startActivity(it); 
Uri uri = Uri.parse("
http://www.baidu.com");       
Intent it = new Intent(Intent.ACTION_VIEW, uri);       
startActivity(it);
10.监控应用程序包的安装&删除
方法一:
view plaincopy to clipboardprint?
public class getBroadcast extends BroadcastReceiver {  
        @Override 
        public void onReceive(Context context, Intent intent) {  
                 
                  if(Intent.ACTION_PACKAGE_ADDED.equals(intent.getAction())){  
                    Toast.makeText(context, "有应用被添加", Toast.LENGTH_LONG).show();  
            }  
                else  if(Intent.ACTION_PACKAGE_REMOVED.equals(intent.getAction())){  
                    Toast.makeText(context, "有应用被删除", Toast.LENGTH_LONG).show();  
            }  
               
                else  if(Intent.ACTION_PACKAGE_REPLACED.equals(intent.getAction())){  
                    Toast.makeText(context, "有应用被替换", Toast.LENGTH_LONG).show();  
            }  
                    
                else  if(Intent.ACTION_CAMERA_BUTTON.equals(intent.getAction())){  
                    Toast.makeText(context, "按键", Toast.LENGTH_LONG).show();  
            }  
              
        }  
         

public class getBroadcast extends BroadcastReceiver {
        @Override
        public void onReceive(Context context, Intent intent) {
              
                  if(Intent.ACTION_PACKAGE_ADDED.equals(intent.getAction())){
                    Toast.makeText(context, "有应用被添加", Toast.LENGTH_LONG).show();
            }
                else  if(Intent.ACTION_PACKAGE_REMOVED.equals(intent.getAction())){
                    Toast.makeText(context, "有应用被删除", Toast.LENGTH_LONG).show();
            }
            
                else  if(Intent.ACTION_PACKAGE_REPLACED.equals(intent.getAction())){
                    Toast.makeText(context, "有应用被替换", Toast.LENGTH_LONG).show();
            }
                 
                else  if(Intent.ACTION_CAMERA_BUTTON.equals(intent.getAction())){
                    Toast.makeText(context, "按键", Toast.LENGTH_LONG).show();
            }
           
        }
      
}

需要声明的权限如下AndroidManifest.xml

view plaincopy to clipboardprint?
<?xml version="1.0" encoding="utf-8"?>  
<manifest xmlns:android="
http://schemas.android.com/apk/res/android
      package="zy.Broadcast" 
      android:versionCode="1" 
      android:versionName="1.0">  
    <application android:icon="@drawable/icon" android:label="@string/app_name">  
        <activity android:name=".Broadcast" 
                  android:label="@string/app_name">  
            <intent-filter>  
                <action android:name="android.intent.action.MAIN" />  
                <category android:name="android.intent.category.LAUNCHER" />  
            </intent-filter>  
        </activity>  
      <receiver android:name="getBroadcast" android:enabled="true" >  
         <intent-filter>  
             <action android:name="android.intent.action.PACKAGE_ADDED"></action>  
             <!-- <action android:name="android.intent.action.PACKAGE_CHANGED"></action>-->  
             <action android:name="android.intent.action.PACKAGE_REMOVED"></action>  
             <action android:name="android.intent.action.PACKAGE_REPLACED"></action>  
             <!-- <action android:name="android.intent.action.PACKAGE_RESTARTED"></action>-->  
           <!--    <action android:name="android.intent.action.PACKAGE_INSTALL"></action>-->  
               <action android:name="android.intent.action.CAMERA_BUTTON"></action>  
               <data android:scheme="package"></data>  
              </intent-filter>  
</receiver>  
    </application>  
    <uses-sdk android:minSdkVersion="3" />  
      
</manifest>  
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="
http://schemas.android.com/apk/res/android"
      package="zy.Broadcast"
      android:versionCode="1"
      android:versionName="1.0">
    <application android:icon="@drawable/icon" android:label="@string/app_name">
        <activity android:name=".Broadcast"
                  android:label="@string/app_name">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
      <receiver android:name="getBroadcast" android:enabled="true" >
         <intent-filter>
          <action android:name="android.intent.action.PACKAGE_ADDED"></action>
          <!-- <action android:name="android.intent.action.PACKAGE_CHANGED"></action>-->
          <action android:name="android.intent.action.PACKAGE_REMOVED"></action>
          <action android:name="android.intent.action.PACKAGE_REPLACED"></action>
          <!-- <action android:name="android.intent.action.PACKAGE_RESTARTED"></action>-->
        <!--    <action android:name="android.intent.action.PACKAGE_INSTALL"></action>-->
            <action android:name="android.intent.action.CAMERA_BUTTON"></action>
            <data android:scheme="package"></data>
              </intent-filter>
</receiver>
    </application>
    <uses-sdk android:minSdkVersion="3" />
   
</manifest> 


方法二:
通过阅读Android SDK里关于intent.action这部分里面的描述,我们可以找到一些与package相关的系统广播

view plaincopy to clipboardprint?
android.intent.action.PACKAGE_ADDED      
android.intent.action.PACKAGE_CHANGED      
android.intent.action.PACKAGE_DATA_CLEARED      
android.intent.action.PACKAGE_INSTALL    
android.intent.action.PACKAGE_REMOVED    
android.intent.action.PACKAGE_REPLACED      
android.intent.action.PACKAGE_RESTARTED    
android.intent.action.PACKAGE_ADDED   
android.intent.action.PACKAGE_CHANGED   
android.intent.action.PACKAGE_DATA_CLEARED   
android.intent.action.PACKAGE_INSTALL 
android.intent.action.PACKAGE_REMOVED 
android.intent.action.PACKAGE_REPLACED   
android.intent.action.PACKAGE_RESTARTED   

其中  ACTION_PACKAGE_ADDED   在SDK里的描述是 :

Broadcast Action: A new application package has been installed on the device.

ACTION_PACKAGE_REMOVED       在SDK里的描述是  :

Broadcast Action: An existing application package has been removed from the device.

ACTION_PACKAGE_REPLACED       在SDK里的描述是  :

Broadcast Action: A new version of an application package has been installed, replacing an existing version that was previously installed.

通过这三个广播消息 我们已经可以监控到Android 应用程序的安装和删除
详细的实现代码如下

getBroadcast.java

view plaincopy to clipboardprint?
package zy.Broadcast;  
import android.content.BroadcastReceiver;  
import android.content.Context;  
import android.content.Intent;  
import android.widget.Toast;  
public class getBroadcast extends BroadcastReceiver {  
        @Override  
        public void onReceive(Context context, Intent intent) {  
                 
                  if(Intent.ACTION_PACKAGE_ADDED.equals(intent.getAction())){  
                    Toast.makeText(context, "有应用被添加", Toast.LENGTH_LONG).show();  
            }  
                else  if(Intent.ACTION_PACKAGE_REMOVED.equals(intent.getAction())){  
                    Toast.makeText(context, "有应用被删除", Toast.LENGTH_LONG).show();  
            }  
             /*   else  if(Intent.ACTION_PACKAGE_CHANGED.equals(intent.getAction())){ 
                    Toast.makeText(context, "有应用被改变", Toast.LENGTH_LONG).show(); 
            }*/ 
                else  if(Intent.ACTION_PACKAGE_REPLACED.equals(intent.getAction())){  
                    Toast.makeText(context, "有应用被替换", Toast.LENGTH_LONG).show();  
            }  
               /* else  if(Intent.ACTION_PACKAGE_RESTARTED.equals(intent.getAction())){ 
                    Toast.makeText(context, "有应用被重启", Toast.LENGTH_LONG).show(); 
            }*/ 
              /*  else  if(Intent.ACTION_PACKAGE_INSTALL.equals(intent.getAction())){ 
                    Toast.makeText(context, "有应用被安装", Toast.LENGTH_LONG).show(); 
            }*/ 
              
        }  
         

package zy.Broadcast;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.widget.Toast;
public class getBroadcast extends BroadcastReceiver {
        @Override
        public void onReceive(Context context, Intent intent) {
              
                  if(Intent.ACTION_PACKAGE_ADDED.equals(intent.getAction())){
                    Toast.makeText(context, "有应用被添加", Toast.LENGTH_LONG).show();
            }
                else  if(Intent.ACTION_PACKAGE_REMOVED.equals(intent.getAction())){
                    Toast.makeText(context, "有应用被删除", Toast.LENGTH_LONG).show();
            }
             /*   else  if(Intent.ACTION_PACKAGE_CHANGED.equals(intent.getAction())){
                    Toast.makeText(context, "有应用被改变", Toast.LENGTH_LONG).show();
            }*/
                else  if(Intent.ACTION_PACKAGE_REPLACED.equals(intent.getAction())){
                    Toast.makeText(context, "有应用被替换", Toast.LENGTH_LONG).show();
            }
               /* else  if(Intent.ACTION_PACKAGE_RESTARTED.equals(intent.getAction())){
                    Toast.makeText(context, "有应用被重启", Toast.LENGTH_LONG).show();
            }*/
              /*  else  if(Intent.ACTION_PACKAGE_INSTALL.equals(intent.getAction())){
                    Toast.makeText(context, "有应用被安装", Toast.LENGTH_LONG).show();
            }*/
           
        }
      
}

然后在AndroidManifest.xml中声明这几个Action的<intent-filter>即可在系统里捕获这些广播消息
具体的源代码如下

view plaincopy to clipboardprint?
<?xml version="1.0" encoding="utf-8"?>  
<manifest xmlns:android="
http://schemas.android.com/apk/res/android
      package="zy.Broadcast" 
      android:versionCode="1" 
      android:versionName="1.0">  
    <application android:icon="@drawable/icon" android:label="@string/app_name">  
        <activity android:name=".Broadcast" 
                  android:label="@string/app_name">  
            <intent-filter>  
                <action android:name="android.intent.action.MAIN" />  
                <category android:name="android.intent.category.LAUNCHER" />  
            </intent-filter>  
        </activity>  
      <receiver android:name="getBroadcast" android:enabled="true" >  
         <intent-filter>  
             <action android:name="android.intent.action.PACKAGE_ADDED"></action>  
             <!-- <action android:name="android.intent.action.PACKAGE_CHANGED"></action>-->  
             <action android:name="android.intent.action.PACKAGE_REMOVED"></action>  
             <action android:name="android.intent.action.PACKAGE_REPLACED"></action>  
             <!-- <action android:name="android.intent.action.PACKAGE_RESTARTED"></action>-->  
           <!--    <action android:name="android.intent.action.PACKAGE_INSTALL"></action>-->  
               <data android:scheme="package"></data>  
              </intent-filter>  
</receiver>  
    </application>  
    <uses-sdk android:minSdkVersion="7" />  
      
</manifest>  
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="
http://schemas.android.com/apk/res/android"
      package="zy.Broadcast"
      android:versionCode="1"
      android:versionName="1.0">
    <application android:icon="@drawable/icon" android:label="@string/app_name">
        <activity android:name=".Broadcast"
                  android:label="@string/app_name">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
      <receiver android:name="getBroadcast" android:enabled="true" >
         <intent-filter>
          <action android:name="android.intent.action.PACKAGE_ADDED"></action>
          <!-- <action android:name="android.intent.action.PACKAGE_CHANGED"></action>-->
          <action android:name="android.intent.action.PACKAGE_REMOVED"></action>
          <action android:name="android.intent.action.PACKAGE_REPLACED"></action>
          <!-- <action android:name="android.intent.action.PACKAGE_RESTARTED"></action>-->
        <!--    <action android:name="android.intent.action.PACKAGE_INSTALL"></action>-->
            <data android:scheme="package"></data>
              </intent-filter>
</receiver>
    </application>
    <uses-sdk android:minSdkVersion="7" />
   
</manifest> 

把程序安装之后 ,系统就会注册这个BroadcastReceiver

然后有应用安装删除替换操作时时,就会弹出Toast提示

删除应用

 

添加应用

 

有应用被替换

 

以上这样,我们就可以实现监控Android 应用程序的安装过程

至于拦截安装过程,我也正在研究中,大家有好的idea可以与我 分享,谢谢
11. 使用Toast输出一个字符串
view plaincopy to clipboardprint?
public void DisplayToast(String str)  
        {  
      Toast.makeText(this,str,Toast.LENGTH_SHORT).show();  
        }  
public void DisplayToast(String str)
     {
   Toast.makeText(this,str,Toast.LENGTH_SHORT).show();
     } 


12. 把一个字符串写进文件
view plaincopy to clipboardprint?
public void writefile(String str,String path )  
        {  
            File file;  
            FileOutputStream out;  
             try {  
                 //创建文件  
                 file = new File(path);  
                 file.createNewFile();  
                   
                 //打开文件file的OutputStream  
                 out = new FileOutputStream(file);  
                 String infoToWrite = str;  
                 //将字符串转换成byte数组写入文件  
                 out.write(infoToWrite.getBytes());  
                 //关闭文件file的OutputStream  
                 out.close();  
                   
                   
             } catch (IOException e) {  
                 //将出错信息打印到Logcat  
              DisplayToast(e.toString());  
                   
             }  
        } 
public void writefile(String str,String path )
     {
      File file;
      FileOutputStream out;
       try {
              //创建文件
        file = new File(path);
              file.createNewFile();
             
              //打开文件file的OutputStream
              out = new FileOutputStream(file);
              String infoToWrite = str;
              //将字符串转换成byte数组写入文件
              out.write(infoToWrite.getBytes());
              //关闭文件file的OutputStream
              out.close();
             
             
          } catch (IOException e) {
              //将出错信息打印到Logcat
           DisplayToast(e.toString());
             
          }
     }

13. 把文件内容读出到一个字符串
view plaincopy to clipboardprint?
public String getinfo(String path)  
        {  
            File file;  
            String str="";   
            FileInputStream in;  
         try{  
            //打开文件file的InputStream  
             file = new File(path);  
             in = new FileInputStream(file);  
             //将文件内容全部读入到byte数组  
             int length = (int)file.length();  
             byte[] temp = new byte[length];  
             in.read(temp, 0, length);  
             //将byte数组用UTF-8编码并存入display字符串中  
             str =  EncodingUtils.getString(temp,TEXT_ENCODING);  
             //关闭文件file的InputStream  
               
             in.close();  
         }  
         catch (IOException e) {  
               
          DisplayToast(e.toString());  
               
         }  
         return str;  
        } 
public String getinfo(String path)
     {
      File file;
      String str="";
      FileInputStream in;
      try{
      //打开文件file的InputStream
       file = new File(path);
          in = new FileInputStream(file);
          //将文件内容全部读入到byte数组
          int length = (int)file.length();
          byte[] temp = new byte[length];
          in.read(temp, 0, length);
          //将byte数组用UTF-8编码并存入display字符串中
          str =  EncodingUtils.getString(temp,TEXT_ENCODING);
          //关闭文件file的InputStream
         
          in.close();
      }
      catch (IOException e) {
         
       DisplayToast(e.toString());
         
      }
      return str;
     }

14. 调用Android installer 安装和卸载程序
view plaincopy to clipboardprint?
Intent intent = new Intent(Intent.ACTION_VIEW);   
       intent.setDataAndType(Uri.fromFile(new File("/sdcard/WorldCupTimer.apk")), "application/vnd.android.package-archive");   
       startActivity(intent); //安装 程序  
         
       Uri packageURI = Uri.parse("package:zy.dnh");       
       Intent uninstallIntent = new Intent(Intent.ACTION_DELETE, packageURI);       
       startActivity(uninstallIntent);//正常卸载程序 
 Intent intent = new Intent(Intent.ACTION_VIEW);
        intent.setDataAndType(Uri.fromFile(new File("/sdcard/WorldCupTimer.apk")), "application/vnd.android.package-archive");
        startActivity(intent); //安装 程序
       
        Uri packageURI = Uri.parse("package:zy.dnh");    
        Intent uninstallIntent = new Intent(Intent.ACTION_DELETE, packageURI);    
        startActivity(uninstallIntent);//正常卸载程序

15. 结束某个进程
view plaincopy to clipboardprint?
activityManager.restartPackage(packageName); 
activityManager.restartPackage(packageName);
16. 设置默认来电铃声
view plaincopy to clipboardprint?
public void setMyRingtone()  
    {  
   File k = new File("/sdcard/Shall We Talk.mp3"); // 设置歌曲路径  
    ContentValues values = new ContentValues();  
    values.put(MediaStore.MediaColumns.DATA, k.getAbsolutePath());  
    values.put(MediaStore.MediaColumns.TITLE, "Shall We Talk");  
    values.put(MediaStore.MediaColumns.SIZE, 8474325);  
    values.put(MediaStore.MediaColumns.MIME_TYPE, "audio/mp3");  
    values.put(MediaStore.Audio.Media.ARTIST, "Madonna");  
    values.put(MediaStore.Audio.Media.DURATION, 230);  
    values.put(MediaStore.Audio.Media.IS_RINGTONE, true);  
    values.put(MediaStore.Audio.Media.IS_NOTIFICATION, false);  
    values.put(MediaStore.Audio.Media.IS_ALARM, false);  
    values.put(MediaStore.Audio.Media.IS_MUSIC, false);  
    // Insert it into the database  
    Uri uri = MediaStore.Audio.Media.getContentUriForPath(k.getAbsolutePath());  
    Uri newUri = this.getContentResolver().insert(uri, values);  
    RingtoneManager.setActualDefaultRingtoneUri(this, RingtoneManager.TYPE_RINGTONE, newUri);  
    ;} 
public void setMyRingtone()
    {
   File k = new File("/sdcard/Shall We Talk.mp3"); // 设置歌曲路径
    ContentValues values = new ContentValues();
    values.put(MediaStore.MediaColumns.DATA, k.getAbsolutePath());
    values.put(MediaStore.MediaColumns.TITLE, "Shall We Talk");
    values.put(MediaStore.MediaColumns.SIZE, 8474325);
    values.put(MediaStore.MediaColumns.MIME_TYPE, "audio/mp3");
    values.put(MediaStore.Audio.Media.ARTIST, "Madonna");
    values.put(MediaStore.Audio.Media.DURATION, 230);
    values.put(MediaStore.Audio.Media.IS_RINGTONE, true);
    values.put(MediaStore.Audio.Media.IS_NOTIFICATION, false);
    values.put(MediaStore.Audio.Media.IS_ALARM, false);
    values.put(MediaStore.Audio.Media.IS_MUSIC, false);
    // Insert it into the database
    Uri uri = MediaStore.Audio.Media.getContentUriForPath(k.getAbsolutePath());
    Uri newUri = this.getContentResolver().insert(uri, values);
    RingtoneManager.setActualDefaultRingtoneUri(this, RingtoneManager.TYPE_RINGTONE, newUri);
    ;}

需要的权限

view plaincopy to clipboardprint?
<uses-permission android:name="android.permission.WRITE_SETTINGS"></uses-permission>
17. 开机自启动
1. 定义一个BroadcastReceiver
代码:

public class BootReceiver extends BroadcastReceiver {   
    public void onReceive(Context ctx, Intent intent) {   
        Log.d("BootReceiver", "system boot completed");   
        //start activity   
        String action="android.intent.action.MAIN";   
        String category="android.intent.category.LAUNCHER";   
        Intent myi=new Intent(ctx,CustomDialog.class);   
        myi.setAction(action);   
        myi.addCategory(category);   
        myi.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);   
        ctx.startActivity(myi);   
        //start service   
        Intent s=new Intent(ctx,MyService.class);   
        ctx.startService(s);   
    }   
}

2. 配置Receiver的许可,允许接收系统启动消息,在AndroidManifest.xml中:

1. <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>  


2. 配置Receiver,可以接收系统启动消息,在AndroidManifest.xml中

1. <receiver android:name=".app.BootReceiver">  
2.     <intent-filter>  
3.         <action android:name="android.intent.action.BOOT_COMPLETED"/>  
4.         <category android:name="android.intent.category.HOME" />  
5.     </intent-filter>  
6. </receiver>

3. 启动模拟器,可以看到系统启动后,弹出一个对话框。
18. 线程与子线程
在一个Android 程序开始运行的时候,会单独启动一个Process。默认的情况下,所有这个程序中的Activity或者Service(Service和Activity只是Android提供的Components中的两种,除此之外还有Content Provider和Broadcast Receiver)都会跑在这个Process。

        一个Android 程序默认情况下也只有一个Process,但一个Process下却可以有许多个Thread。
  
       在这么多Thread当中,有一个Thread,我们称之为UI Thread。UI Thread在Android程序运行的时候就被创建,是一个Process当中的主线程Main Thread,主要是负责控制UI界面的显示、更新和控件交互。在Android程序创建之初,一个Process呈现的是单线程模型,所有的任务都在一个线程中运行。因此,我们认为,UI Thread所执行的每一个函数,所花费的时间都应该是越短越好。而其他比较费时的工作(访问网络,下载数据,查询数据库等),都应该交由子线程去执行,以免阻塞主线程。

        那么,UI Thread如何和其他Thread一起工作呢?常用方法是:

        诞生一个主线程的Handler物件,当做Listener去让子线程能将讯息Push到主线程的Message Quene里,以便触发主线程的handlerMessage()函数,让主线程知道子线程的状态,并在主线程更新UI。

handlerMessage实例
       例如,在子线程的状态发生变化时,我们需要更新UI。如果在子线程中直接更新UI,通常会抛出下面的异常:
  
11-07 13:33:04.393: ERROR/JavaBinder(1029):android.view.ViewRoot$CalledFromWrongThreadException:Only the original thread that created a view hierarchy can touch its views.

       意思是,无法在子线程中更新UI。为此,我们需要通过Handler物件,通知主线程Ui Thread来更新界面。

        如下,首先创建一个Handler,来监听Message的事件:( 以两个事件为例)

       private final int UPDATE_UIONE= 1;
private final int UPDATE_UITWO = 2;

       private Handler mHandler = new MainHandler();
    
      private class MainHandler extends Handler {
         @Override
             public void handleMessage(Message msg) {
             switch (msg.what) {
                 case UPDATE_UIONE: {  
    //这里可以放很多东西, 比如创建某个进度框线程, 执行完成需要取消进度框的显示, 可以发送一个消息, 然后这里就监听到了, 在这里将进度框取消掉, 还可以dispalyToast, 弹出对话框等等…..而这些在子线程中是无法使用的
                Log.i("TTSDeamon", "UPDATE_UIONE");
                showTextView.setText(editText.getText().toString());
                ShowAnimation();
                     break;
                 }
case UPDATE_UITWO: {
//执行某些命令
                     break;
                 }

                 default:
                     break;
             }
         }
       };

     或者

      private Handler mHandler = new Handler(){
         @Override
             public void handleMessage(Message msg) {
             switch (msg.what) {
                 case UPDATE_UIONE: {
                Log.i("TTSDeamon", "UPDATE_UIONE");
                showTextView.setText(editText.getText().toString());
                ShowAnimation();
                     break;
                 }
case UPDATE_UITWO: {
//执行某些命令
                     break;
                 }

                 default:
                     break;
             }
          }
      };

       当子线程的状态发生变化,则在子线程中发出Message,通知更新UI。不同消息响应不同操作.

       mHandler.sendEmptyMessageDelayed(UPDATE_UIONE, 0);

  mHandler.sendEmptyMessageDelayed(UPDATE_UITWO, 0);

      在我们的程序中,很多Callback方法有时候并不是运行在主线程当中的,所以如果在Callback方法中更新UI失败,也可以采用上面的方法。
19. Service
1. 什么是Service
Service,看名字就知道跟正常理解的“服务”差不多,后台运行,可交互这样的一个东西。它跟Activity的级别差不多,但是他不能自己运行,需要通过某一个Activity或者其他Context对象来调用, Context.startService() 和 Context.bindService()。

两种启动Service的方式有所不同。这里要说明一下的是如果你在Service的onCreate或者onStart做一些很耗时间的事情,最好在 Service里启动一个线程来完成,因为Service是跑在主线程中,会影响到你的UI操作或者阻塞主线程中的其他事情。

什么时候需要Service呢?比如播放多媒体的时候用户启动了其他Activity这个时候程序要在后台继续播放,比如检测SD卡上文件的变化,再或者在后台记录你地理信息位置的改变等等,总之服务嘛,总是藏在后头的。
2. 如何使用Service
那接下来用代码来说明一下怎么使用Service,这里我们要讲的是Local Service也就是你自己的一个Service, 你也可以操作别的应用程序的service如果它允许你那么去做的话,这就设计到一个比较麻烦的东西interprocess communication (IPC),在不同的进程中通信的机制,这个我自己也还没有用过,等用了以后再跟大伙说说,通常情况下Local的就够用啦。

跟Activity一样首先你要写一个类继承自android.app.Service,在这里我叫他TestService
代码如下:


package com.haric.tutorial;

import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;
import android.util.Log;

public class TestService extends Service {
private static final String TAG = "TestService";
private NotificationManager _nm;

@Override
public IBinder onBind(Intent i) {
Log.e(TAG, "============> TestService.onBind");
return null;
}

public class LocalBinder extends Binder {
TestService getService() {
return TestService.this;
}
}

@Override
public boolean onUnbind(Intent i) {
Log.e(TAG, "============> TestService.onUnbind");
return false;
}

@Override
public void onRebind(Intent i) {
Log.e(TAG, "============> TestService.onRebind");
}

@Override
public void onCreate() {
Log.e(TAG, "============> TestService.onCreate");
_nm = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
showNotification();
}

@Override
public void onStart(Intent intent, int startId) {
Log.e(TAG, "============> TestService.onStart");
}

@Override
public void onDestroy() {
_nm.cancel(R.string.service_started);
Log.e(TAG, "============> TestService.onDestroy");
}

private void showNotification() {
Notification notification = new Notification(R.drawable.face_1,
"Service started", System.currentTimeMillis());

PendingIntent contentIntent = PendingIntent.getActivity(this, 0,
new Intent(this, TestServiceHolder.class), 0);

// must set this for content view, or will throw a exception
notification.setLatestEventInfo(this, "Test Service",
"Service started", contentIntent);

_nm.notify(R.string.service_started, notification);
}
}

其中用到Notification是为了明显地表明Service存活的状态,跟demo的code学过来的,这样看上去直观一点,更多关于Notification的内容以后UI部分来写吧,现在就知道怎么使用就好了。

@Override
public void onCreate() {
Log.e(TAG, "============> TestService.onCreate");
_nm = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
showNotification();
}

像这样,我在Service的几个生命周期函数中加了打印log的语句,方便测试。

public class LocalBinder extends Binder {
TestService getService() {
return TestService.this;
}
}

这个方法是为了让调用者得到这个Service并操作它。
Service本身就这样简单了,你需要做什么就在onCreate和onStart里做好了,起个线程什么的。

再看一下它的调用者,TestServiceHolder

package com.haric.tutorial;

import android.app.Activity;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.Toast;

public class TestServiceHolder extends Activity {
private boolean _isBound;
private TestService _boundService;

public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.test_service_holder);
setTitle("Service Test");

initButtons();
}

private ServiceConnection _connection = new ServiceConnection() {
public void onServiceConnected(ComponentName className, IBinder service) {
_boundService = ((TestService.LocalBinder)service).getService();

Toast.makeText(TestServiceHolder.this, "Service connected",
Toast.LENGTH_SHORT).show();
}

public void onServiceDisconnected(ComponentName className) {
// unexpectedly disconnected,we should never see this happen.
_boundService = null;
Toast.makeText(TestServiceHolder.this, "Service connected",
Toast.LENGTH_SHORT).show();
}
};

private void initButtons() {
Button buttonStart = (Button) findViewById(R.id.start_service);
buttonStart.setOnClickListener(new OnClickListener() {
public void onClick(View arg0) {
startService();
}
});

Button buttonStop = (Button) findViewById(R.id.stop_service);
buttonStop.setOnClickListener(new OnClickListener() {
public void onClick(View arg0) {
stopService();
}
});

Button buttonBind = (Button) findViewById(R.id.bind_service);
buttonBind.setOnClickListener(new OnClickListener() {
public void onClick(View arg0) {
bindService();
}
});

Button buttonUnbind = (Button) findViewById(R.id.unbind_service);
buttonUnbind.setOnClickListener(new OnClickListener() {
public void onClick(View arg0) {
unbindService();
}
});
}

private void startService() {
Intent i = new Intent(this, TestService.class);
this.startService(i);
}

private void stopService() {
Intent i = new Intent(this, TestService.class);
this.stopService(i);
}

private void bindService() {
Intent i = new Intent(this, TestService.class);
bindService(i, _connection, Context.BIND_AUTO_CREATE);
_isBound = true;
}

private void unbindService() {
if (_isBound) {
unbindService(_connection);
_isBound = false;
}
}
}

这里可以看到两种启动方法,start和bind,当然也是通过intent调用的,在intent中指明指定要启动的Service的名字,stop也一样 :

private void startService() {
Intent i = new Intent(this, TestService.class);
this.startService(i);
}

private void stopService() {
Intent i = new Intent(this, TestService.class);
this.stopService(i);
}

对于bind的话,需要一个ServiceConnection对象

private ServiceConnection _connection = new ServiceConnection() {
public void onServiceConnected(ComponentName className, IBinder service) {
_boundService = ((TestService.LocalBinder)service).getService();

Toast.makeText(TestServiceHolder.this, "Service connected",
Toast.LENGTH_SHORT).show();
}

public void onServiceDisconnected(ComponentName className) {
// unexpectedly disconnected,we should never see this happen.
_boundService = null;
Toast.makeText(TestServiceHolder.this, "Service connected",
Toast.LENGTH_SHORT).show();
}
};

用来把Activity和特定的Service连接在一起,共同存亡,具体的生命周期细节下一段来讲。
3. Service的生命周期
Service的生命周期方法比Activity少一些,只有onCreate, onStart, onDestroy
我们有两种方式启动一个Service,他们对Service生命周期的影响是不一样的。

1 通过startService

    Service会经历 onCreate -> onStart
   stopService的时候直接onDestroy

   如果是调用者(TestServiceHolder)自己直接退出而没有调用stopService的
   话,Service会一直在后台运行。
   下次TestServiceHolder再起来可以stopService。

2 通过bindService   

    Service只会运行onCreate, 这个时候 TestServiceHolder 和TestService绑定在一起

   TestServiceHolder 退出了,Srevice就会调用onUnbind->onDestroyed
   所谓绑定在一起就共存亡了。

那有同学问了,要是这几个方法交织在一起的话,会出现什么情况呢?
一个原则是Service的onCreate的方法只会被调用一次,就是你无论多少次的startService又 bindService,Service只被创建一次。如果先是bind了,那么start的时候就直接运行Service的onStart方法,如果先 是start,那么bind的时候就直接运行onBind方法。如果你先bind上了,就stop不掉了,对啊,就是stopService不好使了,只 能先UnbindService, 再StopService,所以是先start还是先bind行为是有区别的。
附) 常用界面截图:
提示1
 
提示2
 
菜单
 

                                          

查看全文
如若内容造成侵权/违法违规/事实不符,请联系编程学习网邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!

相关文章

  1. 代码整洁之道(一)

    代码整洁之道(一)2017-11-07至2017-11-08前言我为什么会想买这本书??理由很模糊,却又很简单——为了更加简洁优美的代码。然而简洁优美的代码总是很少的,至少在我目前完成的一些项目中,无论是我还是队友,对于代码的整洁与规范都没有一个明确的认识,这也是我所厌恶的现…...

    2024/4/17 7:17:00
  2. 只有在中华帝都才能免费享受到的北大商业课程:财富定律与愿景规划

    如果你不在北京,只能说可惜了。这样的讲座,本来是很贵的商业课程。但到了北大,就变成了免费的公益课。本课程主题是愿景规划,说白了本质是项目管理。你可以看到其实新理论都是旧理论在不同领域发展的结果。主题:财富定律与愿景规划公开课时间:2014年11月2日19:00-22:00,…...

    2024/5/6 9:27:54
  3. 后端权限管理系统

    简介:后台多模块权限管理系统,适用于多场景满足于企业定制化需求。 内置模块如:部门管理、角色用户、菜单及按钮授权、数据权限、系统参数、日志管理、通知公告等。在线定时任务配置;支持集群,支持多数据源。后台演示地址: http://www.ruoyi.vip账号:admin密码:admin12…...

    2024/4/28 4:38:49
  4. 技术入股创业注意事项

    技术入股创业注意事项技术入股的教训(亲身感受):1、技术跟资本合作,千万不要拿低工资,要不项目做成功或者不成功,做技术的可能都是颗粒无收。既然跟资本合作,工资按市面上的算,市面1w就1w,2w就2w,如果对方说,前面没有利润,能不能工资低点什么的,可以少点,但是不能…...

    2024/4/17 7:17:00
  5. 后台权限管理系统 spring+springmvc+shiro

    https://gitee.com/y_project/RuoYi...

    2024/4/17 7:16:42
  6. 比特股(BitShares)白皮书

    摘要一个理想自由市场金融体系(Ideal Free Market Financial System ,IFMFS)应当允许参与各方在最小化风险和成本的前提下,对价值进行存储、交易和转让。在基于比特币首次所提出具有开创性的开源协议之上1,我们进行了改进和扩展,重新定义了一个新的名为比特股(BitShares…...

    2024/5/6 9:04:21
  7. BASE64基本使用

    BASE64中BASE64Encoder、BASE64Decoder,在做一些参数传递的时候用过,在此做个备份package utils;import java.io.IOException; import sun.misc.BASE64Decoder; import sun.misc.BASE64Encoder;/*** * @author 画一**/ public class MainTest {public static void main(Strin…...

    2024/4/19 13:48:24
  8. 漫谈anroid软件设计中的contentprovider及其应用

    一.概述:ContentProvider汉语为内容提供器,又叫数据内容提供器,差不多一个意思吧,因为他是android应用程序间非常通用的共享数据的一种方式。是推荐的应用程序间共享数据的一种方式。android中许多系统软件和应用软件都使用该方式实现数据共享,比如电话本,相片,音乐,短…...

    2024/4/17 7:16:54
  9. 找不到或无法加载主类

    springboot项目时不时的就会出现这个错误, 错误: 找不到或无法加载主类 com.ruoyi.RuoYiApplication 解决方案: 自己在maven clean之后,会把target里边的清理表,项目就需要重新进行编译,这时候如果运行的话就会出现以上错误,在运行项目之前,需要maven install一下即可。…...

    2024/5/6 7:20:37
  10. 大白话讲解word2vec到底在做些什么

    向AI转型的程序员都关注了这个号👇👇👇大数据挖掘DT机器学习 公众号: datayx词向量word2vec也叫word embeddings,中文名“词向量”,作用就是将自然语言中的字词转为计算机可以理解的稠密向量(Dense Vector)。在word2vec出现之前,自然语言处理经常把字词转为离散的…...

    2024/4/17 7:17:54
  11. 2018年个人成长总结及2019年个人成长计划

    2018年是国家值得纪念的一年,因为2018年是改革开放40周年,虽然并未完全经历改革的四十年,好歹我也为祖国奋斗了6年;这些年的变化实在是太大了,明显感受到了祖国的强大、经济的发展、法制的健全、人民的幸福、社会的安定,各行各业都取得了举世瞩目的成就。与我个人来说,2…...

    2024/5/6 8:34:11
  12. 怎样维护ERP,ERP维护需要具备什么知识?

    ERP维护工作主要有这些:<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />1.用户权限管理(新增用户权限、权限变更、权限禁用)2.业务流程管理(协助业务部门制定相应ERP业务流程,主要是业务流程维护方面的作)3.公司ERP文档完善(…...

    2024/5/6 6:46:05
  13. MD5 AES Des 加密解密

    MD5加密不可逆 只能加密,不能解密,代码如下: package com.ruoyi.common.utils.security;import java.security.MessageDigest;import org.slf4j.Logger;import org.slf4j.LoggerFactory;/** * Md5加密方法 * * @author ruoyi */public class Md5Utils{ private static f…...

    2024/4/18 17:46:28
  14. Web 图片Base64编码

    转载自: 【前端攻略】:玩转图片Base64编码引言  图片处理在前端工作中可谓占据了很重要的一壁江山。而图片的 base64 编码可能相对一些人而言比较陌生,本文不是从纯技术的角度去讨论图片的 base64 编码。标题略大,不过只是希望通过一些浅显的论述,让你知道什么是图片的 b…...

    2024/4/17 7:20:00
  15. 两分钟读懂《从0到1》——《从0到1》读书笔记

    Some ideas can’t wait!(好主意不应等待)一些好的创意是无法等待的,如果想到一个好的idea没有去验证,那么等于没有idea。互联网如今的商业思维就是快速试错、快速迭代、快速验证自己的想法。这也就是为什么创业公司能够灵活机动的根本原因,失去了这一点,创业公司是无法直…...

    2024/4/17 7:19:00
  16. 《与大象共舞》读书笔记

    《与大象共舞》读书笔记这本书的副标题是《和IBM学转型》。但这本书的本质不是说转型的,而是说转型所必备的前提基础,没有这些基础是不可能转型成功的。不是你想转就能转的。但这本书介绍的转型前提基础其实也不是转型所必备的前提基础,而是一个企业运营必备的前提基础框架。…...

    2024/4/19 8:53:18
  17. android 中管理短信

    android 中管理短信为了看代码方便,一边在网上google资料,一边看Android java 源代码。 偶然发现了一个类MmsSmsDatabaseHelper.java,原来android将所有的短信信息都存入了mmssms.db中。 公开的SDK中没有这个类,不能直接使用。于是自己写了一个SQLiteOpenHelper,但是查询的…...

    2024/4/17 7:18:06
  18. jexus 加载 spring boot

    jexus 对应的 配置port=9001 root=/ /var/www/java/ruoyi hosts=* #OR your.com,*.your.comAppHost={cmd=java -jar ruoyi-admin.jar;root=/var/www/java/ruoyi;Port=9002;}启动jexus运行效果注: jexus 配置及其 操作 请查看以下 链接https://blog.csdn.net/MeGoodtoo/arti…...

    2024/4/17 7:17:42
  19. 团队项目计划、人员安排以及开发方法

    一个项目,应需要而产生;项目成员,应项目而聚集,组建成团队。项目的各项任务依靠项目团队得以完成。因此项目团队建设的科学、高效是项目管理成功的关键。 此处以手游下载app tap为例。一、项目开发目的:手机游戏行业发展迅速,人们对生活质量的要求越来越高,对娱乐方面的…...

    2024/4/20 0:11:25
  20. js blob流和base64,以及file和base64的相互转换

    file和base64file文件转换为base64,得到base64格式图片var reader = new FileReader(); reader.readAsDataURL(this.files[0]); reader.onload = function(){console.log(reader.result); //获取到base64格式图片 };base64转换为filefunction dataURLtoFile(dataurl, filename…...

    2024/4/18 0:05:37

最新文章

  1. 什么是模版方法模式,有哪些应用?

    模板方法模式是一种行为设计模式&#xff0c;他的主要作用就是复用代码。在很多时候&#xff0c;我们的代码中可能会有-些公共的部分并且还有一些定制的部分&#xff0c;那么公共这部分就可以定义在一个父类中&#xff0c;然后将定制的部分实现在子类中。这样子类可以根据需要扩…...

    2024/5/6 17:03:17
  2. 梯度消失和梯度爆炸的一些处理方法

    在这里是记录一下梯度消失或梯度爆炸的一些处理技巧。全当学习总结了如有错误还请留言&#xff0c;在此感激不尽。 权重和梯度的更新公式如下&#xff1a; w w − η ⋅ ∇ w w w - \eta \cdot \nabla w ww−η⋅∇w 个人通俗的理解梯度消失就是网络模型在反向求导的时候出…...

    2024/5/6 9:38:23
  3. Mybatis--TypeHandler使用手册

    TypeHandler使用手册 场景&#xff1a;想保存user时 teacher自动转String &#xff0c;不想每次保存都要手动去转String&#xff1b;从DB查询出来时&#xff0c;也要自动帮我们转换成Java对象 Teacher Data public class User {private Integer id;private String name;priva…...

    2024/5/5 8:28:12
  4. uniApp使用XR-Frame创建3D场景(7)加入点击交互

    上篇文章讲述了如何将XR-Frame作为子组件集成到uniApp中使用 这篇我们讲解如何与场景中的模型交互&#xff08;点击识别&#xff09; 先看源码 <xr-scene render-system"alpha:true" bind:ready"handleReady"><xr-node><xr-mesh id"…...

    2024/5/6 9:22:15
  5. 【外汇早评】美通胀数据走低,美元调整

    原标题:【外汇早评】美通胀数据走低,美元调整昨日美国方面公布了新一期的核心PCE物价指数数据,同比增长1.6%,低于前值和预期值的1.7%,距离美联储的通胀目标2%继续走低,通胀压力较低,且此前美国一季度GDP初值中的消费部分下滑明显,因此市场对美联储后续更可能降息的政策…...

    2024/5/4 23:54:56
  6. 【原油贵金属周评】原油多头拥挤,价格调整

    原标题:【原油贵金属周评】原油多头拥挤,价格调整本周国际劳动节,我们喜迎四天假期,但是整个金融市场确实流动性充沛,大事频发,各个商品波动剧烈。美国方面,在本周四凌晨公布5月份的利率决议和新闻发布会,维持联邦基金利率在2.25%-2.50%不变,符合市场预期。同时美联储…...

    2024/5/4 23:54:56
  7. 【外汇周评】靓丽非农不及疲软通胀影响

    原标题:【外汇周评】靓丽非农不及疲软通胀影响在刚结束的周五,美国方面公布了新一期的非农就业数据,大幅好于前值和预期,新增就业重新回到20万以上。具体数据: 美国4月非农就业人口变动 26.3万人,预期 19万人,前值 19.6万人。 美国4月失业率 3.6%,预期 3.8%,前值 3…...

    2024/5/4 23:54:56
  8. 【原油贵金属早评】库存继续增加,油价收跌

    原标题:【原油贵金属早评】库存继续增加,油价收跌周三清晨公布美国当周API原油库存数据,上周原油库存增加281万桶至4.692亿桶,增幅超过预期的74.4万桶。且有消息人士称,沙特阿美据悉将于6月向亚洲炼油厂额外出售更多原油,印度炼油商预计将每日获得至多20万桶的额外原油供…...

    2024/5/6 9:21:00
  9. 【外汇早评】日本央行会议纪要不改日元强势

    原标题:【外汇早评】日本央行会议纪要不改日元强势近两日日元大幅走强与近期市场风险情绪上升,避险资金回流日元有关,也与前一段时间的美日贸易谈判给日本缓冲期,日本方面对汇率问题也避免继续贬值有关。虽然今日早间日本央行公布的利率会议纪要仍然是支持宽松政策,但这符…...

    2024/5/4 23:54:56
  10. 【原油贵金属早评】欧佩克稳定市场,填补伊朗问题的影响

    原标题:【原油贵金属早评】欧佩克稳定市场,填补伊朗问题的影响近日伊朗局势升温,导致市场担忧影响原油供给,油价试图反弹。此时OPEC表态稳定市场。据消息人士透露,沙特6月石油出口料将低于700万桶/日,沙特已经收到石油消费国提出的6月份扩大出口的“适度要求”,沙特将满…...

    2024/5/4 23:55:05
  11. 【外汇早评】美欲与伊朗重谈协议

    原标题:【外汇早评】美欲与伊朗重谈协议美国对伊朗的制裁遭到伊朗的抗议,昨日伊朗方面提出将部分退出伊核协议。而此行为又遭到欧洲方面对伊朗的谴责和警告,伊朗外长昨日回应称,欧洲国家履行它们的义务,伊核协议就能保证存续。据传闻伊朗的导弹已经对准了以色列和美国的航…...

    2024/5/4 23:54:56
  12. 【原油贵金属早评】波动率飙升,市场情绪动荡

    原标题:【原油贵金属早评】波动率飙升,市场情绪动荡因中美贸易谈判不安情绪影响,金融市场各资产品种出现明显的波动。随着美国与中方开启第十一轮谈判之际,美国按照既定计划向中国2000亿商品征收25%的关税,市场情绪有所平复,已经开始接受这一事实。虽然波动率-恐慌指数VI…...

    2024/5/4 23:55:16
  13. 【原油贵金属周评】伊朗局势升温,黄金多头跃跃欲试

    原标题:【原油贵金属周评】伊朗局势升温,黄金多头跃跃欲试美国和伊朗的局势继续升温,市场风险情绪上升,避险黄金有向上突破阻力的迹象。原油方面稍显平稳,近期美国和OPEC加大供给及市场需求回落的影响,伊朗局势并未推升油价走强。近期中美贸易谈判摩擦再度升级,美国对中…...

    2024/5/4 23:54:56
  14. 【原油贵金属早评】市场情绪继续恶化,黄金上破

    原标题:【原油贵金属早评】市场情绪继续恶化,黄金上破周初中国针对于美国加征关税的进行的反制措施引发市场情绪的大幅波动,人民币汇率出现大幅的贬值动能,金融市场受到非常明显的冲击。尤其是波动率起来之后,对于股市的表现尤其不安。隔夜美国股市出现明显的下行走势,这…...

    2024/5/6 1:40:42
  15. 【外汇早评】美伊僵持,风险情绪继续升温

    原标题:【外汇早评】美伊僵持,风险情绪继续升温昨日沙特两艘油轮再次发生爆炸事件,导致波斯湾局势进一步恶化,市场担忧美伊可能会出现摩擦生火,避险品种获得支撑,黄金和日元大幅走强。美指受中美贸易问题影响而在低位震荡。继5月12日,四艘商船在阿联酋领海附近的阿曼湾、…...

    2024/5/4 23:54:56
  16. 【原油贵金属早评】贸易冲突导致需求低迷,油价弱势

    原标题:【原油贵金属早评】贸易冲突导致需求低迷,油价弱势近日虽然伊朗局势升温,中东地区几起油船被袭击事件影响,但油价并未走高,而是出于调整结构中。由于市场预期局势失控的可能性较低,而中美贸易问题导致的全球经济衰退风险更大,需求会持续低迷,因此油价调整压力较…...

    2024/5/4 23:55:17
  17. 氧生福地 玩美北湖(上)——为时光守候两千年

    原标题:氧生福地 玩美北湖(上)——为时光守候两千年一次说走就走的旅行,只有一张高铁票的距离~ 所以,湖南郴州,我来了~ 从广州南站出发,一个半小时就到达郴州西站了。在动车上,同时改票的南风兄和我居然被分到了一个车厢,所以一路非常愉快地聊了过来。 挺好,最起…...

    2024/5/4 23:55:06
  18. 氧生福地 玩美北湖(中)——永春梯田里的美与鲜

    原标题:氧生福地 玩美北湖(中)——永春梯田里的美与鲜一觉醒来,因为大家太爱“美”照,在柳毅山庄去寻找龙女而错过了早餐时间。近十点,向导坏坏还是带着饥肠辘辘的我们去吃郴州最富有盛名的“鱼头粉”。说这是“十二分推荐”,到郴州必吃的美食之一。 哇塞!那个味美香甜…...

    2024/5/4 23:54:56
  19. 氧生福地 玩美北湖(下)——奔跑吧骚年!

    原标题:氧生福地 玩美北湖(下)——奔跑吧骚年!让我们红尘做伴 活得潇潇洒洒 策马奔腾共享人世繁华 对酒当歌唱出心中喜悦 轰轰烈烈把握青春年华 让我们红尘做伴 活得潇潇洒洒 策马奔腾共享人世繁华 对酒当歌唱出心中喜悦 轰轰烈烈把握青春年华 啊……啊……啊 两…...

    2024/5/4 23:55:06
  20. 扒开伪装医用面膜,翻六倍价格宰客,小姐姐注意了!

    原标题:扒开伪装医用面膜,翻六倍价格宰客,小姐姐注意了!扒开伪装医用面膜,翻六倍价格宰客!当行业里的某一品项火爆了,就会有很多商家蹭热度,装逼忽悠,最近火爆朋友圈的医用面膜,被沾上了污点,到底怎么回事呢? “比普通面膜安全、效果好!痘痘、痘印、敏感肌都能用…...

    2024/5/5 8:13:33
  21. 「发现」铁皮石斛仙草之神奇功效用于医用面膜

    原标题:「发现」铁皮石斛仙草之神奇功效用于医用面膜丽彦妆铁皮石斛医用面膜|石斛多糖无菌修护补水贴19大优势: 1、铁皮石斛:自唐宋以来,一直被列为皇室贡品,铁皮石斛生于海拔1600米的悬崖峭壁之上,繁殖力差,产量极低,所以古代仅供皇室、贵族享用 2、铁皮石斛自古民间…...

    2024/5/4 23:55:16
  22. 丽彦妆\医用面膜\冷敷贴轻奢医学护肤引导者

    原标题:丽彦妆\医用面膜\冷敷贴轻奢医学护肤引导者【公司简介】 广州华彬企业隶属香港华彬集团有限公司,专注美业21年,其旗下品牌: 「圣茵美」私密荷尔蒙抗衰,产后修复 「圣仪轩」私密荷尔蒙抗衰,产后修复 「花茵莳」私密荷尔蒙抗衰,产后修复 「丽彦妆」专注医学护…...

    2024/5/4 23:54:58
  23. 广州械字号面膜生产厂家OEM/ODM4项须知!

    原标题:广州械字号面膜生产厂家OEM/ODM4项须知!广州械字号面膜生产厂家OEM/ODM流程及注意事项解读: 械字号医用面膜,其实在我国并没有严格的定义,通常我们说的医美面膜指的应该是一种「医用敷料」,也就是说,医用面膜其实算作「医疗器械」的一种,又称「医用冷敷贴」。 …...

    2024/5/4 23:55:01
  24. 械字号医用眼膜缓解用眼过度到底有无作用?

    原标题:械字号医用眼膜缓解用眼过度到底有无作用?医用眼膜/械字号眼膜/医用冷敷眼贴 凝胶层为亲水高分子材料,含70%以上的水分。体表皮肤温度传导到本产品的凝胶层,热量被凝胶内水分子吸收,通过水分的蒸发带走大量的热量,可迅速地降低体表皮肤局部温度,减轻局部皮肤的灼…...

    2024/5/4 23:54:56
  25. 配置失败还原请勿关闭计算机,电脑开机屏幕上面显示,配置失败还原更改 请勿关闭计算机 开不了机 这个问题怎么办...

    解析如下&#xff1a;1、长按电脑电源键直至关机&#xff0c;然后再按一次电源健重启电脑&#xff0c;按F8健进入安全模式2、安全模式下进入Windows系统桌面后&#xff0c;按住“winR”打开运行窗口&#xff0c;输入“services.msc”打开服务设置3、在服务界面&#xff0c;选中…...

    2022/11/19 21:17:18
  26. 错误使用 reshape要执行 RESHAPE,请勿更改元素数目。

    %读入6幅图像&#xff08;每一幅图像的大小是564*564&#xff09; f1 imread(WashingtonDC_Band1_564.tif); subplot(3,2,1),imshow(f1); f2 imread(WashingtonDC_Band2_564.tif); subplot(3,2,2),imshow(f2); f3 imread(WashingtonDC_Band3_564.tif); subplot(3,2,3),imsho…...

    2022/11/19 21:17:16
  27. 配置 已完成 请勿关闭计算机,win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机...

    win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机”问题的解决方法在win7系统关机时如果有升级系统的或者其他需要会直接进入一个 等待界面&#xff0c;在等待界面中我们需要等待操作结束才能关机&#xff0c;虽然这比较麻烦&#xff0c;但是对系统进行配置和升级…...

    2022/11/19 21:17:15
  28. 台式电脑显示配置100%请勿关闭计算机,“准备配置windows 请勿关闭计算机”的解决方法...

    有不少用户在重装Win7系统或更新系统后会遇到“准备配置windows&#xff0c;请勿关闭计算机”的提示&#xff0c;要过很久才能进入系统&#xff0c;有的用户甚至几个小时也无法进入&#xff0c;下面就教大家这个问题的解决方法。第一种方法&#xff1a;我们首先在左下角的“开始…...

    2022/11/19 21:17:14
  29. win7 正在配置 请勿关闭计算机,怎么办Win7开机显示正在配置Windows Update请勿关机...

    置信有很多用户都跟小编一样遇到过这样的问题&#xff0c;电脑时发现开机屏幕显现“正在配置Windows Update&#xff0c;请勿关机”(如下图所示)&#xff0c;而且还需求等大约5分钟才干进入系统。这是怎样回事呢&#xff1f;一切都是正常操作的&#xff0c;为什么开时机呈现“正…...

    2022/11/19 21:17:13
  30. 准备配置windows 请勿关闭计算机 蓝屏,Win7开机总是出现提示“配置Windows请勿关机”...

    Win7系统开机启动时总是出现“配置Windows请勿关机”的提示&#xff0c;没过几秒后电脑自动重启&#xff0c;每次开机都这样无法进入系统&#xff0c;此时碰到这种现象的用户就可以使用以下5种方法解决问题。方法一&#xff1a;开机按下F8&#xff0c;在出现的Windows高级启动选…...

    2022/11/19 21:17:12
  31. 准备windows请勿关闭计算机要多久,windows10系统提示正在准备windows请勿关闭计算机怎么办...

    有不少windows10系统用户反映说碰到这样一个情况&#xff0c;就是电脑提示正在准备windows请勿关闭计算机&#xff0c;碰到这样的问题该怎么解决呢&#xff0c;现在小编就给大家分享一下windows10系统提示正在准备windows请勿关闭计算机的具体第一种方法&#xff1a;1、2、依次…...

    2022/11/19 21:17:11
  32. 配置 已完成 请勿关闭计算机,win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机”的解决方法...

    今天和大家分享一下win7系统重装了Win7旗舰版系统后&#xff0c;每次关机的时候桌面上都会显示一个“配置Windows Update的界面&#xff0c;提示请勿关闭计算机”&#xff0c;每次停留好几分钟才能正常关机&#xff0c;导致什么情况引起的呢&#xff1f;出现配置Windows Update…...

    2022/11/19 21:17:10
  33. 电脑桌面一直是清理请关闭计算机,windows7一直卡在清理 请勿关闭计算机-win7清理请勿关机,win7配置更新35%不动...

    只能是等着&#xff0c;别无他法。说是卡着如果你看硬盘灯应该在读写。如果从 Win 10 无法正常回滚&#xff0c;只能是考虑备份数据后重装系统了。解决来方案一&#xff1a;管理员运行cmd&#xff1a;net stop WuAuServcd %windir%ren SoftwareDistribution SDoldnet start WuA…...

    2022/11/19 21:17:09
  34. 计算机配置更新不起,电脑提示“配置Windows Update请勿关闭计算机”怎么办?

    原标题&#xff1a;电脑提示“配置Windows Update请勿关闭计算机”怎么办&#xff1f;win7系统中在开机与关闭的时候总是显示“配置windows update请勿关闭计算机”相信有不少朋友都曾遇到过一次两次还能忍但经常遇到就叫人感到心烦了遇到这种问题怎么办呢&#xff1f;一般的方…...

    2022/11/19 21:17:08
  35. 计算机正在配置无法关机,关机提示 windows7 正在配置windows 请勿关闭计算机 ,然后等了一晚上也没有关掉。现在电脑无法正常关机...

    关机提示 windows7 正在配置windows 请勿关闭计算机 &#xff0c;然后等了一晚上也没有关掉。现在电脑无法正常关机以下文字资料是由(历史新知网www.lishixinzhi.com)小编为大家搜集整理后发布的内容&#xff0c;让我们赶快一起来看一下吧&#xff01;关机提示 windows7 正在配…...

    2022/11/19 21:17:05
  36. 钉钉提示请勿通过开发者调试模式_钉钉请勿通过开发者调试模式是真的吗好不好用...

    钉钉请勿通过开发者调试模式是真的吗好不好用 更新时间:2020-04-20 22:24:19 浏览次数:729次 区域: 南阳 > 卧龙 列举网提醒您:为保障您的权益,请不要提前支付任何费用! 虚拟位置外设器!!轨迹模拟&虚拟位置外设神器 专业用于:钉钉,外勤365,红圈通,企业微信和…...

    2022/11/19 21:17:05
  37. 配置失败还原请勿关闭计算机怎么办,win7系统出现“配置windows update失败 还原更改 请勿关闭计算机”,长时间没反应,无法进入系统的解决方案...

    前几天班里有位学生电脑(windows 7系统)出问题了&#xff0c;具体表现是开机时一直停留在“配置windows update失败 还原更改 请勿关闭计算机”这个界面&#xff0c;长时间没反应&#xff0c;无法进入系统。这个问题原来帮其他同学也解决过&#xff0c;网上搜了不少资料&#x…...

    2022/11/19 21:17:04
  38. 一个电脑无法关闭计算机你应该怎么办,电脑显示“清理请勿关闭计算机”怎么办?...

    本文为你提供了3个有效解决电脑显示“清理请勿关闭计算机”问题的方法&#xff0c;并在最后教给你1种保护系统安全的好方法&#xff0c;一起来看看&#xff01;电脑出现“清理请勿关闭计算机”在Windows 7(SP1)和Windows Server 2008 R2 SP1中&#xff0c;添加了1个新功能在“磁…...

    2022/11/19 21:17:03
  39. 请勿关闭计算机还原更改要多久,电脑显示:配置windows更新失败,正在还原更改,请勿关闭计算机怎么办...

    许多用户在长期不使用电脑的时候&#xff0c;开启电脑发现电脑显示&#xff1a;配置windows更新失败&#xff0c;正在还原更改&#xff0c;请勿关闭计算机。。.这要怎么办呢&#xff1f;下面小编就带着大家一起看看吧&#xff01;如果能够正常进入系统&#xff0c;建议您暂时移…...

    2022/11/19 21:17:02
  40. 还原更改请勿关闭计算机 要多久,配置windows update失败 还原更改 请勿关闭计算机,电脑开机后一直显示以...

    配置windows update失败 还原更改 请勿关闭计算机&#xff0c;电脑开机后一直显示以以下文字资料是由(历史新知网www.lishixinzhi.com)小编为大家搜集整理后发布的内容&#xff0c;让我们赶快一起来看一下吧&#xff01;配置windows update失败 还原更改 请勿关闭计算机&#x…...

    2022/11/19 21:17:01
  41. 电脑配置中请勿关闭计算机怎么办,准备配置windows请勿关闭计算机一直显示怎么办【图解】...

    不知道大家有没有遇到过这样的一个问题&#xff0c;就是我们的win7系统在关机的时候&#xff0c;总是喜欢显示“准备配置windows&#xff0c;请勿关机”这样的一个页面&#xff0c;没有什么大碍&#xff0c;但是如果一直等着的话就要两个小时甚至更久都关不了机&#xff0c;非常…...

    2022/11/19 21:17:00
  42. 正在准备配置请勿关闭计算机,正在准备配置windows请勿关闭计算机时间长了解决教程...

    当电脑出现正在准备配置windows请勿关闭计算机时&#xff0c;一般是您正对windows进行升级&#xff0c;但是这个要是长时间没有反应&#xff0c;我们不能再傻等下去了。可能是电脑出了别的问题了&#xff0c;来看看教程的说法。正在准备配置windows请勿关闭计算机时间长了方法一…...

    2022/11/19 21:16:59
  43. 配置失败还原请勿关闭计算机,配置Windows Update失败,还原更改请勿关闭计算机...

    我们使用电脑的过程中有时会遇到这种情况&#xff0c;当我们打开电脑之后&#xff0c;发现一直停留在一个界面&#xff1a;“配置Windows Update失败&#xff0c;还原更改请勿关闭计算机”&#xff0c;等了许久还是无法进入系统。如果我们遇到此类问题应该如何解决呢&#xff0…...

    2022/11/19 21:16:58
  44. 如何在iPhone上关闭“请勿打扰”

    Apple’s “Do Not Disturb While Driving” is a potentially lifesaving iPhone feature, but it doesn’t always turn on automatically at the appropriate time. For example, you might be a passenger in a moving car, but your iPhone may think you’re the one dri…...

    2022/11/19 21:16:57