锐单电子商城 , 一站式电子元器件采购平台!
  • 电话:400-990-0325

android开发经验笔记总计

时间:2023-05-03 17:37:00 jd204u电量变送器

四大组件:

Android除了四个组件BroadcastReceiver其他三个组件必须在AndroidManifest中注册。在调用方式上,除了ContentProvider都必须借助Intent。

Activity

1.activity它是用户与应用程序交互的窗口,一个activity相当于我们实际中的一个网页,当打开一个屏幕时,之前的那个屏幕会被置为暂停状态,并且压入历史堆栈中,用户可以通过回退操作回到以前打开过的屏幕。

2.在android中activity它主要用于控制,可以选择显示view,也可以从view获取数据,然后将数据传modele处理层,最后显示处理结果。activity相当于MVC模式的controller控制层。


3.activity的启动模式
( 多次启动 Activity 为了解决这个问题,将重复创建实例,提供启动模式的选择 )
四种启动模式:standardsingleTopsingleTasksingleInstance
1).standard:系统默认的标准模式。
每次启动一个Activity无论这个例子是否存在,都会创建一个例子。任务栈中可以有多个例子,每个例子也可以输入不同的任务栈。谁开始了?Activity,这个Activity在启动他的任务栈中运行。当我们使用它时ApplicationContext去启动standard模式的Acitivty报错如下:
AndroidRuntime: android.util.AndroidRuntimeException: Calling startActivity from outside of  an Activity context requires the FLAG_ACTIVITY_NEW_TASK flag .Is this really what you  want?

这是因为standard模式的Activity默认会进入并启动它Activity在任务栈中,但由于非Activity类型的Context(ApplicationContext)没有所谓的任务栈,所以有这个问题。
解决方案是启动Activity指定FLAG_ACTIVITY_NEW_TASK标记位,这样启动时就会创建一个新的任务栈,此时即将启动Activity实际是以singleTask启动模式。
2).singleTop:栈顶复用模式。
如果新的 Activity已经在栈顶了,所以这样 Activity它不会同时重建 onNewIntent方法会被回调,通过此方法的参数我们可以取出当前请求的信息。需要注意的是,这个 ActivityonCreateonStart不会被系统调用。如果是新的 Actvity例子已经存在,但不在栈顶,所以新的 Activity它仍将被重建。

3).singleTask:栈内复用模式。

只要是单实例模式Activity存在于一个栈中,启动这么多次Activity都不会重新创建实例,和singleTop一样,系统会回调其onNewIntent。当一个具有singleTask模式的Activity请求启动后,比如Activity A,系统首先会寻找是否存在A想要的任务栈,如果不存在,就重新创建一个任务栈,然后创建A的实例后把A放入栈中。如果存在A所需要的任务栈,这时就要看栈中的A的实例存在,如果实例存在,那么系统就会把A调到栈顶并调用它的onNewIntent方法,如果实例不存在,就创建A的事例并把A压入栈中。举例:

a.比如目前任务栈中S1的情况是ABC,这个时候Activity DsingleTask的,模式请求启动,其所需要的是任务栈S2,由于S2D的实例都不存在,所以系统会先创建任务栈S2,然后再创建D的实例并将其入栈S2.

b.另外一种情况,假设D所需要的任务栈为S1,那么由于S1已经存在了,所以系统会直接创建D的实例,并将其入栈S1.

c.如果D所需要的任务栈为S1,此时S1的情况为ADBC,根据栈内复用的原则,此时D不会创建,系统会把D切换到栈顶并调用其onNewIntent方法,同时由于singleTask默认具有clearTop的效果,会导致栈内所有在D上面的Activity全部出栈,于是最终S1的情况为AD

4).singleInstance:单实例模式。

    加强版的singleTask模式,除了具备singleTask的所有特性外,还加强了一点,具有此模式的Activity只能单独位于一个任务栈中。


4. 当前 Activity 只有执行完 onPause() ,才会执行新 Activity onResume()

5. Activity在屏幕旋转时的生命周期:不设置Acitivityandroid:configChanges时,切屏会重新调用各个生命周期,切横屏会调用一次,切竖屏会调用两次;设置android:configChanges=”orientation”时,切屏还是会重新调用各个生命周期,切横、竖屏时只会调用一次;设置android:configChanges=”orientation|keyboardHidden”时,切屏不会重新调用各个生命周期,只会执行onConfigurationChanged方法。


