ubuntu 12.04 编译Android下的ffmpeg 1.2步骤

 更新时间:2016年9月20日 19:57  点击:2020
下面一起来看一篇关于ubuntu 12.04 编译Android下的ffmpeg 1.2的例子,希望此教程能够对各位同学带来有效的帮助。


编译环境:ubuntu 12.04

NDK版本:android-ndk-r8d

ffmpeg版本:1.2

新建Android工程,在工程目录中创建jni文件夹

1、在jni目录下添加如下文件Android.mk ,内容如下:

include $(all-subdir-makefiles)
 

2.在jni/ffmpeg下添加Android.mk内容如下:

 

3.在jni/ffmpeg下添加av.mk

4.在jni/ffmpeg/libavformat下添加Android,mk内容如下:

5. 在jni/ffmpeg/libavcodec下添加Android,mk内容如下:

6.在jni/ffmpeg/libavutil libpostproc libswscale libswresample 下添加Android,mk内容如下:

7.在jni/ffmpeg 下添加可执行文件config.sh, 内容如下

上面PREBUILT PLATFORM的路径自己根据NDK的路径自己更改,并增加可执行权限,命令如下:

chmod +x config.sh

4、命令行到jni/ffmpeg目录下执行

./config.sh

5、修改

a、删除 libavformat libavcodec libavutil libpostproc libswscale libswresample 目录下Makefile下的

include $(SUBDIR)../config.mak

b、删除libavcodec libavutil libswresample目录下Makefile下的

log2_tab.o \

c、修改jni/ffmpeg/config.h下的

#define avrestrict restrict为#define restrict

e、把 ffmpeg/libavutil/time.h更名为avtime.h,

同时修改下面文件中的引用libavutil/time.h为libavutil/avtime.h

ffmpeg/libavformat/avformat.h:211

ffmpeg/libavformat/avio.c:25

ffmpeg/libavformat/hls.c:33

ffmpeg/libavformat/mux.c:39:30

ffmpeg/libavformat/utils.c:40

ffmpeg/libavutil/time.c:36

 

6、接下来就是编译了

cd ..

命令行到项目project目录下执行

$NDK/ndk-build

 

问题一:

Install        : libffplay.so => libs/armeabi-v7a/libffplay.so
Install        : libiptv_media_player_jni.so => libs/armeabi-v7a/libiptv_media_player_jni.so
/home/rds/share/xiongms/android-ndk-r8d/toolchains/arm-linux-androideabi-4.6/prebuilt/linux-x86/bin/../lib/gcc/arm-linux-androideabi/4.6/../../../../arm-linux-androideabi/bin/ld: warning: hidden symbol '__aeabi_atexit' in ./obj/local/armeabi-v7a/libgnustl_static.a(atexit_arm.o)
is referenced by DSO ./obj/local/armeabi-v7a/libffplay.so
/home/rds/share/xiongms/android-ndk-r8d/toolchains/arm-linux-androideabi-4.6/prebuilt/linux-x86/bin/../lib/gcc/arm-linux-androideabi/4.6/../../../../arm-linux-androideabi/bin/ld: ./obj/local/armeabi-v7a/libswscale.a(swscale.o): in function swScale:jni/libffmpeg/libswscale/swscale.c:426:
error: undefined reference to 'av_get_cpu_flags'
/home/rds/share/xiongms/android-ndk-r8d/toolchains/arm-linux-androideabi-4.6/prebuilt/linux-x86/bin/../lib/gcc/arm-linux-androideabi/4.6/../../../../arm-linux-androideabi/bin/ld: ./obj/local/armeabi-v7a/libswscale.a(utils.o): in function sws_init_context:jni/libffmpeg/libswscale/utils.c:917:
error: undefined reference to 'av_get_cpu_flags'
/home/rds/share/xiongms/android-ndk-r8d/toolchains/arm-linux-androideabi-4.6/prebuilt/linux-x86/bin/../lib/gcc/arm-linux-androideabi/4.6/../../../../arm-linux-androideabi/bin/ld: ./obj/local/armeabi-v7a/libswresample.a(resample.o): in function multiple_resample:jni/libffmpeg/libswresample/resample.c:315:
error: undefined reference to 'av_get_cpu_flags'

将Android.mk中的

LOCAL_STATIC_LIBRARIES := libavformat libavcodec libavutil libpostproc libswscale libswresample libmediaplayer

改为

LOCAL_WHOLE_STATIC_LIBRARIES := libavformat libavcodec libavutil libpostproc libswscale libswresample libmediaplayer

本教程我们讲解一下用原生的Android开发生成JSON与解析JSON数据格式,掌握Android原生解析JSON数据的方法相当重要,这样我们就可以比较好理解那些jar包的原理。

下面分为生成JSON数据和解析JSON数据,所用的包是org.json

(1)生成JSON数据方法:

比如要生成一个这样的json文本  

   { 
     "phone" : ["12345678", "87654321"],    //数组
     "name" : "dream9", // 字符串 
      "age" : 100, // 数值 
     "address" : { "country" : "china", "province" : "guangdong" }, // 对象 
    }  


try {
            JSONObject obj = new JSONObject(); // 首先创建一个对象
            JSONArray phone = new JSONArray(); // 添加数据到数组中序号是从0递增的
            phone.put("12345678");
            phone.put("87654321");
            obj.put("phone", phone);
            obj.put("name", "dream9");
            obj.put("age", 100);
            JSONObject address = new JSONObject();
            address.put("country", "china");
            address.put("province", "jiangsu");
            obj.put("address", address);
            Log.e("huang", obj.toString());
}


结果:

001.jpg


(2)解析JSON数据方法(以上面那个为例):