7.Activity之间传递数据的方法:
1).基于消息的通信机制:Intent。action是要去哪,category、data是带上什么。传递的数据类型有限,如遇到Bitmap、InputStream、或者是LinkList链表时就不好用了。
2).static静态数据,public static成员变量。其实gc机制并不可靠,如果经常使用static的bitmap、drawable等,就会很有可能抛出OOM异常。
3).存储机制:File、Sqlite、SharedPreference、ContentProvider等。sp本质是xml,方便使用;file常用语存储大量的数据,但是更新数据相对较难;
4).基于IPC的通信机制:Context与Service之间的传递,如Activity和Service之间的传递
5).Application Context:每个Activity都是context,同样,Application也是一个context,而且android会保证这个context是唯一的实例
public class MyApp extends Application
{
    private Bitmap mBitmap;

    public Bitmap getBitmap()
    {
        return mBitmap;
    }

    public void setBitmap(Bitmap bitmap)
    {
        this.mBitmap = bitmap;
    }
    
}

 获得Bitmap对象的代码: 
     

9.startActivityForResult:
package com.example.result;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.Toast;

public class MainActivity extends Activity {

	public static final int REQUEST_CODE1 = 1;
	public static final int REQUEST_CODE2 = 2;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);

		Button button1 = (Button) findViewById(R.id.button1);
		button1.setOnClickListener(new OnClickListener() {

			@Override
			public void onClick(View v) {
				Intent intent = new Intent(MainActivity.this,
						SecondActivity.class);
				startActivityForResult(intent, REQUEST_CODE1);
			}
		});

		Button button2 = (Button) findViewById(R.id.button2);
		button2.setOnClickListener(new OnClickListener() {

			@Override
			public void onClick(View v) {
				Intent intent = new Intent(MainActivity.this,
						ThridActivity.class);
				startActivityForResult(intent, REQUEST_CODE2);
			}
		});

	}

	@Override
	protected void onActivityResult(int requestCode, int resultCode, Intent data) {
		super.onActivityResult(requestCode, resultCode, data);
		if (requestCode == REQUEST_CODE1) {
			Toast.makeText(getApplicationContext(),
					"111->" + data.getStringExtra("njj"), Toast.LENGTH_SHORT)
					.show();
		}
		if (requestCode == REQUEST_CODE2) {
			Toast.makeText(getApplicationContext(),
					"222->" + data.getStringExtra("njj"), Toast.LENGTH_SHORT)
					.show();
		}
	}
}
package com.example.result;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;

public class SecondActivity extends Activity {

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_second);

		Button button2 = (Button) findViewById(R.id.button2);
		button2.setOnClickListener(new OnClickListener() {

			@Override
			public void onClick(View v) {
				Intent intent = new Intent();
				intent.putExtra("njj", "niejianjian - second");
				setResult(RESULT_OK, intent);
				finish();
			}
		});

	}
}
package com.example.result;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;

public class ThridActivity extends Activity {

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_thrid);

		Button button3 = (Button) findViewById(R.id.button3);
		button3.setOnClickListener(new OnClickListener() {

			@Override
			public void onClick(View v) {
				Intent intent = new Intent();
				intent.putExtra("njj", "niejianjian - thrid");
				setResult(RESULT_OK, intent);
				finish();
			}
		});

	}
}

BroadcastReceiver

1.Broadcast是广泛的应用在程序之间传输信息的机制。而BroadcastReceiver是对发送出来的Broadcast进行过滤接受并响应的一类组件。

2.应用程序可以拥有任意数量的广播接收者以对所以它感兴趣的通知信息予以响应。所有的接收器均继承自BroadcastReceiver基类。

3.广播接收器没有界面。然而,它可以启动一个activity来相应他们接受到的消息,或者用NotificationManager拉力通知用户。通知可以有很多方式来吸引用户的注意力--闪动背光、震动、播放声音等等。一般来说是在状态栏上放一个持久的图标,用户可以打开它并获取消息。

4.到底什么时候用BroadcastReceiver:想要接收到某处的通知后,来进行一系列判断操作时。如用于接受系统的广播通知,系统会有很多sd卡挂在,手机重启,广播通知,低电量,来电,短信等。

5.注册方式,静态注册和动态注册:
 静态广播是常驻型的广播,即使应用程序关闭了,如果有消息广播来,程序也会被系统调用自动运行。
 动态广播不是常驻型的广播,也就是说广播跟随着程序的生命周期。
 1).静态注册
   写一个MyReceive类继承BroadcastReceive,并实现onReceive方法,在方法中进行相关的处理。
        
            
                
            
        
然后只需要通过 sendBroadcast发送即可
                        Intent intent = new Intent();
			intent.setAction("njj.test.receive");
			sendBroadcast(intent);
 2).动态注册
		IntentFilter filter = new IntentFilter();
		filter.addAction("njj.test.receive"); // 添加actionyongyu匹配需要接受的广播
		registerReceiver(receiver, filter); // receiver是一个广播对象。
	BroadcastReceiver receiver = new BroadcastReceiver() {
		@Override
		public void onReceive(Context context, Intent intent) {
		}
	};
取消绑定只需要执行
unregisterReceiver(receiver);
一般在onStart中注册,在onStop中取消解绑。

6.动态注册的广播,永远要快于静态注册的广播,不管静态注册的优先级设置有多高,不管动态注册的优先级有多低。因为代码中注册的运行在内存中,xml在系统中。

7.BroadcastReceive会不会被杀死,如何保证不被杀死?
   广播接受者接收到广播时,会调用 onReceive()方法并传递给它包含消息的intent的对象。广播接受者会被认为紧当它执行这个方法时是活跃的。当onReceive()方法返回时,它是不活跃的。有一个活跃的广播接受者是被进程保护的,不会被杀死,但是系统可以在任何时候杀死仅包括不活跃组件的进程,只要占用的内存被别的进程所需要。
这样就有问题,当一个广播消息的响应是费时的,因此应该在独立的线程中做这件事,远离用户界面其他组件运行的主线程,如果onReceive一旦返回,整个进程就会认定为不活跃的,就有可能被杀死。
  解决的方法就是,在onReceive中开启一个服务,及时服务做这个工作,因此系统知道进程中有活跃的工作在做。

8.有序广播和无序广播
 1).无序广播
   通过 context.sendBroadcast() 发送,就是发送出去之后,所有的接受者的接受顺序不一定,这种方式效率更高,但是无法使用 setResult() getResult() 以及 abort 系列的 API 。索然所以的接受者都可以接收到,但是不能接受到广播,也不能把它的处理结果传递到下一个接受者。
 2).有序广播
   当 android 系统接受到短信时,会发送一个广播 BoradcastReceiver ,这个广播有序广播。
 通过 Context.sendOrderedBroadcast() 发送,所有的 receiver 依次执行,就是广播发出后,接受者按照设置好的优先级一个一个的接受,前面的接受者有权决定这条广播是终止还是发送给后面的接受者。 BroadcastReceiver可以使用setResult系列函数来结果传给下一个BroadcastReceiver,通过getResult系列函数来取得上个BroadcastReceiver返回的结果,并可以abort系列函数来让系统丢弃该广播,使用该广播不再传送到别的BroadcastReceiver。可以通过在intent-filter中设置android:priority属性来设置receiver的优先级,优先级相同的receiver其执行顺序不确定。如果BroadcastReceiver是代码中注册的话,且其intent-filter拥有相同android:priority属性的话,先注册的将先收到广播。
 有序广播,从优先级别最高的广播接收器开始接收,接收完了如果没有丢弃,就下传给下一个次高优先级别的广播接收器进行处理,依次类推,直到最后。 如果多个应用程序设置的优先级别相同,则谁先注册的广播,谁就可以优先接收到广播。优先级的数值可以设置为-1000到1000之间的任何一个数。
案例:
        
            
                
            
        
        
            
                
            
        
在一个按钮的点击事件中发送广播
				Intent intent = new Intent();
				intent.setAction("njj.test.receive");
				intent.putExtra("key", "发送给receive1的广播");
				sendOrderedBroadcast(intent, null);
public class MyReceive1 extends BroadcastReceiver {