private void anaylse(String data){
        try {
            JSONObject obj = new JSONObject((String)data);
            JSONArray phone = obj.getJSONArray("phone");
            for(int t=0; t<phone.length(); ++t){
                Log.e("huang", phone.getString(t));      //解析phone数组
            }
            Log.e("huang", obj.getString("name"));
            Log.e("huang", obj.getInt("age")+"");
            JSONObject o = obj.getJSONObject("address");
            Log.e("huang", o.getString("country"));
            Log.e("huang", o.getString("province"));
        } catch (JSONException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        
    }

结果:

001.jpg

android Json解析详解

android2.3提供的json解析类
android的json解析部分都在包org.json下,主要有以下几个类:

    JSONObject:可以看作是一个json对象,这是系统中有关JSON定义的基本单元,其包含一对儿(Key/Value)数值。它对外部(External:   应用toString()方法输出的数值)调用的响应体现为一个标准的字符串(例如:{"JSON": "Hello, World"},最外被大括号包裹,其中的Key和Value被冒号":"分隔)。其对于内部(Internal)行为的操作格式略微,例如:初始化一个JSONObject实例,引用内部的put()方法添加数值:new JSONObject().put("JSON", "Hello, World!"),在Key和Value之间是以逗号","分隔。Value的类型包括:Boolean、JSONArray、JSONObject、Number、String或者默认值JSONObject.NULL object 。

    JSONStringer:json文本构建类 ,根据官方的解释,这个类可以帮助快速和便捷的创建JSON text。其最大的优点在于可以减少由于 格式的错误导致程序异常,引用这个类可以自动严格按照JSON语法规则(syntax rules)创建JSON text。每个JSONStringer实体只能对应创建一个JSON text。。其最大的优点在于可以减少由于格式的错误导致程序异常,引用这个类可以自动严格按照JSON语法规则(syntax rules)创建JSON text。每个JSONStringer实体只能对应创建一个JSON text。

    JSONArray:它代表一组有序的数值。将其转换为String输出(toString)所表现的形式是用方括号包裹,数值以逗号”,”分隔(例如:     [value1,value2,value3],大家可以亲自利用简短的代码更加直观的了解其格式)。这个类的内部同样具有查询行为,     get()和opt()两种方法都可以通过index索引返回指定的数值,put()方法用来添加或者替换数值。同样这个类的value类型可以包括:Boolean、JSONArray、JSONObject、Number、String或者默认值JSONObject.NULL object。

    JSONTokener:json解析类
    JSONException:json中用到的异常



JSONObject, JSONArray来构建json文本  

    // 假设现在要创建这样一个json文本  
    //  {  
    //      "phone" : ["12345678", "87654321"], // 数组  
    //      "name" : "yuanzhifei89", // 字符串  
    //      "age" : 100, // 数值  
    //      "address" : { "country" : "china", "province" : "jiangsu" }, // 对象  
    //      "married" : false // 布尔值  
    //  }  
      
    try {  
        // 首先最外层是{},是创建一个对象  
        JSONObject person = new JSONObject();  
        // 第一个键phone的值是数组,所以需要创建数组对象  
        JSONArray phone = new JSONArray();  
        phone.put("12345678").put("87654321");  
        person.put("phone", phone);  
      
        person.put("name", "yuanzhifei89");  
        person.put("age", 100);  
        // 键address的值是对象,所以又要创建一个对象  
        JSONObject address = new JSONObject();  
        address.put("country", "china");  
        address.put("province", "jiangsu");  
        person.put("address", address);    
        person.put("married", false);  
    } catch (JSONException ex) {  
        // 键为null或使用json不支持的数字格式(NaN, infinities)  
        throw new RuntimeException(ex);  
    }


getType和optType api的使用   

    getType可以将要获取的键的值转换为指定的类型,如果无法转换或没有值则抛出JSONException

    optType也是将要获取的键的值转换为指定的类型,无法转换或没有值时返回用户提供或这默认提供的值

  

  try {  
        // 所有使用的对象都是用上面创建的对象  
        // 将第一个电话号码转换为数值和将名字转换为数值  
        phone.getLong(0);  
        person.getLong("name"); // 会抛异常,因为名字无法转换为long        
        phone.optLong(0); // 代码内置的默认值  
        phone.optLong(0, 1000); // 用户提供的默认值  
        person.optLong("name");  
        person.optLong("name", 1000); // 不像上面那样抛异常,而是返回1000  
    } catch (JSONException ex) {  
        // 异常处理代码  
    }


除了上面的两个类,还可以使用JSONStringer来构建json文本  

Java代码  

try {  
    JSONStringer jsonText = new JSONStringer();  
    // 首先是{,对象开始。object和endObject必须配对使用  
    jsonText.object();  
      
    jsonText.key("phone");  
    // 键phone的值是数组。array和endArray必须配对使用  
    jsonText.array();  
    jsonText.value("12345678").value("87654321");  
    jsonText.endArray();  
      
    jsonText.key("name");  
    jsonText.value("yuanzhifei89");  
    jsonText.key("age");  
    jsonText.value(100);  
      
    jsonText.key("address");  
    // 键address的值是对象  
    jsonText.object();  
    jsonText.key("country");  
    jsonText.value("china");  
    jsonText.key("province");  
    jsonText.value("jiangsu");  
    jsonText.endObject();  
      
    jsonText.key("married");  
    jsonText.value(false);  
      
    // },对象结束  
    jsonText.endObject();  
} catch (JSONException ex) {  
    throw new RuntimeException(ex);  
}


json文本解析类JSONTokener   
按照RFC4627规范将json文本解析为相应的对象。  

对于将json文本解析为对象,只需要用到该类的两个api:   
构造函数  

public Object nextValue(); 
//  {  
//      "phone" : ["12345678", "87654321"], // 数组  
//      "name" : "yuanzhifei89", // 字符串  
//      "age" : 100, // 数值  
//      "address" : { "country" : "china", "province" : "jiangsu" }, // 对象  
//      "married" : false // 布尔值  
//  }  
  
private static final String JSON =   
"{" +  
    "   \"phone\" : [\"12345678\", \"87654321\"]," +  
    "   \"name\" : \"yuanzhifei89\"," +  
    "   \"age\" : 100," +  
    "   \"address\" : { \"country\" : \"china\", \"province\" : \"jiangsu\" }," +  
    "   \"married\" : false," +  
"}";  
  
try {  
    JSONTokener jsonParser = new JSONTokener(JSON);  
    // 此时还未读取任何json文本,直接读取就是一个JSONObject对象。  
    // 如果此时的读取位置在"name" : 了,那么nextValue就是"yuanzhifei89"(String)  
    JSONObject person = (JSONObject) jsonParser.nextValue();  
    // 接下来的就是JSON对象的操作了  
    person.getJSONArray("phone");  
    person.getString("name");  
    person.getInt("age");  
    person.getJSONObject("address");  
    person.getBoolean("married");  
} catch (JSONException ex) {  
    // 异常处理代码  
}



其它的api基本就是用来查看json文本中的文本的

    try {  
        JSONTokener jsonParser = new JSONTokener(JSON);  
        // 继续向下读8个json文本中的字符。此时刚开始,即在{处  
        jsonParser.next(8); //{    "phone。tab算一个字符  
          
        // 继续向下读1个json文本中的字符  
        jsonParser.next(); //"  
          
        // 继续向下读取一个json文本中的字符。该字符不是空白、同时也不是注视中的字符  
        jsonParser.nextClean(); //:  
          
        // 返回当前的读取位置到第一次遇到'a'之间的字符串(不包括a)。  
        jsonParser.nextString('a'); //  ["12345678", "87654321"],    "n(前面有两个空格)  
          
        // 返回当前读取位置到第一次遇到字符串中(如"0089")任意字符之间的字符串,同时该字符是trimmed的。(此处就是第一次遇到了89)  
        jsonParser.nextTo("0089"); //me" : "yuanzhifei  
          
        // 读取位置撤销一个  
        jsonParser.back();  
        jsonParser.next(); //i  
          
        // 读取位置前进到指定字符串处(包括字符串)  
        jsonParser.skipPast("address");  
        jsonParser.next(8); //" : { "c  
          
        // 读取位置前进到执行字符处(不包括字符)  
        jsonParser.skipTo('m');  
        jsonParser.next(8); //married"  
    } catch (JSONException ex) {  
        // 异常处理代码  
    }

以下是一个标准的JSON请求实现过程:

HttpPost request = new HttpPost(url); 
// 先封装一个 JSON 对象 
JSONObject param = new JSONObject(); 
param.put("name", "rarnu"); 
param.put("password", "123456"); 
// 绑定到请求 Entry 
StringEntity se = new StringEntity(param.toString());  
request.setEntity(se); 
// 发送请求 
HttpResponse httpResponse = new DefaultHttpClient().execute(request); 
// 得到应答的字符串,这也是一个 JSON 格式保存的数据 
String retSrc = EntityUtils.toString(httpResponse.getEntity()); 
// 生成 JSON 对象 
JSONObject result = new JSONObject( retSrc); 
String token = result.get("token");


下面这个是自己修改别人的小例子,主要是加一些注释和讲解,这个例子主要是使用android进行json解析。

单数据{'singer':{'id':1,'name':'tom','gender':'男'}}
多个数据{'singers':[{'id':'2','name':'tom','gender':'男'},{'id':'3','name':'jerry','gender':'男'},{'id':'4','name':'jim','gender':'男'},{'id':'5','name':'lily','gender':'女'}]}                                                                            

下面的类主要是解析单个数据parseJson()和多个数据的方法parseJsonMulti():

public class JsonActivity extends Activity { 
    /** Called when the activity is first created. */ 
    private TextView tvJson; 
    private Button btnJson; 
    private Button btnJsonMulti; 
    @Override 
    public void onCreate(Bundle savedInstanceState) { 
        super.onCreate(savedInstanceState); 
        setContentView(R.layout.main); 
        tvJson = (TextView) this.findViewById(R.id.tvJson); 
        btnJson = (Button) this.findViewById(R.id.btnJson); 
        btnJsonMulti = (Button) this.findViewById(R.id.btnJsonMulti); 
        btnJson.setOnClickListener(new View.OnClickListener() { 
            @Override 
            public void onClick(View v) { 
                // url 
                // String strUrl = "http://10.158.166.110:8080/AndroidServer/JsonServlet"; 
                String strUrl = ServerPageUtil.getStrUrl(UrlsOfServer.JSON_SINGER); 
                //获得返回的Json字符串 
                String strResult = connServerForResult(strUrl); 
                //解析Json字符串 
                parseJson(strResult); 
            } 
        }); 
        btnJsonMulti.setOnClickListener(new View.OnClickListener() { 
            @Override 
            public void onClick(View v) { 
                String strUrl = ServerPageUtil.getStrUrl(UrlsOfServer.JSON_SINGERS); 
                String strResult = connServerForResult(strUrl); 
                //获得多个Singer 
                parseJsonMulti(strResult); 
            } 
        }); 
    } 
    private String connServerForResult(String strUrl) { 
        // HttpGet对象 
        HttpGet httpRequest = new HttpGet(strUrl); 
        String strResult = ""; 
        try { 
            // HttpClient对象 
            HttpClient httpClient = new DefaultHttpClient(); 
            // 获得HttpResponse对象 
            HttpResponse httpResponse = httpClient.execute(httpRequest); 
            if (httpResponse.getStatusLine().getStatusCode() == HttpStatus.SC_OK) { 
                // 取得返回的数据 
                strResult = EntityUtils.toString(httpResponse.getEntity()); 
            } 
        } catch (ClientProtocolException e) { 
            tvJson.setText("protocol error"); 
            e.printStackTrace(); 
        } catch (IOException e) { 
            tvJson.setText("IO error"); 
            e.printStackTrace(); 
        } 
        return strResult; 
    } 
    // 普通Json数据解析 
    private void parseJson(String strResult) { 
        try { 
            JSONObject jsonObj = new JSONObject(strResult).getJSONObject("singer"); 
            int id = jsonObj.getInt("id"); 
            String name = jsonObj.getString("name"); 
            String gender = jsonObj.getString("gender"); 
            tvJson.setText("ID号"+id + ", 姓名:" + name + ",性别:" + gender); 
        } catch (JSONException e) { 
            System.out.println("Json parse error"); 
            e.printStackTrace(); 
        } 
    } 
    //解析多个数据的Json
    private void parseJsonMulti(String strResult) { 
        try { 
            JSONArray jsonObjs = new JSONObject(strResult).getJSONArray("singers"); 
            String s = ""; 
            for(int i = 0; i < jsonObjs.length() ; i++){ 
                JSONObject jsonObj = (JSONObject)jsonObjs.get(i); 
                int id = jsonObj.getInt("id"); 
                String name = jsonObj.getString("name"); 
                String gender = jsonObj.getString("gender"); 
                s +=  "ID号"+id + ", 姓名:" + name + ",性别:" + gender+ "\n" ; 
            } 
            tvJson.setText(s); 
        } catch (JSONException e) { 
            System.out.println("Jsons parse error !"); 
            e.printStackTrace(); 
        } 
    } 
}

Android中的服务和windows中的服务是类似的东西,服务一般没有用户操作界面,它运行于系统中不容易被用户发觉,可以使用它开发如监控之类的程序。

什么是服务:长期后台运行的没有界面的组件,

android是应用场景:
天气预报:后台的连接服务器的逻辑,每隔一段时间获取最新的天气信息
股票显示:后台的连接服务器的逻辑,每隔一段时间获取最新的股票信息
mp3播放器: 后台长期的播放音乐。

new Thread(){}.start(); 子线程没有界面,也是长期后台运行的。

android系统进程管理是按照一定的规则的:

1.应用程序一旦被打开 通常情况下关闭(清空任务栈)后进程不会停止。方面下一次快速启动。

带来内存不足的问题。

2.Android系统有一套 内存清理机制。 按照优先级去回收系统的内存。



进程分为5个等级的优先级:(从高到低)



1.Foreground process 前台进程  用户正在玩的应用程序对应的进程


2.Visible process 可视进程 用户仍然可以看到这个进程的界面。


3.Service process服务进程  应用程序有一个服务组件在后台运行。


4.Background process 后台进程  应用程序没有服务在运行 并且最小化 (activity onstop)


5.Empty process 空进程 没有任何运行的activity, 任务栈空了


长期后台运行的组件,不要在activity开启子线程。

应该是创建服务,在服务里面开启子线程。

 

服务的目的:

1.长期后台运行。

2.提高进程的优先级,系统不容易回收掉进程,即便回收了,内存充足的时候,把进程重新创建。

    案例场景:使用一个按钮开启服务,在控制台打印服务启动状况。程序界面如下:


2 Android清单文件如下:

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

<manifest xmlns:android="http://schemas.android.com/apk/res/android"

    package="com.itheima.testservice"

    android:versionCode="1"

    android:versionName="1.0" >

 

    <uses-sdk

        android:minSdkVersion="8"

        android:targetSdkVersion="19" />

 

    <application

        android:allowBackup="true"

        android:icon="@drawable/ic_launcher"

        android:label="@string/app_name"

        android:theme="@style/AppTheme" >

        <activity

            android:name="com.itheima.testservice.MainActivity"

            android:label="@string/app_name" >

            <intent-filter>

                <action android:name="android.intent.action.MAIN" />

 

                <category android:name="android.intent.category.LAUNCHER" />

            </intent-filter>

        </activity>

        <service android:name="com.itheima.testservice.MyService"></service>

    </application>

 

</manifest>

3 布局文件如下:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"

    xmlns:tools="http://schemas.android.com/tools"

    android:layout_width="match_parent"

    android:layout_height="match_parent"

    tools:context=".MainActivity" >


    <Button

        android:onClick="click"

        android:layout_width="wrap_content"

        android:layout_height="wrap_content"

        android:layout_centerHorizontal="true"

        android:layout_centerVertical="true"

        android:text="开启服务"/>

</RelativeLayout>

4 MainActivity的代码如下:

package com.itheima.testservice;

import android.app.Activity;

import android.content.Intent;
import android.os.Bundle;
import android.view.View;

public class MainActivity extends Activity {

         @Override

         protected void onCreate(Bundle savedInstanceState) {

                   super.onCreate(savedInstanceState);

                   setContentView(R.layout.activity_main);

         }

         public void click(View view) {

                    Intent intent = new Intent(this,MyService.class);

                    startService(intent);

         }

}

5 MyService的代码如下:

package com.itheima.testservice;

import android.app.Service;

import android.content.Intent;

import android.os.IBinder;


public class MyService extends Service {

         @Override

         public IBinder onBind(Intent intent) {

                   return null;

         }


         //oncreate ondestory onstart onstop onresume onpause

         @Override

         public void onCreate() {

                   System.out.println("服务创建了");

                   super.onCreate();

         }

        

         @Override

         public int onStartCommand(Intent intent, int flags, int startId) {

                   System.out.println("服务器");

                   return super.onStartCommand(intent, flags, startId);

         }

        

         @Override

         public void onDestroy() {

                   System.out.println("服务器销毁了");

                   super.onDestroy();

         }

}




6.关于接受者的说明


四大组件:

Activity
Content provider 内容提供者
Broadcast receiver 广播接受者
Service  服务


电台:   发送广播
收音机: 接受广播


android系统下的广播:

电池电量低。
电池充电完毕
短信到来了
程序安装卸载
sd卡卸载 安装

1.写一个类继承广播接受者
2.在清单文件配置关心的动作
3.一旦广播事件发生了,就会执行广播接受者的onreceive方法




Android通过广播接收者调用服务内方法

Android通过广播接收者调用服务内方法 以及利用代码注册广播接收器(4大组件中唯一可以使用代码声明的组件(activity receiver provider service))

服务;

package com.pas.callmethod;
 
import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.IBinder;
import android.widget.Toast;
 
public class MyService extends Service
{
 
    private MyReciver receiver;
     
    @Override
    public void onCreate()
    {
        //采用代码方式注册广播接收者
        receiver=new MyReciver();
        IntentFilter filter=new IntentFilter();
        filter.addAction("com.pas.call");
        registerReceiver(receiver, filter);
        super.onCreate();
    }
     
    @Override
    public void onDestroy()
    {
        unregisterReceiver(receiver);
        receiver=null;
        super.onDestroy();
    }
    @Override
    public IBinder onBind(Intent arg0)
    {
        return null;
    }
 
    private void method_inservice()
    {
        Toast.makeText(getApplicationContext(), "我的服务的方法……", Toast.LENGTH_SHORT).show();
    }
     
    private class MyReciver extends BroadcastReceiver
    {
 
        @Override
        public void onReceive(Context arg0, Intent arg1)
        {
            System.out.println("内部接收者");
            method_inservice();
        }
         
    }
}


MAINAC:

package com.pas.callmethod;
 
import android.os.Bundle;
import android.app.Activity;
import android.content.Intent;
import android.view.Menu;
import android.view.View;
 
public class MainActivity extends Activity
{
 
    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
         
        Intent intent=new Intent(this,MyService.class);
        startService(intent);
    }
 
    @Override
    public boolean onCreateOptionsMenu(Menu menu)
    {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }
 
    public void call(View v)
    {
        //发送自定义广播
        Intent intent=new Intent();
        intent.setAction("com.pas.call");
        sendBroadcast(intent);
    }
}