	@Override
	public void onReceive(Context context, Intent intent) {
		System.out.println("onreceive");
		if (intent.getAction().equals("njj.test.receive")) {
			Toast.makeText(context, intent.getStringExtra("key"),
					Toast.LENGTH_SHORT).show();
			Bundle bundle = new Bundle();
			bundle.putString("re1", "有序广播");
			setResultExtras(bundle);
			// abortBroadcast(); // 终止传递
		}
	}
}
public class MyReceive2 extends BroadcastReceiver {
	@Override
	public void onReceive(Context context, Intent intent) {
		Bundle bundle = getResultExtras(true);
		String msg = bundle.getString("re1");
		String msg2 = intent.getStringExtra("key");
		System.out.println("msg -> " + msg);
		System.out.println("msg2 -> " + msg2);
	}
}
广播会先传递到优先级高的MyReceive1,然后在传递到MyReceive2,在MyReceive1中可以将广播终止传递,也可以传递给下一个接受者数据。

9.sendBroadcast和sendStickyBroadcast
 在MainActivity里面会有sendBroadcastsendStickyBroacat.ReceverActivity里面通过BroadcastReceiver来接收这两个消息,在ReceiverActivity里是通过代码来注册Recevier而不是在 Manifest里面注册的。所以通过sendBroadcast中发出的intentReceverActivity不处于onResume状态是无 法接受到的,即使后面再次使其处于该状态也无法接受到。而sendStickyBroadcast发出的IntentReceverActivity重 新处于onResume状态之后就能重新接受到其Intent.这就是the Intent will be held to be re-broadcast to future receivers这句话的表现。就是说sendStickyBroadcast发出的最后一个Intent会被保留,下次当Recevier处于活跃的 时候,又会接受到它。
sendStickyBroadcast() 意思只要是如果发送广播之后才执行registerReceiver(BroadcastReceiver,IntentFilter).这个方法依然可以接受到。换句话说,在ReceiverActivity里是通过代码来注册Recevier而不是在Manifest里面注册的。sendStickyBroadcast发出的最后一个Intent会被保留,当下次Recevier处于活跃的时候,又会接受到它。需要加BROADCAST_STICKY权限,否则会抛SecurityException。

10.android为什么要引入广播机制
1).从MVC的角度考虑(应用程序内)。其实这个问题也可以这样问,android为什么要有那四大组件,现在的移动开发模型基本也是照搬web的那一套MVC架构,只不过是改了点家长而已。android的四大组件本质上是为了实现移动或者说嵌入式设备上的MVC架构,他们之间有时候是一种相互依存的关系,有时候又是一种补充关系,引入广播机制可以方便几大组件的信息和数据的交互
2).程序间互通消息(例如在自己的应用程序内监听系统来电)
3).效率上(才考UDP的广播协议在局域网内的方便性)
4).设计模式上(反转控制的一种应用,类似监听者模式)

Service

1.什么时候使用Service
它主要用于后台处理一些耗时的逻辑,或者去执行某些需要长期运行的任务。必要的时候我们甚至可以在程序退出的情况下,让Service在后台继续保持运行状态。
当BroadcastReceive捕获到一个事件之后,可以开启一个service来完成相应的耗时操作。

2.service的start、bind、stop、onbind。
package com.example.boradcasttest;

import android.app.Activity;
import android.app.IntentService;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;

public class MainActivity extends Activity {

	MyConn myConn;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);

		myConn = new MyConn();

		Button button1 = (Button) findViewById(R.id.button1);
		button1.setOnClickListener(new OnClickListener() {

			@Override
			public void onClick(View v) {
				System.out.println("click ----> button1");
				Intent intent = new Intent(MainActivity.this, MyService1.class);
				startService(intent);
			}
		});

		Button button2 = (Button) findViewById(R.id.button2);
		button2.setOnClickListener(new OnClickListener() {

			@Override
			public void onClick(View v) {
				System.out.println("click ----> button2");
				Intent intent = new Intent(MainActivity.this, MyService1.class);
				stopService(intent);
			}
		});

		Button button3 = (Button) findViewById(R.id.button3);
		button3.setOnClickListener(new OnClickListener() {

			@Override
			public void onClick(View v) {
				System.out.println("click ----> button3");
				Intent intent = new Intent(MainActivity.this, MyService1.class);
				bindService(intent, myConn, BIND_AUTO_CREATE);
			}
		});

		Button button4 = (Button) findViewById(R.id.button4);
		button4.setOnClickListener(new OnClickListener() {

			@Override
			public void onClick(View v) {
				System.out.println("click ----> button4");
				unbindService(myConn);
			}
		});

		Button button5 = (Button) findViewById(R.id.button5);
		button5.setOnClickListener(new OnClickListener() {

			@Override
			public void onClick(View v) {
				System.out.println("click ----> button5");
				Intent intent = new Intent();
				intent.setAction("stop.service1");
				sendBroadcast(intent);
			}
		});

	}

	private class MyConn implements ServiceConnection {

		public void onServiceConnected(ComponentName name, IBinder service) {
			// 可以通过IBinder的对象 去使用service里面的方法
		}

		public void onServiceDisconnected(ComponentName name) {
		}
	}

}
package com.example.boradcasttest;