有时我们的Android APP需要内嵌现成的wap手机网站,本文我们来介绍两个Android内嵌wap站的实例方法,而且嵌入的网页后界面效果和app差不多。

我们的内嵌Android APP手机站点m.baidu.com,不能显示标题栏,点击网页的超链接,不会弹出系统自带浏览器。


布局web.xml 在layouts目录下新建布局文件web.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">
<webview android:id="@+id/webView" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_weight="1.0">
</webview></linearlayout>

布局文件写好了,那么我们开始写代码了,我把整个代码都拷贝到下面

package cn.afcu.sdk;
 
import android.os.Bundle;
import android.view.View;
import android.webkit.WebSettings;
import android.webkit.WebView;
import android.webkit.WebViewClient;
 
public class Web extends MainActivity {
 
private WebView  webView;
 
@Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.web);
webView  = (WebView)  findViewById(R.id.webView);
openBrowser();
 
webView.setWebViewClient(new WebViewClient() {
public boolean shouldOverrideUrlLoading(WebView view, String url)
{ //  重写此方法表明点击网页里面的链接还是在当前的webview里跳转,不跳到浏览器那边
view.loadUrl(url);
return true;
}
});
}
 
//利用webView的loadUrl方法
public void openBrowser() {
webView.setScrollBarStyle(View.SCROLLBARS_OUTSIDE_OVERLAY);//滚动条在WebView内侧显示
webView.setScrollBarStyle(View.SCROLLBARS_INSIDE_OVERLAY);//滚动条在WebView外侧显示
webView.setVerticalScrollBarEnabled(false); //垂直不显示
WebSettings webSettings = webView.getSettings();
webSettings.setJavaScriptEnabled(true);
webView.loadUrl("http://www.baidu.com");
}
}



Andriod使用webview控件往APP里内嵌网页

1.布局文件片段:res-layout

<WebView android:id="@+id/Toweb"  
     android:layout_width="fill_parent"  
     android:layout_height="fill_parent" />

2.Java片段:src

@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        
        //WebView
        WebView browser=(WebView)findViewById(R.id.Toweb);  
        browser.loadUrl("http://www.baidu.com");  
          
        //设置可自由缩放网页  
        browser.getSettings().setSupportZoom(true);  
        browser.getSettings().setBuiltInZoomControls(true);  
          
        // 如果页面中链接,如果希望点击链接继续在当前browser中响应,  
        // 而不是新开Android的系统browser中响应该链接,必须覆盖webview的WebViewClient对象  
        browser.setWebViewClient(new WebViewClient() {  
            public boolean shouldOverrideUrlLoading(WebView view, String url)  
            {   
                //  重写此方法表明点击网页里面的链接还是在当前的webview里跳转,不跳到浏览器那边  
                view.loadUrl(url);  
                        return true;  
            }         
             });
    }  
    
    //go back
    @Override  
    public boolean onKeyDown(int keyCode, KeyEvent event) {  
        WebView browser=(WebView)findViewById(R.id.Toweb);  
        // Check if the key event was the Back button and if there's history  
        if ((keyCode == KeyEvent.KEYCODE_BACK) && browser.canGoBack()) {  
            browser.goBack();  
            return true;  
        }  
      //  return true;  
        // If it wasn't the Back key or there's no web page history, bubble up to the default  
        // system behavior (probably exit the activity)  
        return super.onKeyDown(keyCode, event);  
    }