import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.ServiceConnection;
import android.os.IBinder;

public class MyService1 extends Service {

	@Override
	public IBinder onBind(Intent intent) {
		System.out.println("MyService1 -> onBind");
		return null;
	}

	@Override
	public void onRebind(Intent intent) {
		System.out.println("MyService1 -> onRebind");
		super.onRebind(intent);
	}

	@Override
	public boolean onUnbind(Intent intent) {
		System.out.println("MyService1 -> onUnbind");
		return super.onUnbind(intent);
	}

	@Override
	public void onCreate() {
		System.out.println("MyService1 -> onCreate");
		super.onCreate();
	}

	@Override
	@Deprecated
	public void onStart(Intent intent, int startId) {
		System.out.println("MyService1 -> onStart");
		IntentFilter filter = new IntentFilter();
		filter.addAction("stop.service1");
		registerReceiver(receiver, filter);
		super.onStart(intent, startId);
	}

	@Override
	public boolean bindService(Intent service, ServiceConnection conn, int flags) {
		System.out.println("MyService1 -> bindService");
		return super.bindService(service, conn, flags);
	}

	@Override
	public void unbindService(ServiceConnection conn) {
		System.out.println("MyService1 -> unbindService");
		super.unbindService(conn);
	}

	@Override
	public int onStartCommand(Intent intent, int flags, int startId) {
		System.out.println("MyService1 -> onStartCommand");
		return super.onStartCommand(intent, flags, startId);
	}

	@Override
	public boolean stopService(Intent name) {
		System.out.println("MyService1 -> stopService");
		stopSelf(); // 停止服务
		return super.stopService(name);
	}

	@Override
	public void onDestroy() {
		System.out.println("MyService1 -> onDestroy");
		super.onDestroy();
	}

	BroadcastReceiver receiver = new BroadcastReceiver() {

		@Override
		public void onReceive(Context context, Intent intent) {
			System.out.println("MyService1 -> receiver");
			if (intent.getAction().equals("stop.service1")) {
				context.stopService(intent);
			}
		}
	};

}
        

3.Service的特点:
没有用户界面;比Activity的优先级高,不会轻易被android系统停止;即使Service被停止,在系统资源恢复后,service也能自动恢复运行状态;
可用于IPC,解决两个不同的android应用程序之间的调用和通信问题。

4.默认情况,如果没有显式的指定service所运行的进程,service和activity是运行在当前app所在进程的main thread(UI 主线程)里面。
service里面不能执行耗时的操作(网络请求,拷贝数据库、大文件),在子线程中new Thread(){}.start();
(anddroid的几大组件都是在main thread中执行的,所以不能执行耗时操作,新版的sdk会直接抛出异常)
特殊情况下,可以在清单文件中配置service所在的进程,让service在另外的进程中执行。

5.拥有Service的进程具有较高的优先级
官方文档告诉我们,Android系统会尽量保持拥有Service的进程运行,只要在该service已经被启动(start)或者客户端连接(bindservice)到它,当内存不足时,需要保持,拥有service的进程具有较高的优先级。
1).如果service正在调用oncreate,onstartcommand或者onSestory方法,那么用于当前的service进程相当于前台进程以避免被killed。
2).如果service已经被启动,拥有它的进程比那些用户可见的进程优先级低一些,但是比那些不可见得进程更重要,这意味着service一般不会被killed。
3).如果客户端已经连接到service,那么拥有service的进程则拥有较高的优先级,那么认为service是可见的
4).如果service可以使用startForeground(int,Notification)方法来将service设置为前台状态,那么系统会认为是对用户可见的,并不会在内存不足时killed。如果其他的应用组件作为Service,Activity等运行在相同的进程中,那么将会增加该进程的重要性。