3. AndroidManifest.xml 设置权限,否则无法访问

<!--添加该权限,webview可以访问网页-->
<uses-permission android:name="android.permission.INTERNET"></uses-permission> 

本文我们需要解决的问题是如何实现Http请求来实现通信,解决Android 2.3 版本以后无法使用Http请求问题,下面请看正文。

Android开发中使用HttpClient来开发Http程序来完成简单的网络通信,其实使用HttpUrlConnection也可以实现,不过HttpClient可以完成HttpUrlConnection的所有功能,并且还自己增加了其他的功能,那相比之下就直接使用HttpClient就得了...Http通信有两种方式,相比大家都清楚,一种是使用GET请求,另一种则是使用POST请求来完成...GET请求可以获取静态页面,也可以把参数放在URL参数后面进行传递...POST与GET不同的地方就在于这里,POST请求无法将数据放到字符串的后面...而是放在Http传递的数据当中...这些参数会通过cookie或者是session来进行传递...POST更加适合传递保密的数据信息...比如说用户的账户密码...这样使用GET方式就不是很合理了...因此把保密的数据信息放入到Http请求数据中更加的安全...

那么Android是如何通过Http请求来实现GET或者是POST请求呢?这里简单的介绍一下...先介绍一下GET方式...如何使用GET请求来获取数据信息....GET请求需要几个步骤...

首先:我们需要建立GET对象...通过创建对象来告诉服务器我们使用的GET请求来获取数据信息的...因为Http请求是以URL的形式进行来完成数据传递的...因此我们需要传递一个URL来实例化对象...我这个地址是服务器上的一个jsp文件...通过使用Http请求来获取JSP界面的数据信息...

String path="http://10.0.2.2:8080/JSP/text.jsp":
HttpGet get=new HttpGet(path);

  然后我们需要使用DefaultHttpClient类中的execute()方法来发送Http GET请求...并返回一个HttpResponse对象,HttpResponse对象的目的是当一个Http连接建立成功之后,我们就可以使用其类中的方法来获取到服务器的响应信息...

HttpClient client=new DefaultHttpClient();
HttpResponse response=client.execute(get);

  最后我们就可以通过HttpResponse对象来获取服务器的响应数据信息了...这里我使用了一个getEntity()方法来返回响应信息,然后获取GET提交的URL后面的数据信息...

if(response.getStatusLine().getStatusCode()==HttpStatuse.SC_OK){
     String result=EntityUtils.toString(resopnse.getEntity());
     tv.setText(result);   
}

   最后我们需要在AndroidManifest.xml文件中配置权限属性...只需要添加<user-permission android:name="android.permission.INTERNET"/>那么简单的举一个小例子来实现Http的GET请求...

  首先我们先写一个JSP页面.....这个页面要在Tomcat上进行发布...当没有参数值进行传递的时候,会显示Your message are wrong!这个信息...

<%
    String name=request.getParameter("name");
    String password=request.getParameter("password");
    if("DARKER".equals(name) && "4968188".equals(password)){
        out.println("Receive name is:"+name);
        out.println("Receive password is:"+password);%>
    Your message are right!
    <%}else{
        out.println("Receive name is:"+name);
        out.println("Receive password is:"+password); %>
        Your message are wrong!
    <%}%>

  然后有了这个东西,我们就可以通过Http传递数据信息来提交数据...然后通过这个界面返回的信息来告知我们服务器响应的信息数据...一个简单的布局文件...就一个文本框...目的就是为了返回服务器的响应信息...

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical"
    tools:context=".MainActivity" >

    <TextView
        android:id="@+id/msg"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"/>

</LinearLayout>

  如何实现才是一个重要的过程...在实现的过程中会出现一个问题,就是在Android2.3版本以后就不允许在主线程中去使用Http请求了...相信大部分的学习资料上都没有这个提示问题,但是确实是存在着这样一个问题的...那么上有政策那么就下有对策...我们可以使用三种方法去解决这个问题...非常的简单,也很好理解...那么既然我们无法在主线程中去使用Http请求,那么我们可以新开启一个线程啊...或者是我们可以去使用异步线程类AsyncTask去实现不就完了吗...还有一种方法就是在主线程中加入某些东西...就是下面的在setContentView()这个函数下面加入的那两句话...但是这种方法在网上说并不是很推荐...因此本人也没怎么研究...其他两种方式先对就很好理解...这三种方式我都进行了列举...只要使用其中的任意一种方式就可以实现Http的GET请求....

package com.example.httpclient;
/* HttpCilent 通过Get与服务器进行通信...
 * HttpClient比HttpUrlConnection更加的有优势...前者能做后者所有能做的事情...
 * 那就干脆就使用这种方式吧....
 *
 *
 * */
import java.io.IOException;

import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.util.EntityUtils;

import android.os.AsyncTask;
import android.os.Bundle;
import android.os.StrictMode;
import android.app.Activity;
import android.view.Menu;
import android.widget.TextView;

public class MainActivity extends Activity {