6.如何让service不被杀死?
Android开发过程中,每次调用startService,都会调用该service对象的onStartCommand(Intent,int,int)方法,然后在onStartCommand方法中做一些处理。
从Android的开发文档中,我们知道onStartCommand有4中int返回值,简单讲讲int返回值的作用:
a.START_STICKY:如果service进程被kill掉,保留service的状态为开始状态, 但不保留递送的intent对象,随后系统会尝试重新创建service,由于服务状态为开始状态,所 以创建服务后一定要调用onStartCommand(Intent,int,int)方法,如果在此期间没有任何启动命令被传递到service,那么参数intent将为null。
b.START_NOT_STICKY:非粘性的,使用这个返回值,如果在执行完onStartCommand之后,服务被异常kill掉,系统不会自动重启服务。
c.START_REDELIVER_INTENT:重传inent,使用这个返回值时,如果执行玩onStartCommand后,服务被异常kill掉,系统会自动重启该服务,并将intent的值传入。
d.START_STICKY_COMPATIBILITY:START_STICKY的兼容版本,但不保证服务kill掉后一定能重启。
其实一般服务不被杀死,分三种情况讨论:
a.系统根据资源分配情况杀死服务
b.用户通过settings->apps->running->stop方式杀死服务
c.用户通过settings->apps->downloaded-Force stop方式杀死服务

1).让service杀不死,在service的onStartCommand中返回START_STICKY,同时在onDestory中调用startService启动自身。
2).让service从后台变为前置,在Android2.0以前有效,接住startForeground(true)方法。
3).提升service的优先级。在AndroidMainfest.xml中,设置service的android:priority的值为最大1000.尽量拥有高优先级,避免service被回收。(实质只是降低了概率)
4).当应用升级之后,即使用户不点开app,也要重启服务。因为升级app会发送ACTION_PACKAGE_RESTARTED,AlarmManager作为系统服务,会接受这个事件,然后startService。
5).创建守护进程。

7.启动前台服务
    前台服务是被认为是用户已知的运行的服务,当系统需要释放内存时不会被优先杀掉的进程。前天进程必须发一个notification在状态栏中显示,知道进程被杀死。因为前台服务会一直消耗一部分资源,但不像一般服务那样会在需要的时候被杀掉,所以为了节约资源,保持电池的寿命,一定要在建前台服务的时候发notification,提示用户。当然,系统提供的方法就是必须有notification参数的,所以不要想着怎么办notification隐藏。
startForeground方法就是将服务设置为前台服务,参数123456就是这个通知唯一的id,只要不为0就可以了。
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
	// TODO Auto-generated method stub
	Intent notificationIntent = new Intent(this, MainActivity.class);
	PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0);
	Notification noti = new Notification.Builder(this)
				.setContentTitle("Title")
				.setContentText("Message")
				.setSmallIcon(R.drawable.ic_launcher)
				.setContentIntent(pendingIntent)
				.build();
	startForeground(12346, noti);
	return Service.START_STICKY;
}

8.service和intentservice的比较
   这里主要说的是IntentService使用队列的方式将请求的Intent加入队列,然后开启一个worker thread来处理队列中的Intent,对于异步的startservice请求,IntentService会处理完成一个之后才会处理第二个,每一个请求都会在一个单独的worker thread中处理,不会阻塞应用程序的主线程,这里就给我们提供一个思路,如果有耗时的操作与其在Service里面开启新的线程,不如使用IntnetService来处理耗时操作。
public class MyService extends Service {  
  
    @Override  
    public void onCreate() {  
        super.onCreate();  
    }  
      
    @Override  
    public void onStart(Intent intent, int startId) {  
        super.onStart(intent, startId);  
        //经测试,Service里面是不能进行耗时的操作的,必须要手动开启一个工作线程来处理耗时操作   
        System.out.println("onStart");  
        try {  
            Thread.sleep(20000);  
        } catch (InterruptedException e) {  
            e.printStackTrace();  
        }  
        System.out.println("睡眠结束");  
    }  
      
    @Override  
    public IBinder onBind(Intent intent) {  
        return null;  
    }  
}  
public class MyIntentService extends IntentService {  
  