    /*
     * 由于在Android2.3版本以后就不允许在主线程使用Http请求...
     * 但是我们可以使用其他的方法来解决这个问题...
     * 第一种方法在主线程onCreate()方法中加入StrictMode方法..不过这种方法不被推荐...
     * 第二种使用异步线程AsyncTask<Param,Progress,Result>也可以实现...在异步线程中完成Http请求..
     * 第三种方法单开启一个线程Runnable()来实现,其实也是延续异步线程的思想...
     *
     * */
    private TextView tv;
//    private String path="http://10.0.2.2:8080/JSP/get.jsp?name=DARKER&password=49681888";
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
//        StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder().detectDiskReads().detectDiskWrites().detectNetwork().penaltyLog().build());
//        StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder().detectLeakedSqlLiteObjects().detectLeakedClosableObjects().penaltyLog().penaltyDeath().build());
        tv=(TextView) findViewById(R.id.msg);
        new Thread(runnable).start();
//        HttpGet httpRequest=new HttpGet(path);
//        HttpClient httpcilents=new DefaultHttpClient();
//        try {
//            HttpResponse response=httpcilents.execute(httpRequest);
//            if(response.getStatusLine().getStatusCode()==HttpStatus.SC_OK){
//                String result=EntityUtils.toString(response.getEntity());
//                tv.setText(result);
//            }else{
//                tv.setText("请求错误");
//            }
//        } catch (ClientProtocolException e) {
//            // TODO Auto-generated catch block
//            e.printStackTrace();
//        } catch (IOException e) {
//            // TODO Auto-generated catch block
//            e.printStackTrace();
//        }
    }
    @SuppressWarnings("unused")
    private class http extends AsyncTask<Integer, Integer, Integer>{

        @Override
        protected Integer doInBackground(Integer... params) {
            // TODO Auto-generated method stub
            String url="http://10.0.2.2:8080/JSP/get.jsp?name=DARKER&password=49681888";
            HttpGet hget=new HttpGet(url);
            HttpClient htclient=new DefaultHttpClient();
            try {
                HttpResponse hresonse=htclient.execute(hget);
                if(hresonse.getStatusLine().getStatusCode()==HttpStatus.SC_OK){
                    String resul=EntityUtils.toString(hresonse.getEntity());
                    tv.setText(resul);
                }else{
                    tv.setText("连接失败...");
                }
            } catch (ClientProtocolException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            return null;
        }
        
    }

    Runnable runnable=new Runnable() {
        
        String path_1="http://10.0.2.2:8080/JSP/get.jsp?name=DARKER&password=49681888";
        @Override
        public void run() {
            // TODO Auto-generated method stub
            HttpGet get=new HttpGet(path_1);
            HttpClient cilent=new DefaultHttpClient();
            try {
                HttpResponse responses=cilent.execute(get);
                if(responses.getStatusLine().getStatusCode()==HttpStatus.SC_OK){
                    String result_1=EntityUtils.toString(responses.getEntity());
                    tv.setText(result_1);
                }else{
                    tv.setText("无法获取信息...");
                }
            } catch (ClientProtocolException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    };
    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }
}

   其实上面代码使用异步线程类是没问题的,不过上面的代码会报错,由于我的代码写错了位置...这个错误其实是在doInBackground()方法中出现的...因为在这个方法中是不能够更新控件的数据信息的...这个问题我将在下面进行解决....下面是实现Http的POST请求...然后解决刚才说的问题....下面使用了Handler类...简答的说一下这个类...其实这个类并不是用在这个异步线程类里面的...这个异步线程类内部还有三个没有实现的方法...就是onPreExecute(),publishProgress(),onProgressUpdate()...这三个方法内部都可以完成控件数据信息的更新,唯独这个doInBackground()是无法实现的...使用一个AsyncTask类,再使用Handler是完全没有必要的...其实Handler和AsyncTask是为了实现子线程无法去更新主线程中控件的数据信息而存在的...因为控件对于线程来说是不安全的,因此在子线程中也就无法完成主线程中控件数据信息的更新操作...但是在Android中往往是需要这样做的...因此出现了这两个类去解决这个问题...

  首先说一句主要的事,就是使用到了Runnable并不代表一定使用到了多线程...就拿上面那个Runnable类来说,这个runnable虽然重写了run()方法,并且还在主函数中使用了start进行调用,但是这个线程仍然是属于主线程Activity的,并不属于我们单独开启了一个新的线程,然后去执行任务...这是必然的,否则一定会报错...因为在一个新的线程内部是无法去更新主线程中控件的数据信息的...然后在说一下Handler是如何能够完成在子线程中能够对主线程中的控件完成对数据的更新...首先Handler通过传递Message或者是Runnable对象...一般来说都是Message对数据进行封装...Handler主要用来与Looper进行沟通..把信息加入到特定的Looper消息队列中,或者是获取Looper的信息,然后调用handlemessage方法来对获取的信息进行操作...然后将Message发送到MessageQueue中,MessageQueue是一个线性队列,用来保存获取到的消息数据...当Looper发现MessageQueue中有未处理的信息就将这个信息广播出去...Looper就是对MessageQueue队列中然后主线程Handler接收到信息,然后做相应的处理...最后完成更新操作...这就是实现的一个过程...

package com.example.httpclientpost;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.List;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.NameValuePair;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;

import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.view.Menu;
import android.widget.TextView;

public class MainActivity extends Activity {

    TextView tv;
    String result;
    @SuppressLint("HandlerLeak")
    private Handler handler=new Handler(){
        @Override
        public void handleMessage(Message msg){
            if(msg.what==1){
                tv.setText(result);
            }else{
                tv.setText("无法连接服务器...");
            }
        }
    };
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        tv=(TextView) findViewById(R.id.show);
        http h=new http();
        h.execute();
    }
    
    class http extends AsyncTask<Integer, Integer, Integer>{

        String url="http://10.0.2.2:8080/JSP/get.jsp";
        @Override
        protected Integer doInBackground(Integer... params) {
            // TODO Auto-generated method stub
            HttpPost post=new HttpPost(url);
            List<NameValuePair> param=new ArrayList<NameValuePair>();
            param.add(new BasicNameValuePair("name", "DARKER"));
            param.add(new BasicNameValuePair("password", "49681888"));
            try {
                HttpEntity entity=new UrlEncodedFormEntity(param,"gb2312");
                post.setEntity(entity);
                HttpClient client=new DefaultHttpClient();
                HttpResponse response=client.execute(post);
                if(response.getStatusLine().getStatusCode()==HttpStatus.SC_OK){
                     result=EntityUtils.toString(response.getEntity());
                     Message msg=new Message();
                     msg.what=1;
                     handler.sendMessage(msg);
                }else{
                    Message msg=new Message();
                    msg.what=0;
                    handler.sendMessage(msg);
                }
            }catch (UnsupportedEncodingException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (ClientProtocolException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
          
            return null;
        }
        
    }
    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }

}

  其实我觉得使用Android中使用AsyncTask这个异步线程类其实就行,因为这个异步线程类是结合了handler+Thread才得以实现的,当然我们也可以使用handler去进行处理,个人推荐还是使用这个异步线程类更好...好了有点说跑题了...返回Http的POST请求,Http的POST请求比GET能多了一点东西,它使用NameValuePair以键值对的形式对数据进行保存...并且POST请求需要制定字符集...否则数据会出现乱码现象...剩下的东西基本就类似了...这样就实现了Http的POST请求

[!--infotagslink--]

相关文章

  • Android子控件超出父控件的范围显示出来方法

    下面我们来看一篇关于Android子控件超出父控件的范围显示出来方法,希望这篇文章能够帮助到各位朋友,有碰到此问题的朋友可以进来看看哦。 <RelativeLayout xmlns:an...2016-10-02
  • Android开发中findViewById()函数用法与简化

    findViewById方法在android开发中是获取页面控件的值了,有没有发现我们一个页面控件多了会反复研究写findViewById呢,下面我们一起来看它的简化方法。 Android中Fin...2016-09-20
  • Android模拟器上模拟来电和短信配置

    如果我们的项目需要做来电及短信的功能,那么我们就得在Android模拟器开发这些功能,本来就来告诉我们如何在Android模拟器上模拟来电及来短信的功能。 在Android模拟...2016-09-20
  • 夜神android模拟器设置代理的方法

    夜神android模拟器如何设置代理呢?对于这个问题其实操作起来是非常的简单,下面小编来为各位详细介绍夜神android模拟器设置代理的方法,希望例子能够帮助到各位。 app...2016-09-20
  • android自定义动态设置Button样式【很常用】

    为了增强android应用的用户体验,我们可以在一些Button按钮上自定义动态的设置一些样式,比如交互时改变字体、颜色、背景图等。 今天来看一个通过重写Button来动态实...2016-09-20
  • Android WebView加载html5页面实例教程

    如果我们要在Android应用APP中加载html5页面,我们可以使用WebView,本文我们分享两个WebView加载html5页面实例应用。 实例一:WebView加载html5实现炫酷引导页面大多...2016-09-20
  • 深入理解Android中View和ViewGroup

    深入理解Android中View和ViewGroup从组成架构上看,似乎ViewGroup在View之上,View需要继承ViewGroup,但实际上不是这样的。View是基类,ViewGroup是它的子类。本教程我们深...2016-09-20
  • Android自定义WebView网络视频播放控件例子

    下面我们来看一篇关于Android自定义WebView网络视频播放控件开发例子,这个文章写得非常的不错下面给各位共享一下吧。 因为业务需要,以下代码均以Youtube网站在线视...2016-10-02
  • Android用MemoryFile文件类读写进行性能优化

    java开发的Android应用,性能一直是一个大问题,,或许是Java语言本身比较消耗内存。本文我们来谈谈Android 性能优化之MemoryFile文件读写。 Android匿名共享内存对外A...2016-09-20
  • Android设置TextView竖着显示实例

    TextView默认是横着显示了,今天我们一起来看看Android设置TextView竖着显示如何来实现吧,今天我们就一起来看看操作细节,具体的如下所示。 在开发Android程序的时候,...2016-10-02
  • android.os.BinderProxy cannot be cast to com解决办法

    本文章来给大家介绍关于android.os.BinderProxy cannot be cast to com解决办法,希望此文章对各位有帮助呀。 Android在绑定服务的时候出现java.lang.ClassCastExc...2016-09-20
  • Android 实现钉钉自动打卡功能

    这篇文章主要介绍了Android 实现钉钉自动打卡功能的步骤,帮助大家更好的理解和学习使用Android,感兴趣的朋友可以了解下...2021-03-15
  • Android 开发之布局细节对比:RTL模式

    下面我们来看一篇关于Android 开发之布局细节对比:RTL模式 ,希望这篇文章对各位同学会带来帮助,具体的细节如下介绍。 前言 讲真,好久没写博客了,2016都过了一半了,赶紧...2016-10-02
  • VSCode C++多文件编译的简单使用方法

    这篇文章主要介绍了VSCode C++多文件编译的简单使用方法,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下...2021-03-29
  • Vue3 编译流程-源码解析

    今天将从 Vue 的入口文件开始,看看声明了一个 Vue 的单文件之后是如何被 compile-core 编译核心模块编译成渲染函数的。下面小编讲解并附上代码分析展现在文章里,感兴趣的小伙伴不要错过奥...2021-09-25
  • Android中使用SDcard进行文件的读取方法

    首先如果要在程序中使用sdcard进行存储,我们必须要在AndroidManifset.xml文件进行下面的权限设置: 在AndroidManifest.xml中加入访问SDCard的权限如下: <!--...2016-09-20
  • Android开发之PhoneGap打包及错误解决办法

    下面来给各位简单的介绍一下关于Android开发之PhoneGap打包及错误解决办法,希望碰到此类问题的同学可进入参考一下哦。 在我安装、配置好PhoneGap项目的所有依赖...2016-09-20
  • 用Intel HAXM给Android模拟器Emulator加速

    Android 模拟器 Emulator 速度真心不给力,, 现在我们来介绍使用 Intel HAXM 技术为 Android 模拟器加速,使模拟器运行度与真机比肩。 周末试玩了一下在Eclipse中使...2016-09-20
  • Android判断当前屏幕是全屏还是非全屏

    在安卓开发时我碰到一个问题就是需要实现全屏,但又需要我们来判断出用户是使用了全屏或非全屏了,下面我分别找了两段代码,大家可参考。 先来看一个android屏幕全屏实...2016-09-20
  • Android开发中布局中的onClick简单完成多控件时的监听的利与弊

    本文章来为各位介绍一篇关于Android开发中布局中的onClick简单完成多控件时的监听的利与弊的例子,希望这个例子能够帮助到各位朋友. 首先在一个控件加上这么一句:and...2016-09-20