    public MyIntentService() {  
        super("yyyyyyyyyyy");  
    }  
  
    @Override  
    protected void onHandleIntent(Intent intent) {  
        // 经测试,IntentService里面是可以进行耗时的操作的   
        //IntentService使用队列的方式将请求的Intent加入队列,然后开启一个worker thread(线程)来处理队列中的Intent   
        //对于异步的startService请求,IntentService会处理完成一个之后再处理第二个   
        System.out.println("onStart");  
        try {  
            Thread.sleep(20000);  
        } catch (InterruptedException e) {  
            e.printStackTrace();  
        }  
        System.out.println("睡眠结束");  
    }  
}  
public class ServiceDemoActivity extends Activity {  
    /** Called when the activity is first created. */  
    @Override  
    public void onCreate(Bundle savedInstanceState) {  
        super.onCreate(savedInstanceState);  
        setContentView(R.layout.main);  
        startService(new Intent(this,MyService.class));//主界面阻塞,最终会出现Application not responding   
        //连续两次启动IntentService,会发现应用程序不会阻塞,而且最重的是第二次的请求会再第一个请求结束之后运行(这个证实了IntentService采用单独的线程每次只从队列中拿出一个请求进行处理)   
        startService(new Intent(this,MyIntentService.class));  
        startService(new Intent(this,MyIntentService.class));  
    }  
}  
IntentServicede 的好处:
*Activity的进程,当处理Intent的时候,会产生一个对应的Service。
*Android的进程处理器现在会尽可能的不kill掉你
*非常容易使用

9.intentservice的处理流程
创建默认的一个worker线程处理传递给onStartCommand()的所有intent,不占据应用的主线程;创建一个工作队列一次传递一个intent到你实现的onHandleIntent()方法,避免了多线程;在所有启动请求被处理后自动关闭服务,不需要调用stopSelf();默认提供onBind()的实现,并返回null;默认提供onStartCommand()的实现,实现发送intent到工作队列再到你的onHandleIntent()方法实现。这些都加入到intentservice中了,你需要做的就是实现构造方法和onHandleIntent()。
public class HelloIntentService extends IntentService {

  /**
   * A constructor is required, and must call the super IntentService(String)
   * constructor with a name for the worker thread.
   */
  public HelloIntentService() {
      super("HelloIntentService");
  }

  /**
   * The IntentService calls this method from the default worker thread with
   * the intent that started the service. When this method returns, IntentService
   * stops the service, as appropriate.
   */
  @Override
  protected void onHandleIntent(Intent intent) {
      // Normally we would do some work here, like download a file.
      // For our sample, we just sleep for 5 seconds.
      long endTime = System.currentTimeMillis() + 5*1000;
      while (System.currentTimeMillis() < endTime) {
          synchronized (this) {
              try {
                  wait(endTime - System.currentTimeMillis());
              } catch (Exception e) {
              }
          }
      }
  }
}
如果需要重写其他回调方法,如onCreate,onStartCommand()等,一定要调用super()方法,保证intentservice正确处理worker线程,只有onHandleIntent()和onBind()不需要这样,如:
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
    Toast.makeText(this, "service starting", Toast.LENGTH_SHORT).show();
    return super.onStartCommand(intent,flags,startId);
}


Service对象不能自己启动,需要通过某个Activity、Service或者其他Context对象来启动,启动的方法有两种,Context.startService()和Context.bindService()。两种方式的生命周期是不同的。

context.startService:

如果service还没有运行,则android先调用onCreate()方法,然后调用onStart();如果service已经运行,则至调用onStart(),所以一个service的onStart()方法可能会重复调用多次。stopService的时候会直接调用onDestory(),如果是调用者自己直接退出而没有调用stopService的话,service会一直在后台运行,该service的调用者再次启动起来后可以通过stopService关闭service

1.在同一个应用任何地方调用startService()方法就能启动Service了,然后系统会回调service类的onCreate()以及onStart()方法,这样启动的service会一直运行在后台,知道Context.stopService()或者selfStop()方法被调用。

2.另外一种bindService()方法的意思是,把这个Service和调用service的客户类绑起来,如果调用这个客户类被销毁,service也会被销毁,用这个方法的一个好处是,bindService()方法执行后service会回调上边提到的onBind()方法,你可以从这里返回一个实现了IBind接口的类,在额客户端操作这个类就能和这个服务通信了, 比如得到service运行的状态或其他操作,如果service还没有运行,使用这个方法启动service就会onCreate()方法而不会调用onStart().

3.startService()的目的是回调onStart()方法,onCreate()方法是在Service不存在的时候调用的,如果Service存在(例如之前调用了bindService,那么Service的onCreate方法已经被调用了)那么startService()将跳过onCreate()方法。

4.bindService()目的是回调onBind()方法,它的作用是在Service和调用者之间建立一个桥梁,并不负责更多的工作(例如一个service需要连接服务器的操作),一般使用bindService来帮顶到一个现有的Service(即通过StartService启动的服务)

由于Service的onStart()方法只有在startService()启动service的情况下才会调用,故使用onStart()的时候要注意这点。

5.与Service通信并且让它持续运行:如果我们想要保持和Service的通信,又不想让Service随着Activity退出而退出。你可以先startService()然后在bindService()。当你不需要帮顶的时候就执行unbindService()方法,执行这个方法只会触发Service的onUnbind()方法而不会把这个Service销毁,这样就可以既保持和service的通信,也不会随着activity销毁而销毁。

6.为什么是foregorund:默认启动的Service是被标记为background,当前运行的Activity一般被标记为foreground,也就是说你给service设置了foreground那么他就和正在运行的Activity类似优先级得到了一定的提高。当让这并不能保证你service永远不被杀掉。只是提高了他的优先级

7.如果先是bind了,那么start的时候就直接运行service的onStart方法,如果是先start,那么bind的时候就直接运行onBind方法,如果你先bind上了,就stop不掉了,只能先执行UnbindService,再stopService,所以是先start还是先bind行为是有区别的。

8.如果打算采用Context.startService()方法启动服务,在服务未被创建时,系统会先调用服务的onCreate()方法,接着调用onStart()。如果调用startService()方法前服务已经被创建,多次调用startService()方法,并不会导致多次创建服务,但会导致多次调用onStart()方法,采用startService()方法启动的服务只能调用Context.stopService()方法结束服务,服务结束时会被调用onDestory()。

9.如果打算采用Context.bindService()方法启动服务,在服务未被创建时,系统会先调用服务的onCreate()方法,接着调用onBind()方法,这个时候调用者和服务绑定在一起,调用者退出,系统就会先调用服务的onUnbind()方法,接着调用onDestory()方法,如果调用bindService()方法前服务已经被绑定,多次调用bindService()并不会导致多次创建服务及绑定(也就是说onCreate和onBind方法并不会多次调用)。如果调用者希望与正在绑定的服务解除绑定,可以调用unbindService()方法。

10.Service和Thread的区别:

Thread是程序执行的最小单位,他是分配CPUde基本但那位,可以用Thread来执行一些异步的操作。

Service是android的一种机制,当它运行的时候,如果是Local Service,那么对应的Service是运行在主进程的main线程上的。如onCreate,onStart这些函数在被系统调用的时候都是在主进程的main线程上运行的。如果Remote Service,那么对应的Service则是运行在独立进程的main线程上,因此不要把Service理解成线程,它和线程半毛钱关系都没有。

那么我们为什么要用Service?   Thread的运行是独立于Activity的,也就是说当一个Activity被finish之后,如果你没有主动停止Thread或者Thread中的run方法没有执行完毕,Thread也会一直执行。因此这里会出现一个问题,当Activity被finish掉之后,你不在持有该Thread的引用,另一方面,你没有办法在不同的Activity中对同一个Thread进行控制。

举个例子:如果你的Thread需要不停的隔一段时间就要连接服务器做某种同步的话,该Thread需要在Activity没有start的时候就运行。这个时候当你start一个Activity就没有办法在该Activity里面控制之前创建的Thread。因此你需要创建并启动一个Service。在Service里面创建、运行并控制该Thread,这样便解决了该问题(因为任何Activity都可以控制同一个Service,而系统也只会创建一个对应的Service实例)

因此你可以把Service想象成一种消息服务,而你可以在任何有Context的地方调用StartService、Context.stopService、Context.bindService、Context.unbindService,来控制它,你也可以在Service中注册BroadcastReceiver,在其他地方通过发送broadcast来控制它,当然这些都是Thread做不到的。


相关文章